shmp 0.1.0

A flexible and efficient MessagePack serialization implementation in Rust
Documentation
# shmp


[![crates.io](https://img.shields.io/crates/v/shmp.svg)](https://crates.io/crates/shmp)
[![docs.rs](https://docs.rs/shmp/badge.svg)](https://docs.rs/shmp)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](./LICENSE-MIT)

A flexible and efficient MessagePack implementation in Rust, designed with `serde` integration in mind.

`shmp` offers two primary ways to work with MessagePack data:

1. **Direct Serialization with Serde**: Serialize and deserialize your Rust structs directly to and from MessagePack bytes for maximum performance and type safety. (This is the default and recommended approach).
2. **Dynamic `Pack` Enum**: Work with a dynamic, `serde_json::Value`-like enum (`shmp::Pack`) to represent MessagePack data when the schema is unknown at compile time.

## Features


* **Serde Integration**: Robust support for `serde` allows for easy serialization and deserialization of custom types.
* **Dynamic `Pack` Type**: A flexible enum for representing and manipulating any valid MessagePack data.
* **`pack!` Macro**: An intuitive, JSON-like macro for ergonomic creation of `Pack` values.
* **Zero-Copy Deserialization**: Efficiently deserialize `&str` and `&[u8]` from a byte slice without unnecessary allocations.
* **Extensible**: Provides `EncodeExt` and `DecodeExt` traits to easily support custom MessagePack extension types.
* **Optional Features**:
  * `chrono`: Adds support for serializing/deserializing `chrono::DateTime<Utc>` and `chrono::NaiveDateTime` as MessagePack Timestamps.

## Installation


Add `shmp` to your `Cargo.toml`:

```toml
[dependencies]
shmp = "0.1.0"
```

To enable optional features like `chrono`:

```toml
[dependencies]
shmp = { version = "0.1.0", features = ["chrono"] }
```

## Quick Start


### 1. Using Serde (Recommended)


This is the most common and idiomatic way to use `shmp`.

```rust
use serde::{Serialize, Deserialize};
use shmp::{to_vec, from_slice, to_writer, from_reader, to_pack, from_pack, Pack};

#[derive(Serialize, Deserialize, Debug, PartialEq)]

struct User {
    id: u32,
    username: String,
    is_active: bool,
}

fn main() -> Result<(), shmp::Error> {
    let user = User {
        id: 1024,
        username: "shmp_user".to_string(),
        is_active: true,
    };

    // 1. Direct serialization to/from bytes
    let encoded: Vec<u8> = to_vec(&user)?;
    let decoded: User = from_slice(&encoded)?;

    assert_eq!(user, decoded);
    println!("Successfully round-tripped via bytes: {:?}", decoded);

    // 2. Serialization to/from an I/O stream (like a file or network socket)
    let mut buffer: Vec<u8> = Vec::new();
    to_writer(&mut buffer, &user)?;
    let mut reader = std::io::Cursor::new(&buffer);
    let decoded_from_reader: User = from_reader(&mut reader)?;

    assert_eq!(user, decoded_from_reader);
    println!("Successfully round-tripped via reader/writer: {:?}", decoded_from_reader);

    // 3. Using the `Pack` enum as an intermediate representation
    // Struct -> Pack -> Bytes
    let encoded_pack: Pack = to_pack(&user)?; // Pass a reference, which also works.
    let encoded_from_pack: Vec<u8> = to_vec(&encoded_pack)?;
    // Bytes -> Pack -> Struct
    let decoded_pack: Pack = from_slice(&encoded_from_pack)?;
    let decoded_from_pack: User = from_pack(decoded_pack)?;
    assert_eq!(user, decoded_from_pack);
    println!("Successfully round-tripped via Pack enum: {:?}", decoded_from_pack);

    return Ok(());
}
```

### 2. Using the Dynamic `Pack` Enum


Useful when the structure is not known at compile time.

```rust
use shmp::{to_vec, from_slice, from_pack, pack, Pack};
use serde::Deserialize;

fn main() -> Result<(), shmp::Error> {
    let manual_pack = Pack::Map(vec![
        (Pack::String("id".into()), Pack::Uint(12345u64)),
        (Pack::String("username".into()), Pack::String("shmp".into())),
        (Pack::String("is_active".into()), Pack::Boolean(true)),
    ]);

    // Manually creating a `Pack` value can be verbose.
    // The `pack!` macro provides a much cleaner, JSON-like syntax for the same result.
    let macro_pack = pack!({
        "id": 12345u32,
        "username": "shmp",
        "is_active": true
    });

    assert_eq!(manual_pack, macro_pack);
    println!("Successfully created Pack value with the pack! macro.");

    // The macro-created value can be serialized and deserialized like any other `Pack`.
    let encoded = to_vec(&macro_pack)?;
    let decoded: Pack = from_slice(&encoded)?;

    assert_eq!(macro_pack, decoded);
    assert_eq!(manual_pack, macro_pack, "Both methods produce the same Pack value");

    // It can also be deserialized directly into a struct.
    #[derive(Deserialize, Debug, PartialEq)]
    struct User {
        id: u32,
        username: String,
        is_active: bool,
    }

    // It can also be deserialized directly into a struct.
    let user = User {
        id: 12345u32,
        username: "shmp".to_string(),
        is_active: true,
    };
    let macro_user: User = from_pack(macro_pack)?;
    assert_eq!(user, macro_user);
    println!("Successfully created and round-tripped User value with the pack! macro.");
    
    Ok(())
}

```

## License


This project is dual-licensed under either of

* Apache License, Version 2.0, (LICENSE-APACHE or <http://www.apache.org/licenses/LICENSE-2.0>)
* MIT license (LICENSE-MIT or <http://opensource.org/licenses/MIT>)

at your option.