| ## The Rust MessagePack Library |
| |
| RMP is a pure Rust [MessagePack](http://msgpack.org) implementation of an efficient binary |
| serialization format. This crate provides low-level core functionality, writers and readers for |
| primitive values with direct mapping between binary MessagePack format. |
| |
| **Warning** this library is still in rapid development and everything may change until 1.0 |
| comes. |
| |
| ### Usage |
| |
| To use `rmp`, first add this to your `Cargo.toml`: |
| |
| ```toml |
| [dependencies.rmp] |
| rmp = "^0.8" |
| ``` |
| |
| ### Features |
| |
| - **Convenient API** |
| |
| RMP is designed to be lightweight and straightforward. There are low-level API, which gives you |
| full control on data encoding/decoding process and makes no heap allocations. On the other hand |
| there are high-level API, which provides you convenient interface using Rust standard library and |
| compiler reflection, allowing to encode/decode structures using `derive` attribute. |
| |
| - **Zero-copy value decoding** |
| |
| RMP allows to decode bytes from a buffer in a zero-copy manner easily and blazingly fast, while Rust |
| static checks guarantees that the data will be valid until buffer lives. |
| |
| - **Clear error handling** |
| |
| RMP's error system guarantees that you never receive an error enum with unreachable variant. |
| |
| - **Robust and tested** |
| |
| This project is developed using TDD and CI, so any found bugs will be fixed without breaking |
| existing functionality. |
| |
| ### Detailed |
| |
| This crate represents the very basic functionality needed to work with MessagePack format. |
| Ideologically it is developed as a basis for building high-level abstractions. |
| |
| Currently there are two large modules: encode and decode. More detail you can find in the |
| corresponding sections. |
| |
| Formally every MessagePack message consists of some marker encapsulating a data type and the |
| data itself. Sometimes there are no separate data chunk, for example for booleans. In these |
| cases a marker contains the value. For example, the `true` value is encoded as `0xc3`. |
| |
| ```rust |
| let mut buf = Vec::new(); |
| rmp::encode::write_bool(&mut buf, true).unwrap(); |
| |
| assert_eq!([0xc3], buf[..]); |
| ``` |
| |
| Sometimes a single value can be encoded in multiple ways. For example a value of `42` can be |
| represented as: `[0x2a], [0xcc, 0x2a], [0xcd, 0x00, 0x2a]` and so on, and all of them are |
| considered as valid representations. To allow fine-grained control over encoding such values |
| the library provides direct mapping functions. |
| |
| ```rust |
| let mut bufs = vec![vec![]; 5]; |
| |
| rmp::encode::write_pfix(&mut bufs[0], 42).unwrap(); |
| rmp::encode::write_u8(&mut bufs[1], 42).unwrap(); |
| rmp::encode::write_u16(&mut bufs[2], 42).unwrap(); |
| rmp::encode::write_u32(&mut bufs[3], 42).unwrap(); |
| rmp::encode::write_u64(&mut bufs[4], 42).unwrap(); |
| |
| assert_eq!([0x2a], bufs[0][..]); |
| assert_eq!([0xcc, 0x2a], bufs[1][..]); |
| assert_eq!([0xcd, 0x00, 0x2a], bufs[2][..]); |
| assert_eq!([0xce, 0x00, 0x00, 0x00, 0x2a], bufs[3][..]); |
| assert_eq!([0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a], bufs[4][..]); |
| ``` |
| |
| But they aren't planned to be widely used. Instead we often need to encode bytes compactly to |
| save space. In these cases RMP provides functions that guarantee that for encoding the most |
| compact representation will be chosen. |
| |
| ```rust |
| let mut buf = Vec::new(); |
| |
| rmp::encode::write_sint(&mut buf, 300).unwrap(); |
| |
| assert_eq!([0xcd, 0x1, 0x2c], buf[..]); |
| ``` |
| |
| On the other hand for deserialization it is not matter in which representation the value is |
| encoded - RMP deals with all of them. |
| |
| Sometimes you know the exact type representation and want to enforce the deserialization process |
| to make it strongly type safe. |
| |
| ```rust |
| let buf = [0xcd, 0x1, 0x2c]; |
| |
| assert_eq!(300, rmp::decode::read_u16(&mut &buf[..]).unwrap()); |
| ``` |
| |
| However if you try to decode such bytearray as other integer type, for example `u32`, there will |
| be type mismatch error. |
| |
| ```rust |
| let buf = [0xcd, 0x1, 0x2c]; |
| rmp::decode::read_u32(&mut &buf[..]).err().unwrap(); |
| ``` |
| |
| But sometimes all you want is just to encode an integer that *must* fit in the specified type |
| no matter how it was encoded. RMP provides [`such`][read_int] function to ease integration with |
| other MessagePack libraries. |
| |
| ```rust |
| let buf = [0xcd, 0x1, 0x2c]; |
| |
| assert_eq!(300i16, rmp::decode::read_int(&mut &buf[..]).unwrap()); |
| assert_eq!(300i32, rmp::decode::read_int(&mut &buf[..]).unwrap()); |
| assert_eq!(300i64, rmp::decode::read_int(&mut &buf[..]).unwrap()); |
| assert_eq!(300u16, rmp::decode::read_int(&mut &buf[..]).unwrap()); |
| assert_eq!(300u32, rmp::decode::read_int(&mut &buf[..]).unwrap()); |
| assert_eq!(300u64, rmp::decode::read_int(&mut &buf[..]).unwrap()); |
| ``` |
| |
| ### API |
| |
| Almost all API are represented as pure functions, which accepts a generic `Write` or `Read` and |
| the value to be encoded/decoded. For example let's do a round trip for π number. |
| |
| ```rust |
| let pi = std::f64::consts::PI; |
| let mut buf = Vec::new(); |
| rmp::encode::write_f64(&mut buf, pi).unwrap(); |
| |
| assert_eq!([0xcb, 0x40, 0x9, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18], buf[..]); |
| assert_eq!(pi, rmp::decode::read_f64(&mut &buf[..]).unwrap()); |
| ``` |
| |
| [read_int]: decode/fn.read_int.html |
| |
| License: MIT |