void
FreezeScript::AssignVisitor::visitSequence(const SequenceDataPtr& dest)
{
    Slice::TypePtr type = dest->getType();
    SequenceDataPtr src = SequenceDataPtr::dynamicCast(_src);
    if(src && isCompatible(type, src->getType()))
    {
        DataList& srcElements = src->getElements();
        DataList destElements;
        Slice::SequencePtr seqType = Slice::SequencePtr::dynamicCast(type);
        assert(seqType);
        Slice::TypePtr elemType = seqType->type();
        string typeName = typeToString(type);
        for(DataList::const_iterator p = srcElements.begin(); p != srcElements.end(); ++p)
        {
            DataPtr element = _factory->create(elemType, false);
            Destroyer<DataPtr> elementDestroyer(element);
            AssignVisitor v(*p, _factory, _errorReporter, _convert, typeName + " element");
            element->visit(v);
            destElements.push_back(element);
            elementDestroyer.release();
        }
        DataList& l = dest->getElements();
        l.swap(destElements);
    }
    else
    {
        typeMismatchError(type, _src->getType());
    }
}
void
FreezeScript::AssignVisitor::visitDictionary(const DictionaryDataPtr& dest)
{
    Slice::TypePtr type = dest->getType();
    DictionaryDataPtr d = DictionaryDataPtr::dynamicCast(_src);
    if(d && isCompatible(type, _src->getType()))
    {
        DataMap& srcMap = d->getElements();
        DataMap destMap;
        Slice::DictionaryPtr dictType = Slice::DictionaryPtr::dynamicCast(type);
        assert(dictType);
        Slice::TypePtr keyType = dictType->keyType();
        Slice::TypePtr valueType = dictType->valueType();
        string typeName = typeToString(type);
        for(DataMap::const_iterator p = srcMap.begin(); p != srcMap.end(); ++p)
        {
            DataPtr key = _factory->create(keyType, false);
            Destroyer<DataPtr> keyDestroyer(key);
            DataPtr value = _factory->create(valueType, false);
            Destroyer<DataPtr> valueDestroyer(value);

            AssignVisitor keyVisitor(p->first, _factory, _errorReporter, _convert, typeName + " key");
            key->visit(keyVisitor);

            AssignVisitor valueVisitor(p->second, _factory, _errorReporter, _convert, typeName + " value");
            value->visit(valueVisitor);

            DataMap::const_iterator q = destMap.find(key);
            if(q != destMap.end())
            {
                error("duplicate dictionary key in " + typeToString(dictType));
            }
            else
            {
                destMap.insert(DataMap::value_type(key, value));
                keyDestroyer.release();
                valueDestroyer.release();
            }
        }
        DataMap& m = dest->getElements();
        m.swap(destMap);
    }
    else
    {
        typeMismatchError(type, _src->getType());
    }
}
void
FreezeScript::TransformVisitor::visitSequence(const SequenceDataPtr& dest)
{
    Slice::TypePtr type = dest->getType();
    if(_info->doDefaultTransform(type))
    {
        SequenceDataPtr s = SequenceDataPtr::dynamicCast(_src);
        if(s && isCompatible(type, _src->getType()))
        {
            DataList& srcElements = s->getElements();
            DataList destElements;
            Slice::SequencePtr seqType = Slice::SequencePtr::dynamicCast(type);
            assert(seqType);
            Slice::TypePtr elemType = seqType->type();
            string typeName = typeToString(type);
            for(DataList::const_iterator p = srcElements.begin(); p != srcElements.end(); ++p)
            {
                DataPtr element = _info->getDataFactory()->create(elemType, false);
                Destroyer<DataPtr> elementDestroyer(element);
                try
                {
                    TransformVisitor v(*p, _info, typeName + " element");
                    element->visit(v);
                    destElements.push_back(element);
                    elementDestroyer.release();
                }
                catch(const ClassNotFoundException& ex)
                {
                    //
                    // If transformation of the sequence element fails because a class
                    // could not be found, then we invoke purgeObjects() to determine
                    // whether we should ignore the situation (and remove the element
                    // from the sequence) or raise the exception again.
                    //
                    if(!_info->purgeObjects())
                    {
                        throw;
                    }
                    warning("purging element of sequence " + typeToString(type) +
                            " due to missing class type " + ex.id);
                }
            }
            DataList& l = dest->getElements();
            l.swap(destElements);
        }
        else
        {
            typeMismatchError(type, _src->getType());
        }
    }
    _info->executeCustomTransform(dest, _src);
}
void
FreezeScript::TransformVisitor::visitDictionary(const DictionaryDataPtr& dest)
{
    Slice::TypePtr type = dest->getType();
    if(_info->doDefaultTransform(type))
    {
        DictionaryDataPtr d = DictionaryDataPtr::dynamicCast(_src);
        if(d && isCompatible(type, _src->getType()))
        {
            DataMap& srcMap = d->getElements();
            DataMap destMap;
            Slice::DictionaryPtr dictType = Slice::DictionaryPtr::dynamicCast(type);
            assert(dictType);
            Slice::TypePtr keyType = dictType->keyType();
            Slice::TypePtr valueType = dictType->valueType();
            string typeName = typeToString(type);
            for(DataMap::const_iterator p = srcMap.begin(); p != srcMap.end(); ++p)
            {
                DataPtr key = _info->getDataFactory()->create(keyType, false);
                Destroyer<DataPtr> keyDestroyer(key);
                DataPtr value = _info->getDataFactory()->create(valueType, false);
                Destroyer<DataPtr> valueDestroyer(value);

                TransformVisitor keyVisitor(p->first, _info, typeName + " key");
                key->visit(keyVisitor);

                try
                {
                    TransformVisitor valueVisitor(p->second, _info, typeName + " value");
                    value->visit(valueVisitor);
                }
                catch(const ClassNotFoundException& ex)
                {
                    //
                    // If transformation of the dictionary value fails because a class
                    // could not be found, then we invoke purgeObjects() to determine
                    // whether we should ignore the situation (and remove the element
                    // from the dictionary) or raise the exception again.
                    //
                    if(!_info->purgeObjects())
                    {
                        throw;
                    }
                    warning("purging element of dictionary " + typeToString(dictType) + " due to missing class type " +
                            ex.id);
                    continue;
                }

                DataMap::const_iterator q = destMap.find(key);
                if(q != destMap.end())
                {
                    warning("duplicate dictionary key in " + typeToString(dictType));
                }
                else
                {
                    destMap.insert(DataMap::value_type(key, value));
                    keyDestroyer.release();
                    valueDestroyer.release();
                }
            }
            DataMap& m = dest->getElements();
            m.swap(destMap);
        }
        else
        {
            typeMismatchError(type, _src->getType());
        }
    }
    _info->executeCustomTransform(dest, _src);
}