# MessagePack-Async and Unexpected Behavior
## MessagePack-Async
I started working on a [Neovim](https://neovim.io) plugin recently,
and decided to use the RPC-over-MessagePack API and write the plugin
with [Rust](https://www.rust-lang.org/).
There are a few decent MessagePack libraries on
[crates.io](https://crates.io), but I couldn't find anything that I
really liked which worked with [tokio](https://tokio.rs).
I implemented my plugin initially using a synchronous library,
leveraging
[`tokio_util`](https://docs.rs/tokio-util/latest/tokio_util/index.html)
to bridge the reader with a
[`SyncIoBridge`](https://docs.rs/tokio-util/latest/tokio_util/io/struct.SyncIoBridge.html). Working with `tokio` and blocking code is
difficult however, which lead me to write
[`messagepack-async`](https://docs.rs/messagepack-async/latest/messagepack_async).
`messagepack-async` supports reading and writing MessagePack values
using both `std::io::{Read, Write}` and
`tokio::io::{AsyncRead, AsyncWrite}`. It's a simple and clean library
that does what it does well, and nothing else. I have since replaced
the library I was using with `messagepack-async`, making the code a
lot cleaner and more idiomatic.
## Weird Bug
RPC-over-MessagePack defines RPC requests to be a MessagePack array
of the form `[0, {msg_id}, {method_name}, [{param1}, ...]]`. These
calls were working in my plugin to begin with, but strangely about
half of them stopped working when I switched to using my library.
It turns out that what was happening is that while all MessagePack
integers should be treated the same regardless of encoding, Neovim
seems to differentiate between signed and unsigned integers. This
means a `Value::Int(Int::I32(0))` will not work for the leading zero
of a request, but a `Value::Int(Int::U8(0))` will.
In both my library, and the previous one I was using, the `Value`
struct implemented `From` or `TryFrom`. In my library I implemented
these by performing a direct trivial conversion. `100i32` becomes
`Value::Int(Int::I32(100))` for example. On the other hand, the
library I was using was taking the integer, then finding the smallest
possible encoding of the number and encoding any positive numbers as
unsigned. `100i32` here would become `Value::Int(Int::U8(100))`.
This behavior took me longer than I would have liked to diagnose, but
has taught me rather a useful lesson. While my first thought was to
copy this behavior, I decided against it. Instead, I replaced all my
uses of `0` in my plugin, which default to `0i32`, with `0u8` before
calling `Into::into`.
After some thought and research, it seems `Into` should perform the
most trivial conversions possible as to avoid issues like this.
Instead, to provide the minimizing behavior when needed. I created
`Value::r#int`, `Value::unsigned_int`, and `Value::signed_int`
constructors.
This makes the library a little more useful too as it allows
differentiating between encodings of MessagePack's integers when you
need to.