Git Product home page Git Product logo

protobuf.dart's Introduction

CI status

Protobuf support for Dart

Protocol Buffers (protobuf) are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data.

This repository is home to packages related to protobuf for Dart.

Package Description Published Version
protobuf A support library for the generated code pub package
protoc_plugin A Dart back-end for the protoc compiler pub package
api_benchmark Benchmarking for various API calls
query_benchmark Benchmark for encoding and decoding of a "real-world" protobuf

Publishing automation

For information about our publishing automation and release process, see https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.

protobuf.dart's People

Contributors

antonm avatar cbracken avatar dependabot[bot] avatar devoncarew avatar domesticmouse avatar iinozemtsev avatar jakemac53 avatar jakobr-google avatar jonasfj avatar justinfagnani avatar kevmoo avatar king0liver avatar lorenvs avatar mightyvoice avatar mit-mit avatar mkustermann avatar mraleph avatar nichite avatar osa1 avatar rakudrama avatar selkhateeb avatar sgjesse avatar sigmundch avatar sigurdm avatar srawlins avatar szakarias avatar tcriess avatar tvolkert avatar wibling avatar xclud avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

protobuf.dart's Issues

Cloning should avoid validation checks

When merging data from the same field (i.e. identical FieldInfo) we can avoid validation checks because the source must already have been validated. This will be especially beneficial for repeated fields.

fixing (or documenting?) clearField semantics for optional fields

This bug was reported from a user:

GeneratedMessage.clearField() is broken for optional fields.

clearField (and consequently generated helpers that use it) set the field to the default value instead of clearing it. As a consequence, the following test fails:

var proto = new ProtoWithOptionalField();
proto.clearTheOptionalField();
expect(proto.hasTheOptionalField(), false); // Boom!

Call .check() when constructed

Wouldn't it make sense to always call .check() on a GeneratedMessage when it's generated with .fromBuffer() or .fromJson()? This just really got me and I don't quite see why you wouldn't want to run a check...

Support decoded Map<String, dynamic> "JSON" input in fromJson

Here's my use-case: I get the JSON for a protobuf inside a larger JSON, so I already have it in decoded (Map<String, dynamic>) form.
To deserialize the protobuf with MyGeneratedMessage.fromJson, I need to stringify that map first, then let GeneratedMessage.fromJson parse it again.

It would be nice to be able to feed the decoded JSON to fromJson.

To do this, I suggest adding the following method to both GeneratedMessage and the generated MyGeneratedMessage:
fromDecodedJson(Map<String, dynamic> value, ExtensionRegistry).

Any thoughts?

Strong-mode analysis errors prevent DDC compilation

The following list of strong-mode errors prevent code that depend on package:protobuf from being compiled with DDC.

(ran pub get && dartanalyzer --strong find lib -name '*.dart' | sort -u with SDK version 1.16.0-dev.0.0)

[error] Invalid override. The type of PbList.setRange ((int, int, List<E>, [int]) → void) is not a subtype of List<E>.setRange ((int, int, Iterable<E>, [int]) → void). (./lib/src/protobuf/pb_list.dart, line 90, col 3)
[error] Invalid override. The type of PbList.setRange ((int, int, List<E>, [int]) → void) is not a subtype of ListMixin<E>.setRange ((int, int, Iterable<E>, [int]) → void). (./lib/src/protobuf/pb_list.dart, line 90, col 3)
[hint] The method '_getBaseFieldType' is not used (./lib/src/protobuf/generated_message.dart, line 1029, col 7)
[warning] Unsound implicit cast from List<dynamic> to Iterable<GeneratedMessage> (./lib/src/protobuf/builder_info.dart, line 207, col 48)
[warning] Unsound implicit cast from List<dynamic> to Iterable<int> (./lib/src/protobuf/generated_message.dart, line 292, col 29)
[warning] Unsound implicit cast from List<dynamic> to Iterable<int> (./lib/src/protobuf/generated_message.dart, line 378, col 27)
[warning] Unsound implicit cast from List<dynamic> to Iterable<int> (./lib/src/protobuf/generated_message.dart, line 678, col 27)
[warning] Unsound implicit cast from List<dynamic> to Iterable<int> (./lib/src/protobuf/generated_message.dart, line 708, col 27)
[warning] Unsound implicit cast from List<dynamic> to Iterable<int> (./lib/src/protobuf/unknown_field_set.dart, line 137, col 21)
[warning] Unsound implicit cast from dynamic to List<int> (./lib/src/protobuf/generated_message.dart, line 654, col 42)
[warning] Unsound implicit cast from dynamic to Map<String, dynamic> (./lib/src/protobuf/generated_message.dart, line 844, col 20)

Int64 is signed, but we use it to store unsigned 64-bit values

We are storing both signed and unsigned 64-bit integers in as instances of Int64, even though the Int64 class is intended for signed values. It's up to the caller to treat the the value appropriately.

This is confusing because methods on Int64 such as isNegative() return the wrong thing for numbers from 1<<31 to the top of the range.

To fix this we would need to add another type to the fixnum library:
dart-lang/fixnum#20

default message created again on each access

Code like this has no effect:

var rec = new pb.Rec();
rec.msg.str = "hello";

The reason is that when getField() returns the default value of a message field, it doesn't store it in the map. As a workaround, you can explicitly initialize the message:

var rec = new pb.Rec();
rec.msg = new pb.Msg();
rec.msg.str = "hello";

Generate method to get assigned oneof field

Protobuf supports "oneof" since 1.6. Currently oneof fields are generated like any other field. In Java there is a getOneofNameCase method that returns which field is set. A method like this is missing for dart. This bug is related to #33

Extension registry is ignored

The extensionRegistry argument in CodedBufferReader.readGroup and CodedBufferReader.readMessage is ignored.

It looks like

message.mergeFromCodedBufferReader(this);

in these methods should be changed to

message.mergeFromCodedBufferReader(this, extensionRegistry);

Add support for unknown fields in JSON serialization

When reading and writing protobufs to JSON, we currently only serialize extensions if they are registered. Unknown fields are ignored.

This is a problem for the JSON-encoded constants for metadata in .pb.dart files. Any extensions in the original protobuf descriptor get stripped. It would be good to encode them somehow, instead.

Incorrect results decoding ZigZag for int32 using Dart2js

The decoding worked in Dartium, but when I used Dart2js deserializing a protocol buffer containing signed int32s it threw exceptions for values being out of bounds of signed int32.

Fox32 found the replacement function that works, I have tested and confirmed that it works in Dartium and in Chrome with Dart2js.

http://stackoverflow.com/questions/17427976/bitwise-operations-wrong-result-in-dart2js/17433485#17433485

Can this function replace the _decodeZigZag32 in coded_buffer_reader.dart or will users need to account for this issue themselves?

Tweak PbList.hashCode

Rewriting forEachto for(E value in _wrappedList) will produce better dart2js code.
It will be a while before we can inline that.

  int get hashCode {
    int hash = 0;
    _wrappedList.forEach((E value) {
      hash = (hash + value.hashCode) & 0x3fffffff;
      hash = (hash + hash << 10) & 0x3fffffff;
      hash = (hash ^ hash >> 6) & 0x3fffffff;
    });
    hash = (hash + hash << 3) & 0x3fffffff;
    hash = (hash ^ hash >> 11) & 0x3fffffff;
    hash = (hash + hash << 15) & 0x3fffffff;
    return hash;
  }```

possibility to make protobuffer entities @observable

I use protobuf entities in polymer elements. For automatic binding / updating those entities must implement the Observable interface.

protoc could automatically implement this interface but a probably easier and less invasive way would be if protoc allowed generated entities to extend from something different than GeneratedMessage.

This would reduce the changes to:

  • importing another library
  • extending from another class
  • passing a symbol to the setField, getField, clearField super functions.
    (This would allow us to use ChangeNotifier)

If you think this is a good /acceptable approach I would try to implement this.

(I currently have a fork where the generated code implements ChangeNotifier in the protoc output and not the super class)

http://stackoverflow.com/questions/25868749/how-do-i-observe-objects-which-do-not-implement-observe-observable-in-polymer

bugs in tests

The latest dart editor highlights a couple bugs in the unit tests.

Keep the actual fieldnames around in BuilderInfo

For some reason, field names in BuilderInfo are converted to lower camelcase from underscores. This makes it harder to deserialize protos generated by other JSON proto libraries. Eg the Java proto to json serializer or https://github.com/google/protobuf.

If there is an reason to keep the modified field name, it would be nice to provide the actual field name in a different field.

Two messages with the same name but in different packages

In the proto files I have the same message name but in different packages.
The generated Dart code has no indication which Class to instantiate

..a(1100, 'nominatedWorkNominations', GeneratedMessage.OM, () => new Nominations(), () => new Nominations())
..a(1200, 'nomineeNominations', GeneratedMessage.OM, () => new Nominations(), () => new Nominations())

message Property {
optional nominated_work.Nominations NominatedWork_Nominations = 1100;
optional nominee.Nominations Nominee_Nominations = 1200;
}

How can this be resolved?

Length-prefix Stream encoder/decoders for proto-based RPCs

Most proto RPC I've seen uses some kind of length-prefix encoding for the separation of the messages. Would it be a good place to provide such thing along the protobuf runtime? The following example uses a fixed 4-byte length prefix for each message on the stream.


class PacketPrefixEncoder implements StreamTransformer<List<int>, List<int>> {
  Stream<List<int>> bind(Stream<List<int>> stream) =>
      new Stream.eventTransformed(stream,
          (sink) => new _PacketPrefixEncoderSink(sink));
}

class PacketPrefixDecoder implements StreamTransformer<List<int>, List<int>> {
  Stream<List<int>> bind(Stream<List<int>> stream) =>
      new Stream.eventTransformed(stream,
          (sink) => new _PacketPrefixDecoderSink(sink));
}

class _PacketPrefixEncoderSink implements EventSink<List<int>> {

  final EventSink<List<int>> _outputSink;
  _PacketPrefixEncoderSink(this._outputSink);

  void add(List<int> event) {
    ByteData length = new ByteData(4);
    length.setUint32(0, event.length, Endianness.LITTLE_ENDIAN);
    _outputSink.add(new Uint8List.view(length.buffer, 0, 4));
    _outputSink.add(event);
  }

  void addError(errorEvent, [StackTrace stackTrace]) =>
      _outputSink.addError(errorEvent, stackTrace);

  void close() =>
      _outputSink.close();
}

class _PacketPrefixDecoderSink implements EventSink<List<int>> {

  final EventSink<List<int>> _outputSink;
  _PacketPrefixDecoderSink(this._outputSink);

  BytesBuilder _buffer = null;
  int _length;

  void add(List<int> data) {
    bool added = true;
    while (added) {
      added = false;

      if (_buffer == null) {
        _buffer = new BytesBuilder();
      }
      _buffer.add(data);

      if (_length == null && _buffer.length >= 4) {
        var byteData =
            new ByteData.view(new Uint8List.fromList(_buffer.toBytes()).buffer);
        _length = byteData.getUint32(0, Endianness.LITTLE_ENDIAN);
      }

      if (_length != null && _buffer.length >= _length + 4) {
        Uint8List base = new Uint8List.fromList(_buffer.toBytes());
        Uint8List msg = new Uint8List.view(base.buffer, 4, _length);

        if (_buffer.length == _length + 4) {
          _buffer = null;
        } else {
          var next = new Uint8List.view(base.buffer, 4 + _length);
          _buffer.clear();
          _buffer.add(next);
        }
        _length = null;

        _outputSink.add(msg);
        added = true;
      }
    }
  }

  void addError(errorEvent, [StackTrace stackTrace]) =>
      _outputSink.addError(errorEvent, stackTrace);

  void close() {
    if (_buffer != null) {
      _outputSink.addError(
          "Unprocessed buffer: ${_buffer.length} bytes.");
    }
     _outputSink.close();
  }
}

Compare operator does not handle cleared lists

Assume the protobuffer test.proto:

syntax = "proto2";

message Simple {
  optional string name = 1;
  repeated int32 values = 2;
}

This will fail the '==' test (serialization is ok, however compare seems to differentiate between 'empty list' and 'list never initialized'). I would expect: if object type and serialization is identical, then objects should be identical:

library simple_test;

import 'package:unittest/unittest.dart';
import 'test.pb.dart';

void main() {
  Simple s1 = new Simple()
      ..name = 'Name'
      ;

  Simple s2 = new Simple()
      ..name = 'Name'
      ..values.clear() // redundant
      ;

  test('Json', () => expect(s1.writeToJson(), equals(s2.writeToJson())));
  test('==', () => expect(s1, equals(s2)));   // FAILS!
  test('Buffer', () => expect(s1.writeToBuffer(), equals(s2.writeToBuffer())));
}

API for creating read-only protobufs

We would like a way to create read-only GeneratedMessages, using some kind build or freeze API.

An important use case is to storing read-only data in a cache and passing out references to it without corrupting the cache.

Some issues to consider:

  • Is it recursive?
  • Do we need to freeze in place or is creating a read-only clone acceptable?
  • Do we need to unfreeze it?
  • Do we want read-only types? That is, for message Foo, should we also have ReadonlyFoo?

provide a way to retrieve all enum values

I am looking for a way to retrieve all enum values from the fieldInfos.

I can easily get the default value, but the values() function is static and AFAIC there is no easy way (without mirrors) to call this static values() function from the default enum value.

Support long ints when merging to/from JSON

Just filing this as a vote for some TODOs already in the code:

There are still a few getInt64/getUint64 accesses in GeneratedMessage _toString and _toMap. These work fine in Dartium but fail in dart2js, which makes it impossible to use mergeTo/FromJson for compiled code.

We'd really like to use to/fromJson as a standard approach for RPCs, and this is the only blocker. Thanks!

Create structure with repeated field

Hi! I'm trying to create a structure with a repeated field. At the moment, as far as i can see, the dart file generated by protoc doesn't export setters for repeated fields. Are there plans to add this in the future?

Run in javascript fails

when trying to run in javascript, in chrome, an app using protobuf package, an exception occurs in "GeneratedMessage.fromBuffer" (I assume because I do not know how to debug when it is running in compiled javascript).

The exception is:
Uncaught CastError: Casting value of type ByteBuffer to incompatible type List js_helper.dart:1796

I can provide you with a test case if needed, may be it is not expected to use protobuf in javascript compiled program, but then it should be explained somewhere.

Many thanks for this project and for your help,
Adrien

verify that byte arrays are handled consistently

Byte array fields are treated in some ways like repeated fields.

  • They are stored in a mutable List
  • hasField() returns false if they're empty.
  • an empty byte array doesn't change the hashCode (versus null)

In other ways they're treated differently: you can use setField() to replace a byte array.
It seems like the corner cases need to be tested better, particular for events.

hashCode is problematic

The current implementation of hashCode in generated_message.dart hashes the values of the fields of the protobuf – https://github.com/dart-lang/dart-protobuf/blob/f821faf77a3d273255a76ea723a46f390d1a89f8/lib/src/protobuf/generated_message.dart#L291.  This prevents its use as a map key or in a set since a protobuf is mutable.  Perhaps the hashCode getter should not be abused this way and this functionality should be moved into a regular method (e.g. "hash()") to avoid this issue.  In the current state, it only makes sense if the protobuf itself is immutable.

Mixins need to enforce read-only behavior for default instance

For each protobuf class there is a default instance, which should be read-only. Mixins may add extra fields and a way to set them. Any mixin with a setter should throw an exception if the instance is read-only.

Currently the _isReadOnly getter is private. We should make it public. In the meantime, a mixin can implement the check like this:

if (this is ReadonlyMessageMixin) {
  throw new UnsupportedError(
    "attempted to set <somefield> on a read-only message (${info_.messageName})");
}

named arguments to set fields in a constructor

I am not sure if this feature request is worth it, but I wanted to share the idea, so here it is:

What if we take generated messages and make a constructor that takes as arguments the actual fields from the proto buff? for example:

message A {
  required someField = 1;
  optional otherField = 2;
}

generates:

class A extends GeneratedMessage {
  A.filled(this.someField, {this.otherField});
}

I just often see patterns where developers have all the data they need to fill in, and end up writing code like:

  new A()
      ..someField = a
      ..otherField  = b

instead of:

  new A(a, otherField: b)

How about putting clone() into GeneratedMessage?

Protobuf library: Every generate class that extends GeneratedMessage has a clone method, how about putting clone() into GeneratedMessage?
////////////////////////////////////////////////////////////////////////////////////
Editor: 1.5.0.dev_04_02 (2014-06-06)
OS: Windows 8 - amd64 (6.2)
JVM: 1.7.0_51

projects: 5

open dart files: 2

auto-run pub: true
localhost resolves to: 127.0.0.1
mem max/total/free: 1778 / 1209 / 552 MB
thread count: 36
index: 1063521 relationships in 180908 keys in 1616 sources

SDK installed: true
Dartium installed: true

Codec generator?

I think it would be worth to create JSON-Codec and Buffer-Codec for the generated messages, as it would reduce some of the boilerplate in the client's code. Maybe as an option in the generated output? A simple example is the following, the extension could be passed in too:

class _Message__BufferEncoder extends Converter<Message, List<int>> {
  List<int> convert(Message input) =>
      input.writeToBuffer();
}

class _Message__BufferDecoder extends Converter<List<int>, Message> {
  Message convert(List<int> input) =>
      new Message.fromBuffer(input);
}

class Message__BufferCodec extends Codec<Message, List<int>> {
  Converter _decoder = new _Message__BufferDecoder();
  Converter _encoder = new _Message__BufferEncoder();
  Converter<List<int>, Message> get decoder => _decoder;
  Converter<Message, List<int>> get encoder => _encoder;
}

Circular dependency result in Stack overflow

The following object with a circular dependency throws a Stack Overlfow:

Person child = new Person()
      ..firstName = "Eliott"
      ..lastName = "Garnier Capbert"

Person person = new Person()
    ..firstName = "Nicolas"
    ..lastName = "Garnier"
    ..children.add(child);

child.children.add(person);

I realize circular dependencies are not allowed but a graceful detection and error would be nice as this could happen in real life code and it would be best to have a way to catch these errors.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.