Generalize class property access.
This commit is contained in:
Родитель
040eb9db42
Коммит
f554c2fac0
|
@ -1154,42 +1154,47 @@ function __embind_register_class_class_function(
|
|||
}
|
||||
|
||||
function __embind_register_class_property(
|
||||
rawClassType,
|
||||
classType,
|
||||
fieldName,
|
||||
rawFieldType,
|
||||
getterReturnType,
|
||||
getter,
|
||||
getterContext,
|
||||
setterArgumentType,
|
||||
setter,
|
||||
context
|
||||
setterContext
|
||||
) {
|
||||
fieldName = Pointer_stringify(fieldName);
|
||||
getter = FUNCTION_TABLE[getter];
|
||||
setter = FUNCTION_TABLE[setter];
|
||||
whenDependentTypesAreResolved([], [rawClassType], function(classType) {
|
||||
|
||||
whenDependentTypesAreResolved([], [classType], function(classType) {
|
||||
classType = classType[0];
|
||||
var humanName = classType.name + '.' + fieldName;
|
||||
|
||||
Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, {
|
||||
get: function() {
|
||||
throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]);
|
||||
throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]);
|
||||
},
|
||||
set: function() {
|
||||
throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]);
|
||||
throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]);
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
whenDependentTypesAreResolved([], [rawFieldType], function(fieldType) {
|
||||
fieldType = fieldType[0];
|
||||
whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) {
|
||||
var getterReturnType = types[0];
|
||||
var setterArgumentType = types[1];
|
||||
|
||||
Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, {
|
||||
get: function() {
|
||||
var ptr = validateThis(this, classType, humanName + ' getter');
|
||||
return fieldType.fromWireType(getter(context, ptr));
|
||||
return getterReturnType.fromWireType(getter(getterContext, ptr));
|
||||
},
|
||||
set: function(v) {
|
||||
var ptr = validateThis(this, classType, humanName + ' setter');
|
||||
var destructors = [];
|
||||
setter(context, ptr, fieldType.toWireType(destructors, v));
|
||||
setter(setterContext, ptr, setterArgumentType.toWireType(destructors, v));
|
||||
runDestructors(destructors);
|
||||
},
|
||||
enumerable: true
|
||||
|
|
|
@ -136,10 +136,12 @@ namespace emscripten {
|
|||
void _embind_register_class_property(
|
||||
TYPEID classType,
|
||||
const char* fieldName,
|
||||
TYPEID fieldType,
|
||||
TYPEID getterReturnType,
|
||||
GenericFunction getter,
|
||||
void* getterContext,
|
||||
TYPEID setterArgumentType,
|
||||
GenericFunction setter,
|
||||
void* context);
|
||||
void* setterContext);
|
||||
|
||||
void _embind_register_class_class_function(
|
||||
TYPEID classType,
|
||||
|
@ -980,11 +982,30 @@ namespace emscripten {
|
|||
fieldName,
|
||||
TypeID<FieldType>::get(),
|
||||
reinterpret_cast<GenericFunction>(&MemberAccess<ClassType, FieldType>::template getWire<ClassType>),
|
||||
getContext(field),
|
||||
TypeID<FieldType>::get(),
|
||||
reinterpret_cast<GenericFunction>(&MemberAccess<ClassType, FieldType>::template setWire<ClassType>),
|
||||
getContext(field));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Getter, typename Setter>
|
||||
class_& property(const char* fieldName, Getter getter, Setter setter) {
|
||||
using namespace internal;
|
||||
typedef GetterPolicy<Getter> GP;
|
||||
typedef SetterPolicy<Setter> SP;
|
||||
_embind_register_class_property(
|
||||
TypeID<ClassType>::get(),
|
||||
fieldName,
|
||||
TypeID<typename GP::ReturnType>::get(),
|
||||
reinterpret_cast<GenericFunction>(&GP::template get<ClassType>),
|
||||
GP::getContext(getter),
|
||||
TypeID<typename SP::ArgumentType>::get(),
|
||||
reinterpret_cast<GenericFunction>(&SP::template set<ClassType>),
|
||||
SP::getContext(setter));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ReturnType, typename... Args, typename... Policies>
|
||||
class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) {
|
||||
using namespace internal;
|
||||
|
|
|
@ -837,6 +837,16 @@ module({
|
|||
assert.equal(0, cm.count_emval_handles());
|
||||
});
|
||||
|
||||
test("class properties can be methods", function() {
|
||||
var a = {};
|
||||
var b = {foo: 'foo'};
|
||||
var c = new cm.ValHolder(a);
|
||||
assert.equal(a, c.val);
|
||||
c.val = b;
|
||||
assert.equal(b, c.val);
|
||||
c.delete();
|
||||
});
|
||||
|
||||
test("class instance $$ property is non-enumerable", function() {
|
||||
var c = new cm.ValHolder(undefined);
|
||||
assert.deepEqual([], Object.keys(c));
|
||||
|
|
|
@ -1527,6 +1527,7 @@ EMSCRIPTEN_BINDINGS(tests) {
|
|||
.function("getConstVal", &ValHolder::getConstVal)
|
||||
.function("getValConstRef", &ValHolder::getValConstRef)
|
||||
.function("setVal", &ValHolder::setVal)
|
||||
.property("val", &ValHolder::getVal, &ValHolder::setVal)
|
||||
.class_function("makeConst", &ValHolder::makeConst, allow_raw_pointer<ret_val>())
|
||||
.class_function("makeValHolder", &ValHolder::makeValHolder)
|
||||
.class_function("some_class_method", &ValHolder::some_class_method)
|
||||
|
|
Загрузка…
Ссылка в новой задаче