immutable_proto 0.1.0
immutable_proto: ^0.1.0

Dart native js
Flutter Android iOS web

Automatically generates immutable data classes for Protocol Buffer messages

This library generates immutable data classes for Protocol Buffers. Here's how to get started:

  1. Add these packages to your dependencies:
dependencies:
  immutable_proto: ^0.1.0

dev_dependencies:
  build_runner: ^1.8.1
  immutable_proto_generator: ^0.1.0
  1. Write your Protocol Buffers definition:
message User {
  string first_name = 1;

  string last_name = 2;

  repeated string email_addresses = 3;

  enum FavoriteDrink {
    UNKNOWN = 0;
    COFFEE = 1;
    COKE = 2;
    TEA = 3;
  }
  FavoriteDrink favorite_drink = 4;
}
  1. Generate the default (mutable) dart code for your Protobuf message (see the official documentation for more information).

  2. Write a blueprint class. Let the name be Mutable<Protobuf name> and annotate it with @ImmutableProto(<Protobuf class>) (Protobuf class is a reference to the generated (mutable) class):

import 'package:immutable_proto/immutable_proto.dart';
// Use an import prefix to avoid name conflicts:
import 'proto_generated/user.pb.dart' as proto;

part 'main.g.dart';

@ImmutableProto(proto.User)
class MutableUser {
  String firstName;

  @required // This field must not be null
  String lastName;

  // Lists are non-nullable by default
  List<String> emailAddresses;

  // Will be replaced by the generated enum
  proto.User_FavoriteDrink favoriteDrink;
}
  1. Run pub run build_runner build in the command line (or flutter pub run build_runner build, if you're using Flutter). The implementation based on your blueprint class will automatically get generated.

The immutable class contains

  • a constructor with named parameters and assertions for required values
  • method/constructor for converting the immutable class to the mutable class (generated by Protocol Buffers) and the other way around
  • custom implementations of ==, hashCode and toString()
  • a copy method
  • enum mappers

For example, here's the generated code of our class above:

@immutable
class User {
  final String firstName;
  final String lastName;
  @required
  final List<String> emailAddresses;
  final UserFavoriteDrink favoriteDrink;

  User({
    this.firstName,
    this.lastName,
    @required this.emailAddresses,
    this.favoriteDrink,
  }) : assert(emailAddresses != null);

  User.fromProto(proto.User user)
      : this(
          firstName: user.firstName,
          lastName: user.lastName,
          emailAddresses: user.emailAddresses,
          favoriteDrink: userFavoriteDrinkFromProto(user.favoriteDrink),
        );
  proto.User toProto() {
    final user = proto.User();
    if (firstName != null) user.firstName = firstName;
    if (lastName != null) user.lastName = lastName;
    user.emailAddresses.addAll(emailAddresses);
    if (favoriteDrink != null)
      user.favoriteDrink = userFavoriteDrinkToProto(favoriteDrink);
    return user;
  }

  bool operator ==(Object other) {
    return other is User &&
        firstName == other.firstName &&
        lastName == other.lastName &&
        emailAddresses == other.emailAddresses &&
        favoriteDrink == other.favoriteDrink;
  }

  int get hashCode => hashList([
        firstName,
        lastName,
        emailAddresses,
        favoriteDrink,
      ]);
  User copy({
    String firstName,
    String lastName,
    List<String> emailAddresses,
    UserFavoriteDrink favoriteDrink,
  }) =>
      User(
        firstName: firstName ?? this.firstName,
        lastName: lastName ?? this.lastName,
        emailAddresses: emailAddresses ?? this.emailAddresses,
        favoriteDrink: favoriteDrink ?? this.favoriteDrink,
      );

  String toString() {
    return 'User(firstName: $firstName, lastName: $lastName, emailAddresses: $emailAddresses, favoriteDrink: $favoriteDrink)';
  }

  static UserFavoriteDrink userFavoriteDrinkFromProto(
      proto.User_FavoriteDrink userFavoriteDrink) {
    switch (userFavoriteDrink) {
      case proto.User_FavoriteDrink.COFFEE:
        return UserFavoriteDrink.coffee;
      case proto.User_FavoriteDrink.COKE:
        return UserFavoriteDrink.coke;
      case proto.User_FavoriteDrink.TEA:
        return UserFavoriteDrink.tea;
      case proto.User_FavoriteDrink.UNKNOWN:
      default:
        return UserFavoriteDrink.unknown;
    }
  }

  static proto.User_FavoriteDrink userFavoriteDrinkToProto(
      UserFavoriteDrink userFavoriteDrink) {
    switch (userFavoriteDrink) {
      case UserFavoriteDrink.coffee:
        return proto.User_FavoriteDrink.COFFEE;
      case UserFavoriteDrink.coke:
        return proto.User_FavoriteDrink.COKE;
      case UserFavoriteDrink.tea:
        return proto.User_FavoriteDrink.TEA;
      case UserFavoriteDrink.unknown:
      default:
        return proto.User_FavoriteDrink.UNKNOWN;
    }
  }
}

enum UserFavoriteDrink {
  unknown,
  coffee,
  coke,
  tea,
}

Features #

  • [x] Generate basic immutable classes for a message
  • [x] Generate classes for nested messages automatically
  • [x] Generate enum + mappers for nested enums automatically
  • [ ] Support built-in wrappers (e.g. UInt32Value)
  • [ ] oneof-support
  • [ ] Commented code
  • [ ] Custom methods
1
likes
105
pub points
19%
popularity

Publisher

wanke.dev

Automatically generates immutable data classes for Protocol Buffer messages

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

Apache 2.0 (LICENSE)

Dependencies

meta

More

Packages that depend on immutable_proto