# Autoproto
This crate implements a custom derive macro for the `prost::Message` trait, along with including
some helper traits to make automatic derivation as simple as possible - basically putting more
information in the type system instead of in the macro implementation. If the macro doesn't do
something that you need it to do, you can implement one of the "base traits" like `ProtoStruct` and
`ProtoOneof` and use the functions in the `generic` module to implement the rest of the traits.
### Limitations
#### (Currently) no oneof-nested-within-struct
This can be lifted eventually, but right now a major limitation of this derive macro is that we
cannot support protobuf types like so:
```proto
message Foo {
string first = 1;
oneof some_oneof {
string second = 2;
string third = 3;
}
}
```
As the library is written, it will only support `oneof` when it is the only member of a message.
#### No automatic generation from `.proto` files
This is the biggest change from `prost`, and was a deliberate choice. I consider automatically
generating the Rust files from protobuf files to be (at least in part) a misfeature of `prost`,
since for many cases it leads to extremely unwieldy types in Rust. Rust has a deep and rich type
system and it isn't possible for Protobuf to nicely represent it. Eventually I want to have compile-
time checking that a Rust type is compatible with a given protobuf file, but this is currently not
implemented.
### Improvements and changes from `#[derive(prost::Message)]`
#### Supporting more types as fields
This macro supports collections other than `Vec` for repeated fields, bare enumerations in structs,
`usize`/`isize`, and maps. For repeated collections, any type that implements `std::iter::Extend`
and where a reference to that type can be iterated over can be used as a collection in a struct.
Currently you must manually implement `Proto` and `ProtoEncode` for these types, but if and when
`feature(specialization)` is stablised this restriction should hopefully be lifted.
While currently we cannot automatically support any type implementing `proto::Message` as a field -
because that trait is implemented for scalars and the main reason we have our own trait is so we can
have a different impl for scalars - you just need to implement the `IsMessage` marker trait to allow
the type to be used as a field in a `#[derive(autoproto::Message)]` type.
Also, messages no longer need to be wrapped in an `Option`, as protobuf's eager decoding already
requires that all messages implement `Default`. You can wrap any type in an `Option` if you want to
distinguish between a field being supplied with default values or not supplied at all.
#### Deriving for more kinds of types
This macro allows deriving for pretty much any tagged union, and deriving for generic structures.
For example:
```rust,no_run
# #![feature(generic_associated_types)]
#[derive(Copy, Clone, PartialEq, Debug, autoproto::Message)]
enum Oneof {
Nothing,
One(A),
Two(A, B),
Three(A, B, C),
}
```
#### No mixed tagged-untagged structs
One change from the `prost` macro is that either all fields must be tagged or no fields can be
tagged. For example, these two are ok:
```rust
# #![feature(generic_associated_types)]
#[derive(Copy, Clone, PartialEq, Default, Debug, autoproto::Message)]
struct SomeStructTagged {
#[autoproto(tag = 1)]
a: A,
#[autoproto(tag = 2)]
b: B,
#[autoproto(tag = 3)]
c: C,
#[autoproto(tag = 4)]
d: D,
#[autoproto(tag = 5)]
e: E,
}
#[derive(Copy, Clone, PartialEq, Default, Debug, autoproto::Message)]
struct SomeStruct {
a: A,
b: B,
c: C,
d: D,
e: E,
}
```
But the following is not:
```rust,compile_fail
# #![feature(generic_associated_types)]
#[derive(Copy, Clone, PartialEq, Default, Debug, autoproto::Message)]
struct SomeStruct {
a: A,
b: B,
#[autoproto(tag = 1)]
c: C,
d: D,
e: E,
}
```