Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2026-07-13

### Changed
- Synced from bettersign workspace (bs-multitrait 0.7.0)
- Renamed crate from `bs-multitrait` to `multi-trait`
- Initial published release on crates.io as `multi-trait`

## [1.0.1] - 2025-01-08

### Fixed
Expand Down
25 changes: 22 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
[package]
name = "multitrait"
name = "multi-trait"
version = "1.0.1"
edition = "2021"
authors = ["Dave Grantham <dwg@linuxprogrammer.org>"]
description = "Common traits for multiformats types"
repository = "https://github.com/cryptidtech/multitrait.git"
repository = "https://github.com/cryptidtech/multi-trait.git"
readme = "README.md"
license = "Apache-2.0"
keywords = ["multiformats", "encoding", "multicodec", "multibase", "no_std"]
categories = ["encoding", "data-structures"]

[features]
default = ["std"]
Expand All @@ -18,8 +20,25 @@ unsigned-varint = { version = "0.8", default-features = false }

[dev-dependencies]
proptest = "1.4"
criterion = "0.5"
criterion = { version = "0.5", features = ["html_reports"] }

[[bench]]
name = "encoding"
harness = false
path = "benches/encoding.rs"

[[example]]
name = "basic"
path = "examples/basic.rs"

[[example]]
name = "custom_type"
path = "examples/custom_type.rs"

[[example]]
name = "error_handling"
path = "examples/error_handling.rs"

[[example]]
name = "no_std"
path = "examples/no_std.rs"
6 changes: 4 additions & 2 deletions benches/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
//!
//! Run with: `cargo bench`

use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use multitrait::{EncodeInto, EncodeIntoArray, EncodeIntoBuffer, TryDecodeFrom};
use std::hint::black_box;

use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use multi_trait::{EncodeInto, EncodeIntoArray, EncodeIntoBuffer, TryDecodeFrom};

/// Benchmark encoding operations for various integer types
fn bench_encoding(c: &mut Criterion) {
Expand Down
2 changes: 1 addition & 1 deletion examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! - Sequential encoding and decoding
//! - Using different encoding strategies

use multitrait::{EncodeInto, EncodeIntoArray, EncodeIntoBuffer, TryDecodeFrom};
use multi_trait::{EncodeInto, EncodeIntoArray, EncodeIntoBuffer, TryDecodeFrom};

fn main() {
println!("=== Multitrait Basic Example ===\n");
Expand Down
10 changes: 5 additions & 5 deletions examples/custom_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! - Implementing Null and TryNull for custom types
//! - Creating composable encoding/decoding for complex structures

use multitrait::{EncodeInto, EncodeIntoBuffer, Null, TryDecodeFrom, TryNull};
use multi_trait::{EncodeInto, EncodeIntoBuffer, Null, TryDecodeFrom, TryNull};

fn main() {
println!("=== Multitrait Custom Type Example ===\n");
Expand Down Expand Up @@ -47,7 +47,7 @@ fn simple_newtype() {

// Implement TryDecodeFrom
impl<'a> TryDecodeFrom<'a> for UserId {
type Error = multitrait::Error;
type Error = multi_trait::Error;

fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (id, remaining) = u64::try_decode_from(bytes)?;
Expand Down Expand Up @@ -96,7 +96,7 @@ fn multi_field_struct() {

// Implement TryDecodeFrom - decode fields sequentially
impl<'a> TryDecodeFrom<'a> for Person {
type Error = multitrait::Error;
type Error = multi_trait::Error;

fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (id, remaining) = u32::try_decode_from(bytes)?;
Expand Down Expand Up @@ -244,7 +244,7 @@ fn nested_structures() {

// Implement TryDecodeFrom for Metadata
impl<'a> TryDecodeFrom<'a> for Metadata {
type Error = multitrait::Error;
type Error = multi_trait::Error;

fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (version, remaining) = u8::try_decode_from(bytes)?;
Expand All @@ -267,7 +267,7 @@ fn nested_structures() {

// Implement TryDecodeFrom for Message
impl<'a> TryDecodeFrom<'a> for Message {
type Error = multitrait::Error;
type Error = multi_trait::Error;

fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (metadata, remaining) = Metadata::try_decode_from(bytes)?;
Expand Down
4 changes: 2 additions & 2 deletions examples/error_handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! - Validating data with EncodedBytes
//! - Recovering from errors

use multitrait::{EncodedBytes, Error, TryDecodeFrom};
use multi_trait::{EncodedBytes, Error, TryDecodeFrom};

fn main() {
println!("=== Multitrait Error Handling Example ===\n");
Expand Down Expand Up @@ -215,7 +215,7 @@ fn inspect_error_source() {
/// Helper function showing how to wrap multitrait errors in application-specific errors
#[allow(dead_code)]
mod application_errors {
use multitrait::Error as MultitraitError;
use multi_trait::Error as MultitraitError;

#[derive(Debug)]
pub enum AppError {
Expand Down
6 changes: 3 additions & 3 deletions examples/no_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
// #![no_std]
// extern crate alloc;

use multitrait::{EncodeInto, EncodeIntoArray, EncodeIntoBuffer, TryDecodeFrom};
use multi_trait::{EncodeInto, EncodeIntoArray, EncodeIntoBuffer, TryDecodeFrom};

fn main() {
println!("=== Multitrait no_std Usage Patterns ===\n");
Expand Down Expand Up @@ -207,7 +207,7 @@ fn zero_allocation_decoding() {
mod no_std_custom_types {
// In actual no_std code:
// use alloc::vec::Vec;
use multitrait::{EncodeIntoArray, EncodeIntoBuffer, TryDecodeFrom};
use multi_trait::{EncodeIntoArray, EncodeIntoBuffer, TryDecodeFrom};

/// A custom type that uses only stack encoding
#[derive(Debug, PartialEq)]
Expand All @@ -230,7 +230,7 @@ mod no_std_custom_types {
}

/// Decode from bytes (zero allocation)
pub fn decode_from(bytes: &[u8]) -> Result<(Self, &[u8]), multitrait::Error> {
pub fn decode_from(bytes: &[u8]) -> Result<(Self, &[u8]), multi_trait::Error> {
let (sensor_id, remaining) = u8::try_decode_from(bytes)?;
let (value, remaining) = u16::try_decode_from(remaining)?;
Ok((SensorReading { sensor_id, value }, remaining))
Expand Down
23 changes: 12 additions & 11 deletions src/enc_into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#[cfg(not(feature = "std"))]
use alloc::{vec, vec::Vec};

use unsigned_varint::{decode, encode};
use unsigned_varint::encode;

/// Trait for encoding values into compact varint byte representation.
///
Expand Down Expand Up @@ -37,7 +37,7 @@ use unsigned_varint::{decode, encode};
/// # Examples
///
/// ```rust
/// use multitrait::EncodeInto;
/// use multi_trait::EncodeInto;
///
/// // Small values use minimal space
/// let small = 42u8;
Expand Down Expand Up @@ -72,7 +72,7 @@ pub trait EncodeInto {
/// # Examples
///
/// ```rust
/// use multitrait::EncodeInto;
/// use multi_trait::EncodeInto;
///
/// let value = 300u16;
/// let bytes = value.encode_into();
Expand Down Expand Up @@ -114,16 +114,10 @@ macro_rules! impl_encode_into {
let mut buf = encode::$buffer_fn();

// Encode value into buffer
encode::$encode_fn(*self, &mut buf);

// Find the length efficiently by locating the last byte marker
let len = buf
.iter()
.position(|&b| decode::is_last(b))
.map_or(buf.len(), |pos| pos + 1);
let encoded = encode::$encode_fn(*self, &mut buf);

// Single allocation: slice and convert to Vec
buf[..len].to_vec()
encoded.to_vec()
}
}
)+
Expand All @@ -149,3 +143,10 @@ impl_encode_into! {
u128 => u128_buffer, u128;
usize => usize_buffer, usize;
}

/// Encode a fixed-length byte array as raw bytes (used for BLS share identifiers).
impl<const N: usize> EncodeInto for [u8; N] {
fn encode_into(&self) -> Vec<u8> {
self.as_slice().to_vec()
}
}
10 changes: 5 additions & 5 deletions src/enc_into_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//! ## Basic stack encoding
//!
//! ```rust
//! use multitrait::EncodeIntoArray;
//! use multi_trait::EncodeIntoArray;
//!
//! let (array, len) = 42u8.encode_into_array();
//! assert_eq!(&array[..len], &[42]);
Expand All @@ -35,7 +35,7 @@
//! ## Working with larger values
//!
//! ```rust
//! use multitrait::EncodeIntoArray;
//! use multi_trait::EncodeIntoArray;
//!
//! let (array, len) = 1000u16.encode_into_array();
//! // Varint encoding of 1000 takes 2 bytes
Expand All @@ -48,7 +48,7 @@
//! Each type has a compile-time known maximum encoded size:
//!
//! ```rust
//! use multitrait::EncodeIntoArray;
//! use multi_trait::EncodeIntoArray;
//!
//! // u8 values fit in 2 bytes max
//! assert_eq!(<u8 as EncodeIntoArray>::MAX_ENCODED_SIZE, 2);
Expand Down Expand Up @@ -97,7 +97,7 @@ pub const MAX_VARINT_SIZE: usize = 19;
/// # Examples
///
/// ```rust
/// use multitrait::EncodeIntoArray;
/// use multi_trait::EncodeIntoArray;
///
/// // Encode a value to a stack array
/// let (array, len) = 42u8.encode_into_array();
Expand Down Expand Up @@ -132,7 +132,7 @@ pub trait EncodeIntoArray {
/// # Examples
///
/// ```rust
/// use multitrait::EncodeIntoArray;
/// use multi_trait::EncodeIntoArray;
///
/// let (array, len) = 42u8.encode_into_array();
/// assert_eq!(len, 1);
Expand Down
20 changes: 7 additions & 13 deletions src/enc_into_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
//! ## Single value encoding
//!
//! ```rust
//! use multitrait::EncodeIntoBuffer;
//! use multi_trait::EncodeIntoBuffer;
//!
//! let mut buffer = Vec::new();
//! 42u8.encode_into_buffer(&mut buffer);
Expand All @@ -35,7 +35,7 @@
//! ## Sequential encoding (multiple values)
//!
//! ```rust
//! use multitrait::EncodeIntoBuffer;
//! use multi_trait::EncodeIntoBuffer;
//!
//! let mut buffer = Vec::new();
//! 42u8.encode_into_buffer(&mut buffer);
Expand All @@ -49,7 +49,7 @@
//! ## Buffer reuse
//!
//! ```rust
//! use multitrait::EncodeIntoBuffer;
//! use multi_trait::EncodeIntoBuffer;
//!
//! let mut buffer = Vec::with_capacity(100);
//! for i in 0u8..10 {
Expand Down Expand Up @@ -88,7 +88,7 @@ use unsigned_varint::encode;
/// # Examples
///
/// ```rust
/// use multitrait::EncodeIntoBuffer;
/// use multi_trait::EncodeIntoBuffer;
///
/// // Create a reusable buffer
/// let mut buffer = Vec::with_capacity(64);
Expand Down Expand Up @@ -121,7 +121,7 @@ pub trait EncodeIntoBuffer {
/// # Examples
///
/// ```rust
/// use multitrait::EncodeIntoBuffer;
/// use multi_trait::EncodeIntoBuffer;
///
/// let mut buffer = Vec::new();
/// 42u8.encode_into_buffer(&mut buffer);
Expand Down Expand Up @@ -167,16 +167,10 @@ macro_rules! impl_encode_into_buffer {
let mut buf = encode::$buffer_fn();

// Encode value into temporary buffer
encode::$encode_fn(*self, &mut buf);

// Find the length efficiently by locating the last byte marker
let len = buf
.iter()
.position(|&b| unsigned_varint::decode::is_last(b))
.map_or(buf.len(), |pos| pos + 1);
let encoded = encode::$encode_fn(*self, &mut buf);

// Extend the target buffer with the encoded bytes
buffer.extend_from_slice(&buf[..len]);
buffer.extend_from_slice(encoded);
}
}
)+
Expand Down
Loading
Loading