#msgpack #message-pack

rmp-futures

Async Rust MessagePack and MessagePack-RPC

8 releases

0.3.2 Sep 13, 2022
0.3.1 Apr 21, 2022
0.3.0 Dec 14, 2021
0.2.2 Nov 30, 2021
0.1.0 Mar 19, 2020

#515 in Asynchronous

Download history 106/week @ 2023-11-06 184/week @ 2023-11-13 51/week @ 2023-11-20 195/week @ 2023-11-27 136/week @ 2023-12-04 86/week @ 2023-12-11 23/week @ 2023-12-18 35/week @ 2023-12-25 82/week @ 2024-01-01 67/week @ 2024-01-08 81/week @ 2024-01-15 140/week @ 2024-01-22 97/week @ 2024-01-29 104/week @ 2024-02-05 171/week @ 2024-02-12 301/week @ 2024-02-19

683 downloads per month

MIT/Apache

125KB
3K SLoC

rmp-futures - Async Rust MessagePack and MessagePack-RPC

Async encode/decode for msgpack and msgpack-rpc. Intended to allow deterministic memory use, making the client responsible for allocation. Since msgpack is a streamable format, the ability to serialize on the fly as the writer becomes writable is exposed. Similarly, the reader can be written to deal with individual encoded objects as they are encountered in the stream. No memory allocations are performed in the library unless requested, such as returning a string as a Rust String or returning an entire object as a dynamic rmpv::Value.

Data types are compatible with rmp and rmpv crates where possible.

Theory of operation

Every time some data is read and a decision point is reached, such as reaching the start of a new item, the client gets a new object that represents the state of the stream and only offers operations that are valid at that point. So a client can have a static decoding sequence for an expected message with the storage requirements known up front.

The underlying reader or writer are moved into the decoder or encoder. It is only possible to get ownership back by performing a sequence of valid operations on the parser, each returning a new type with its own set of valid operations. This enforces at compile time that elements are read before processing the next element, and that encoded messsages are well-formed.

Recursive objects yield recursive types. Example data type progression for reading an array containing one element: [true]

  • R: Initial plain async reader
  • MsgPackFuture: client wraps reader with MsgPackFuture::new() to indicate that this reader is at the start of a message
  • ValueFuture::Array(ArrayFuture): decode() returns an enum
  • ArrayFuture: client matches on the enum and destructures the inner ArrayFuture
  • MsgPackFuture<ArrayFuture>: client calls next(), unwraps the MsgPackOption. Now we're at the start of a new msg that's an element of an array, as indicated by the data type
  • ValueFuture::Boolean(true, ArrayFuture): message decoded as "true"
  • ArrayFuture: destructure the Boolean, now the ArrayFuture is ready to read the next element
  • MsgPackOption::End(R): ArrayFuture::next() returns an enum indicating end of the array
  • R: destructuring the End of the array returns the original reader

Encode and Decode support dynamic write_value() and into_value() functions that deal with heap-allocated messages. This is easier to use at the cost of memory, but also allows easier transition from other libraries that use rmpv::Value such as rmp-rpc.

TODO

  • RpcMessage::Request should produce a handle to be used to send the message back. Currently the client has to save the id and use the correct one when starting the response message.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~3MB
~59K SLoC