Hello everyone, I'm playing around with a Rust implementation for Cap'n Proto. Check it out: http://github.com/dwrensha/capnproto-rust . I welcome any comments or contributions.
The reason I'm sharing this project with you now is I'd like to ask about a language feature missing from Rust that I feel may be hindering my progress. To the point, I want to be able define a trait like this: trait Constructable<'self> { fn construct<'a>(StructReader<'a>) -> Self<'a>; } The important detail here is that the lifetime 'a of the constructed object is the same as the lifetime of the constructor's input. Why do I want this? When we are reading a Cap'n Proto message, the message's data is just an immutable byte vector owned by some enclosing scope. To traverse the message, we use auxiliary data structures such as `StructReader<'a>` and `ListReader<'a>` that hold slices of the message and various indices into them. These auxiliary structures are internal to the library and should not be exposed to the user. They are in turn wrapped by specialized user-facing structs. For example, if AddressBook is a user-defined message, then capnproto-rust generates an `AddressBook::Reader<'a>` struct, with message-specific accessor methods, which can be constructed from a generic `StructReader<'a>`. Here we hit a problem. We want the user to be able to do something like this: let addressBookReader = message.readRoot::<AddressBook::Reader>(); If we had the `Constructable` trait above, we could achieve that like this: impl <'self> MessageReader <'self> { // ... fn readRoot<T : Constructable> (&self) -> T<'a> { Constructable::construct(self.readRootStructReader()) } } but otherwise the user is forced to do something like: let addressBookReader = AddressBook::Reader::new(message.readRootStructReader()); or maybe, if we want to hide the `StructReader` as much a possible: let addressBookReader = AddressBook::Reader::constructFromMessageRoot(message); Note that the latter workaround requires that capnproto-rust generate a `constructFromMessageRoot` method for each type of message. We run into more problems when we start considering lists. Cap'n Proto messages may contain arbitrarily nested lists. So, for example, we may encounter a list of lists of AddressBooks. Under the hood, these will be generic ListReaders, but we would like to provide users an appropriate specialized interface to them. For instance, if a user gets an element from a list of structs, it should not be a generic StructReader---it should be a reader of the appropriate specialized type. As a simple example, we want allow uses like this: let people = addressBookReader.getPeople(); for std::uint::range(0, people.size()) |i| { let person = people.get(i); printfln!("person: %s, email: %s", person.getName(), person.getEmail()); } Generalizing such usage to the general case of arbitrarily nested lists seems to require a trait like `Constructable`. Otherwise I can't see a way around writing a tangled mess of `constructFrom...` methods. Just ask yourself: what type does `people` need to be so that it can implement the `get` method? It seems to me that the natural answer is something like "the instantiation of some struct with a type parameter <T : Constructable>". I'll note that my implementation strategy has been to follow the C++ Cap'n Proto implementation, which uses templates to solve all of these problems. My big questions are: Is there a way to do what I want in Rust? If not, why not?---and will there be in the future? Thanks, David _______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev