Home > Mobile >  How to return and correctly identify a duplicate enum from C to dart using dart ffi?
How to return and correctly identify a duplicate enum from C to dart using dart ffi?

Time:11-08

I stepped over this enum in C:

typedef enum
{
  UndefinedGravity,
  ForgetGravity = 0,
  NorthWestGravity = 1,
  NorthGravity = 2,
  NorthEastGravity = 3,
  WestGravity = 4,
  CenterGravity = 5,
  EastGravity = 6,
  SouthWestGravity = 7,
  SouthGravity = 8,
  SouthEastGravity = 9
} GravityType;

I built its corresponding enum type in dart:

enum GravityType {
  UndefinedGravity(0),
  ForgetGravity(0),
  NorthWestGravity(1),
  NorthGravity(2),
  NorthEastGravity(3),
  WestGravity(4),
  CenterGravity(5),
  EastGravity(6),
  SouthWestGravity(7),
  SouthGravity(8),
  SouthEastGravity(9);

  final int value;

  const GravityType(this.value);

  static GravityType fromValue(int value) => GravityType.values.firstWhere((e) => e.value == value);
}

You can see that UndefinedGravity and ForgetGravity have the same int value in C, and theyhave the same int value in dart.

Now consider this C function:

int myFunc(...){
GravityType gt = ForgetGravity;
return gt;
}

If I call this function from dart, it will return a dart int (0 in this case). Then I can call GravityType.fromValue(returnedValue) But how can I know if it represents UndefinedGravity or ForgetGravity so I can map it properly in dart?The current implementation of fromValue is naiive and will return the first match of the int value, so how can I return the same enum as the one that was meant to be sent from C?

CodePudding user response:

Let's take the following enum:

// Broken example, firstType and secondType have the same value but aren't equal.
enum MyType {
  firstType(0),
  secondType(0),
  thirdType(123);

  final int value;
  const MyType(this.value);
  static MyType fromValue(int value) => MyType.values.firstWhere((e) => e.value == value);
}

The ideal solution for sparse, overlapping enum values is to declare them as static const:

enum MyType {
  firstType(0),
  thirdType(123);

  // Make the overlapping value an alias of the first
  static const secondType = firstType;

  final int value;
  const MyType(this.value);
  static MyType fromValue(int value) => MyType.values.firstWhere((e) => e.value == value);
}

Now MyType.firstType == MyType.secondType returns true, secondType feels the same as a real enum value but is really just an alias.

One more problem you might notice is that print(MyType.secondType) confusingly prints MyType.firstType, this can be solved by making a new value with a more descriptive name:

enum MyType {
  firstOrSecondType(0),
  thirdType(123);

  // Both values are now an alias of firstOrSecondType
  static const firstType = firstOrSecondType;
  static const secondType = firstOrSecondType;

  final int value;
  const MyType(this.value);
  static MyType fromValue(int value) => MyType.values.firstWhere((e) => e.value == value);
}

Enums in C do not store their name, their literal values are ints, so no information is lost by giving both firstType and secondType the same name.

CodePudding user response:

Enumeration constants (these things: UndefinedGravity) in C basically work like this:

  • They always have type int.
  • If no value is specified for the first item, it defaults to zero.
  • If no value is specified for any other item, it defaults to previous enumeration constant 1.
  • If a value is specified with = assignment, it uses that value.
  • Duplicates are allowed.
  • Related