heaplet 0.1.0

A small, in-process, Redis-inspired in-memory store for Rust.
Documentation
//! Encoding/decoding for values stored in the [`Store`](crate::Store).
//!
//! All data structure APIs in this crate store values as shared bytes (`Bytes`).
//! A [`Codec`] controls how typed values are turned into bytes and back.
//!
//! The default implementation is [`BincodeCodec`], backed by `bincode` + `serde`.

use std::sync::Arc;

use serde::{Serialize, de::DeserializeOwned};

use crate::error::Error;

/// Shared byte storage for values in the store.
///
/// `heaplet` stores encoded values as reference-counted byte slices so cloned
/// values are cheap (`Arc` clone) and can be shared across structures.
///
/// Most public APIs accept/return typed values (`T: Serialize` / `T: DeserializeOwned`)
/// and use the store's [`Codec`] to convert between `T` and [`Bytes`].
pub type Bytes = Arc<[u8]>;

/// Encode/decode values stored in [`crate::Store`].
///
/// A [`Codec`] is responsible for turning a typed Rust value into bytes and back.
/// The default codec is [`BincodeCodec`], which uses `bincode`.
///
/// # Thread-safety
/// A codec must be `Send + Sync + 'static` because it is stored inside [`crate::Store`]
/// and used from concurrent operations.
///
/// # Example
///
/// ```rust
/// use heaplet::codec::{BincodeCodec, Codec};
///
/// let c = BincodeCodec;
/// let b = c.encode(&123_i64).unwrap();
/// let v: i64 = c.decode(&b).unwrap();
/// assert_eq!(v, 123);
/// ```
pub trait Codec: Send + Sync + 'static {
    /// Encode `v` into an owned byte buffer.
    fn encode<T: Serialize + ?Sized>(&self, v: &T) -> Result<Bytes, Error>;

    /// Decode `bytes` into type `T`.
    fn decode<T: DeserializeOwned>(&self, bytes: &[u8]) -> Result<T, Error>;
}

/// The default [`Codec`] implementation used by [`crate::Store`].
///
/// This codec uses `bincode` for compact binary encoding.
///
/// # Example
///
/// ```rust
/// use heaplet::codec::{BincodeCodec, Codec};
///
/// let c = BincodeCodec;
/// let b = c.encode(&"hello").unwrap();
/// let v: String = c.decode(&b).unwrap();
/// assert_eq!(v, "hello");
/// ```
#[derive(Clone, Copy, Debug, Default)]
pub struct BincodeCodec;

impl Codec for BincodeCodec {
    fn encode<T: Serialize + ?Sized>(&self, v: &T) -> Result<Bytes, Error> {
        bincode::serialize(v)
            .map(Arc::from)
            .map_err(|e| Error::Encode(e.to_string()))
    }

    fn decode<T: DeserializeOwned>(&self, b: &[u8]) -> Result<T, Error> {
        bincode::deserialize(b).map_err(|e| Error::Decode(e.to_string()))
    }
}