DaoValue* DaoObject_CastToBase( DaoObject *self, DaoType *host ) { DaoValue *sup = self->parent; if( host == NULL ) return NULL; host = DaoType_GetBaseType( host ); if( self->defClass->objType == host ) return (DaoValue*) self; if( self->parent == NULL ) return NULL; if( sup->type == DAO_OBJECT ){ if( (sup = DaoObject_CastToBase( & sup->xObject, host ) ) ) return sup; }else if( sup->type == DAO_CSTRUCT && host->tid == DAO_CSTRUCT ){ if( DaoType_ChildOf( sup->xCdata.ctype, host ) ) return sup; }else if( sup->type == DAO_CDATA && host->tid == DAO_CDATA ){ if( DaoType_ChildOf( sup->xCdata.ctype, host ) ) return sup; } return NULL; }
DaoValue* DaoValue_Convert( DaoValue *self, DaoType *type, int copy, DaoProcess *proc ) { DaoTypeCore *core = DaoValue_GetTypeCore( self ); DaoValue *value = self; DaoType *at; if( type->tid & DAO_ANY ){ if( copy == 0 ) return value; at = DaoValue_GetType( value, proc->vmSpace ); at = DaoType_GetBaseType( at ); if( at == NULL ) return NULL; if( DaoType_IsImmutable( at ) ) return value; if( value->type >= DAO_ARRAY && value->type <= DAO_TUPLE ){ at = DaoNamespace_MakeInvarSliceType( proc->activeNamespace, at ); return DaoValue_CopyContainer( value, at ); }else if( core != NULL && core->Copy != NULL ){ return core->Copy( value, NULL ); } return NULL; }else if( type->tid == DAO_CINVALUE ){ DaoCinType *cintype = (DaoCinType*) type->aux; if( value->type == DAO_CINVALUE && value->xCinValue.cintype == cintype ) return value; if( value->type == DAO_CINVALUE && DaoType_MatchValue( type, value, NULL ) ) return value; at = DaoNamespace_GetType( proc->activeNamespace, value ); if( cintype->target == at || DaoType_MatchTo( cintype->target, at, NULL ) >= DAO_MT_CIV ){ proc->cinvalue.cintype = cintype; proc->cinvalue.value = value; return (DaoValue*) & proc->cinvalue; } return NULL; }else if( type->tid == DAO_INTERFACE ){ DaoInterface *inter = (DaoInterface*) type->aux; DaoRoutine *incompatible; if( type->aux == NULL ){ /* type "interface": */ if( value->type != DAO_INTERFACE ) return NULL; return value; } if( value->type == DAO_CINVALUE && DaoType_MatchValue( type, value, NULL ) ) return value; at = DaoNamespace_GetType( proc->activeNamespace, value ); if( inter->concretes ){ DaoCinType *cintype = DaoInterface_GetConcrete( inter, at ); if( cintype ){ proc->cinvalue.cintype = cintype; proc->cinvalue.value = value; return (DaoValue*) & proc->cinvalue; } } switch( value->type ){ case DAO_OBJECT : value = (DaoValue*) value->xObject.rootObject; at = value->xObject.defClass->objType; break; case DAO_CSTRUCT : case DAO_CDATA : if( value->xCstruct.object ){ value = (DaoValue*) value->xCstruct.object->rootObject; at = value->xObject.defClass->objType; } break; } /* Automatic binding when casted to an interface: */ incompatible = DaoInterface_BindTo( inter, at, NULL ); if( incompatible != NULL ){ DString *buffer = DString_New(); DString_AppendChars( buffer, "Interface method " ); DString_Append( buffer, inter->abtype->name ); DString_AppendChars( buffer, "::" ); DString_Append( buffer, incompatible->routName ); DString_AppendChars( buffer, "() is not available in the source type;" ); DaoProcess_DeferException( proc, "Error::Type", buffer->chars ); DString_Delete( buffer ); return NULL; } return value; }else if( type->tid == DAO_VARIANT ){ DaoType *best = NULL; int i, n, max = DAO_MT_NOT; for(i=0,n=type->args->size; i<n; i++){ DaoType *itype = type->args->items.pType[i]; int mt = DaoType_MatchValue( itype, self, NULL ); if( mt > max ){ best = itype; max = mt; } } if( best == NULL ) return NULL; return DaoValue_Convert( self, best, copy, proc ); } if( core == NULL || core->DoConversion == NULL ) return NULL; value = core->DoConversion( self, type, copy, proc ); if( value == NULL || value->type <= DAO_ENUM || copy == 0 ) return value; if( value == self /*|| DaoValue_ChildOf( value, self ) || DaoValue_ChildOf( self, value )*/ ){ // No way to determine inheritance relationship between wrapped C++ objects; if( value->type >= DAO_ARRAY && value->type <= DAO_TUPLE ){ DaoType *type = DaoValue_GetType( value, proc->vmSpace ); if( type == NULL ) return NULL; type = DaoNamespace_MakeInvarSliceType( proc->activeNamespace, type ); return DaoValue_CopyContainer( value, type ); } if( core == NULL || core->Copy == NULL ) return NULL; value = core->Copy( value, NULL ); /* Copy invariable value; */ if( value == NULL ) return NULL; DaoProcess_CacheValue( proc, value ); } return value; }
/* // Assumming the value "self" is compatible to the type "tp", if it is not null. */ DaoValue* DaoValue_SimpleCopyWithTypeX( DaoValue *self, DaoType *tp, DaoType *cst ) { if( self == NULL ) return dao_none_value; if( self->type < DAO_ENUM && (tp == NULL || tp->tid == self->type) ){ /* // The following optimization is safe theoretically. // But it is not practically safe for DaoProcess_PutChars() etc., // which often uses shallow wraps of "const char*" as the source value, // and expects it to be copied at the destination as a primitive value. */ /* if( cst && cst->invar ) return self; */ switch( self->type ){ case DAO_NONE : return self; case DAO_BOOLEAN : return (DaoValue*) DaoBoolean_New( self->xBoolean.value ); case DAO_INTEGER : return (DaoValue*) DaoInteger_New( self->xInteger.value ); case DAO_FLOAT : return (DaoValue*) DaoFloat_New( self->xFloat.value ); case DAO_COMPLEX : return (DaoValue*) DaoComplex_New( self->xComplex.value ); case DAO_STRING : return (DaoValue*) DaoString_Copy( & self->xString ); } return self; /* unreachable; */ }else if( tp && tp->tid >= DAO_BOOLEAN && tp->tid <= DAO_FLOAT ){ DaoValue *va = NULL; switch( tp->tid ){ case DAO_BOOLEAN : va = (DaoValue*) DaoBoolean_New( DaoValue_GetInteger(self) ); break; case DAO_INTEGER : va = (DaoValue*) DaoInteger_New( DaoValue_GetInteger(self) ); break; case DAO_FLOAT : va = (DaoValue*) DaoFloat_New( DaoValue_GetFloat(self) ); break; } return va; }else if( self->type == DAO_ENUM ){ switch( tp ? tp->tid : 0 ){ case DAO_ENUM : if( tp->subtid == DAO_ENUM_ANY ) tp = NULL; return (DaoValue*) DaoEnum_Copy( & self->xEnum, tp ); case DAO_BOOLEAN : return (DaoValue*) DaoBoolean_New( self->xEnum.value ); case DAO_INTEGER : return (DaoValue*) DaoInteger_New( self->xEnum.value ); case DAO_FLOAT : return (DaoValue*) DaoFloat_New( self->xEnum.value ); } return (DaoValue*) DaoEnum_Copy( & self->xEnum, NULL ); }else if( tp && tp->tid == DAO_ENUM ){ switch( self->type ){ case DAO_BOOLEAN : case DAO_INTEGER : return (DaoValue*) DaoEnum_New( tp, self->xInteger.value ); case DAO_FLOAT : return (DaoValue*) DaoEnum_New( tp, self->xFloat.value ); } }else if( self->type == DAO_CINVALUE ){ return (DaoValue*) DaoCinValue_Copy( (DaoCinValue*) self ); } if( tp != NULL ){ assert( tp->tid == 0 || tp->tid > DAO_ENUM ); assert( self->type == 0 || self->type > DAO_ENUM ); } #ifdef DAO_WITH_NUMARRAY if( self->type == DAO_ARRAY && self->xArray.original ){ DaoArray_Sliced( (DaoArray*)self ); return self; }else #endif if( self->type == DAO_CSTRUCT || self->type == DAO_CDATA ){ if( self->xCstruct.ctype->core->Slice ) self->xCstruct.ctype->core->Slice( self ); return self; } if( tp == NULL ){ switch( self->type ){ case DAO_LIST : if( self->xList.ctype->empty ) tp = self->xList.ctype; break; case DAO_MAP : if( self->xMap.ctype->empty ) tp = self->xMap.ctype; break; default : break; } } if( self->xBase.trait & DAO_VALUE_NOCOPY ) return self; if( (self->xBase.trait & DAO_VALUE_CONST) == 0 ) return self; if( cst != NULL && cst->invar != 0 ) return self; if( tp ) tp = DaoType_GetBaseType( tp ); return DaoValue_CopyContainer( self, tp ); }