Skip to content

Embind: enums are not serializable. Couldn't the implementation be simplified ? #24324

Open
@FelixNumworks

Description

@FelixNumworks

When I'm storing an enum value binded via embind in a js var, I can't use JSON.stringify on it.

Current implementation:

I'm not understanding very well why the enums are binded the way they are today, attaching values to their constructor.

Register enum

_embind_register_enum: (rawType, name, size, isSigned) => {
name = readLatin1String(name);
function ctor() {}
ctor.values = {};
registerType(rawType, {
name,
constructor: ctor,
'fromWireType': function(c) {
return this.constructor.values[c];
},
'toWireType': (destructors, c) => c.value,
argPackAdvance: GenericWireTypeSize,
'readValueFromPointer': enumReadValueFromPointer(name, size, isSigned),
destructorFunction: null,
});
exposePublicSymbol(name, ctor);
},

Register enum value

_embind_register_enum_value: (rawEnumType, name, enumValue) => {
var enumType = requireRegisteredType(rawEnumType, 'enum');
name = readLatin1String(name);
var Enum = enumType.constructor;
var Value = Object.create(enumType.constructor.prototype, {
value: {value: enumValue},
constructor: {value: createNamedFunction(`${enumType.name}_${name}`, function() {})},
});
Enum.values[enumValue] = Value;
Enum[name] = Value;
},

Suggested implementation

Isn't it possible to replace with something along those lines:

Register enum

  _embind_register_enum: (rawType, name, size, isSigned) => {
    name = readLatin1String(name);
    var values = {};
    registerType(rawType, {
      name,
      values,
      fromWireType: (c) => {
        return Object.values(values).find((v) => v.value === c);
      },
      toWireType: (destructors, c) => c.value,
      argPackAdvance: GenericWireTypeSize,
      'readValueFromPointer': enumReadValueFromPointer(name, size, isSigned),
      destructorFunction: null,
    });
    exposePublicSymbol(name, values);
  },

Register enum value

  _embind_register_enum_value: (rawEnumType, name, enumValue) => {
    var enumType = requireRegisteredType(rawEnumType, 'enum');
    name = readLatin1String(name);
    enumType.values[name] = { value: enumValue };
  },

I'm just creating a values object tied to the enum type. And enum values are just a simple object { value: ... }

It seems to me that it doesn't change how enums are used, but it makes them way more flexible, as they are just simple js object.

Typescript

You could even add the enum name to the the enum values to strongly type them in typescript

  _embind_register_enum_value: (rawEnumType, name, enumValue) => {
    var enumType = requireRegisteredType(rawEnumType, 'enum');
    name = readLatin1String(name);
    enumType.values[name] = { value: enumValue, enumType: enumType.name };
  },

In the .d.ts file:

export interface MyEnumValue<T extends number> {
  value: T;
  enumType: "MyEnum";
}

export type MyEnum = MyEnumValue<0> | MyEnumValue<1> | MyEnumValue<2>;

interface EmbindModule {
  MyEnum: { MyFirstValue: MyEnumValue<0>, MySecondValue: MyEnumValue<1>, MyThirdValue: MyEnumValue<2> }
}

Maybe there is something I'm not grasping here ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions