Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add getters to base class for common properties of dart enum classes #16

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

kturney
Copy link
Contributor

@kturney kturney commented Aug 23, 2022

Summary

For complex enums, add getters to the dart base class when

  • all variants are structs
  • a field with same name and type appears in every variant
Example complex_enum output
part of example_types;

abstract class ComplexEnum {
  const ComplexEnum();

  String get id;

  void serialize(BinarySerializer serializer);

  static ComplexEnum deserialize(BinaryDeserializer deserializer) {
    int index = deserializer.deserializeVariantIndex();
    switch (index) {
      case 0: return ComplexEnumAItem.load(deserializer);
      case 1: return ComplexEnumBItem.load(deserializer);
      case 2: return ComplexEnumCItem.load(deserializer);
      default: throw Exception("Unknown variant index for ComplexEnum: " + index.toString());
    }
  }

  Uint8List bincodeSerialize() {
      final serializer = BincodeSerializer();
      serialize(serializer);
      return serializer.bytes;
  }

  static ComplexEnum bincodeDeserialize(Uint8List input) {
    final deserializer = BincodeDeserializer(input);
    final value = ComplexEnum.deserialize(deserializer);
    if (deserializer.offset < input.length) {
      throw Exception('Some input bytes were not read');
    }
    return value;
  }

  Uint8List bcsSerialize() {
      final serializer = BcsSerializer();
      serialize(serializer);
      return serializer.bytes;
  }

  static ComplexEnum bcsDeserialize(Uint8List input) {
    final deserializer = BcsDeserializer(input);
    final value = ComplexEnum.deserialize(deserializer);
    if (deserializer.offset < input.length) {
      throw Exception('Some input bytes were not read');
    }
    return value;
  }
}


@immutable
class ComplexEnumAItem extends ComplexEnum {
  const ComplexEnumAItem({
    required this.id,
    required this.value,
    required this.a,
  }) : super();

  ComplexEnumAItem.load(BinaryDeserializer deserializer) :
    id = deserializer.deserializeString(),
    value = deserializer.deserializeString(),
    a = deserializer.deserializeString();

  final String id;
  final String value;
  final String a;


  void serialize(BinarySerializer serializer) {
    serializer.serializeVariantIndex(0);
    serializer.serializeString(id);
    serializer.serializeString(value);
    serializer.serializeString(a);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other.runtimeType != runtimeType) return false;

    return other is ComplexEnumAItem
    &&  id == other.id
    &&  value == other.value
    &&  a == other.a
    ;}

  @override
  int get hashCode => Object.hash(
        id,
        value,
        a,
      );

  @override
  String toString() {
    String? fullString;

    assert(() {
      fullString = '$runtimeType('
        'id: $id, '
        'value: $value, '
        'a: $a'
        ')';
      return true;
    }());

    return fullString ?? 'ComplexEnumAItem';
  }
}

@immutable
class ComplexEnumBItem extends ComplexEnum {
  const ComplexEnumBItem({
    required this.id,
    required this.value,
    required this.b,
  }) : super();

  ComplexEnumBItem.load(BinaryDeserializer deserializer) :
    id = deserializer.deserializeString(),
    value = deserializer.deserializeInt64(),
    b = deserializer.deserializeString();

  final String id;
  final int value;
  final String b;


  void serialize(BinarySerializer serializer) {
    serializer.serializeVariantIndex(1);
    serializer.serializeString(id);
    serializer.serializeInt64(value);
    serializer.serializeString(b);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other.runtimeType != runtimeType) return false;

    return other is ComplexEnumBItem
    &&  id == other.id
    &&  value == other.value
    &&  b == other.b
    ;}

  @override
  int get hashCode => Object.hash(
        id,
        value,
        b,
      );

  @override
  String toString() {
    String? fullString;

    assert(() {
      fullString = '$runtimeType('
        'id: $id, '
        'value: $value, '
        'b: $b'
        ')';
      return true;
    }());

    return fullString ?? 'ComplexEnumBItem';
  }
}

@immutable
class ComplexEnumCItem extends ComplexEnum {
  const ComplexEnumCItem({
    required this.id,
    required this.value,
    required this.c,
  }) : super();

  ComplexEnumCItem.load(BinaryDeserializer deserializer) :
    id = deserializer.deserializeString(),
    value = deserializer.deserializeBool(),
    c = deserializer.deserializeString();

  final String id;
  final bool value;
  final String c;


  void serialize(BinarySerializer serializer) {
    serializer.serializeVariantIndex(2);
    serializer.serializeString(id);
    serializer.serializeBool(value);
    serializer.serializeString(c);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other.runtimeType != runtimeType) return false;

    return other is ComplexEnumCItem
    &&  id == other.id
    &&  value == other.value
    &&  c == other.c
    ;}

  @override
  int get hashCode => Object.hash(
        id,
        value,
        c,
      );

  @override
  String toString() {
    String? fullString;

    assert(() {
      fullString = '$runtimeType('
        'id: $id, '
        'value: $value, '
        'c: $c'
        ')';
      return true;
    }());

    return fullString ?? 'ComplexEnumCItem';
  }
}

In the example, the addition this PR adds is the String get id; on the ComplexEnum base class.

Test Plan

Test was added

cc @jerel

@kturney kturney requested a review from ma2bd as a code owner August 23, 2022 05:56
@kturney kturney force-pushed the complex-enum-getters branch from 684807f to cc9e6d1 Compare August 23, 2022 05:57
Kyle Turney (TCNA) added 2 commits August 23, 2022 01:13
@jerel
Copy link
Contributor

jerel commented Aug 23, 2022

I like it! This looks useful to me.

@ma2bd
Copy link
Contributor

ma2bd commented Sep 12, 2022

Ok so this one, I'm not entirely fond of, because it is hard to guess if fields have the same name by accident or not (and how about types?).

I'd rather implement the option with_custom_code which is not currently supported in the dart generator. This would allow injecting user-defined code in generated classes.

@kturney
Copy link
Contributor Author

kturney commented Sep 12, 2022

For the variant property comparison, we are comparing Named, which derives Eq and will compare both name and typed value.

So we should be good checking that the properties have both same name and type.
I also added a test case to cover that, and it gave the expected output.

As for properties only accidentally having same name and type across all variants, I suppose that could happen.
But I'm not sure the harm of making those accessible via the base class.

Does it not seem like a common pattern to be able to access base/interface level properties without having to cast to the concrete type?

With the with_custom_code option I guess the dev would need to add custom code for every complex enum for which they want common properties on the base class?

@jerel
Copy link
Contributor

jerel commented Sep 15, 2022

The downside I see of the with_custom_code approach is that it's strictly name based. The developer isn't able to create a getter based on it being an enum with struct variants, they need to add each name path in the project and keep that list updated as more code is written.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants