From 129d68a676c9dacb97023aa9c87ae7f248cfeff3 Mon Sep 17 00:00:00 2001 From: Pi Lanningham Date: Thu, 23 Jan 2025 11:13:17 -0500 Subject: [PATCH] Add minicbor support (#97) --- Cargo.toml | 20 +++---- benches/bench.rs | 11 ++++ src/bench_minicbor.rs | 34 ++++++++++++ src/datasets/log/mod.rs | 15 +++++ src/datasets/mesh/mod.rs | 11 ++++ src/datasets/minecraft_savedata/mod.rs | 76 ++++++++++++++++++++++++++ src/lib.rs | 2 + 7 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 src/bench_minicbor.rs diff --git a/Cargo.toml b/Cargo.toml index 17c20db..591735f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,10 @@ ciborium = { version = "=0.2.2", optional = true } databuf = { version = "=0.5.0", optional = true } dlhn = { version = "=0.1.7", optional = true } flatbuffers = { version = "=24.12.23", optional = true } +minicbor = { version = "=0.25.1", optional = true, features = [ + "alloc", + "derive", +] } msgpacker = { version = "=0.4.5", optional = true } nachricht-serde = { version = "=0.4.0", optional = true } nanoserde = { version = "=0.1.37", optional = true } @@ -74,9 +78,7 @@ ron = { version = "=0.8.1", optional = true } savefile = { version = "=0.18.5", optional = true } savefile-derive = { version = "=0.18.5", optional = true } serde_bare = { version = "=0.5.0", optional = true } -serde-brief = { version = "=0.1.0", features = [ - "std", -], optional = true } +serde-brief = { version = "=0.1.0", features = ["std"], optional = true } serde_cbor = { version = "=0.11.2", optional = true } serde_json = { version = "=1.0.134", features = [ "float_roundtrip", @@ -94,10 +96,7 @@ serde = { version = "=1.0.216", features = ["derive"] } zstd = "=0.13.2" [features] -default = [ - "default-encoding-set", - "measure-compression", -] +default = ["default-encoding-set", "measure-compression"] default-encoding-set = [ "bilrost", "bincode1", @@ -110,6 +109,7 @@ default-encoding-set = [ "databuf", "dlhn", "flatbuffers", + "minicbor", "msgpacker", "nachricht-serde", "nanoserde", @@ -138,11 +138,7 @@ savefile = ["dep:savefile", "dep:savefile-derive"] scale = ["dep:parity-scale-codec", "dep:parity-scale-codec-derive"] # Enable these features to regenerate generated files rather than using the committed versions. -regenerate = [ - "regenerate-capnp", - "regenerate-flatbuffers", - "regenerate-prost", -] +regenerate = ["regenerate-capnp", "regenerate-flatbuffers", "regenerate-prost"] regenerate-capnp = ["dep:capnpc"] regenerate-flatbuffers = ["dep:flatc-rust"] regenerate-prost = ["dep:prost-build"] diff --git a/benches/bench.rs b/benches/bench.rs index 1d4de32..5d55a89 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -23,6 +23,8 @@ use rust_serialization_benchmark::bench_databuf; use rust_serialization_benchmark::bench_dlhn; #[cfg(feature = "flatbuffers")] use rust_serialization_benchmark::bench_flatbuffers; +#[cfg(feature = "minicbor")] +use rust_serialization_benchmark::bench_minicbor; #[cfg(feature = "msgpacker")] use rust_serialization_benchmark::bench_msgpacker; #[cfg(feature = "nachricht-serde")] @@ -149,6 +151,9 @@ fn bench_log(c: &mut Criterion) { }, ); + #[cfg(feature = "minicbor")] + bench_minicbor::bench(BENCH, c, &data); + #[cfg(feature = "msgpacker")] bench_msgpacker::bench(BENCH, c, &data); @@ -323,6 +328,9 @@ fn bench_mesh(c: &mut Criterion) { }, ); + #[cfg(feature = "minicbor")] + bench_minicbor::bench(BENCH, c, &data); + #[cfg(feature = "msgpacker")] bench_msgpacker::bench(BENCH, c, &data); @@ -491,6 +499,9 @@ fn bench_minecraft_savedata(c: &mut Criterion) { }, ); + #[cfg(feature = "minicbor")] + bench_minicbor::bench(BENCH, c, &data); + #[cfg(feature = "msgpacker")] bench_msgpacker::bench(BENCH, c, &data); diff --git a/src/bench_minicbor.rs b/src/bench_minicbor.rs new file mode 100644 index 0000000..c035ecb --- /dev/null +++ b/src/bench_minicbor.rs @@ -0,0 +1,34 @@ +use criterion::{black_box, Criterion}; +use minicbor::{Decode, Encode}; + +pub fn bench(name: &'static str, c: &mut Criterion, data: &T) +where + T: Encode<()> + for<'de> Decode<'de, ()> + PartialEq, +{ + const BUFFER_LEN: usize = 50_000_000; + + let mut group = c.benchmark_group(format!("{}/minicbor", name)); + + let mut serialize_buffer = vec![0; BUFFER_LEN]; + group.bench_function("serialize", |b| { + b.iter(|| { + minicbor::encode(black_box(data), black_box(serialize_buffer.as_mut_slice())).unwrap(); + black_box(()); + }) + }); + + let mut deserialize_buffer = Vec::new(); + minicbor::encode(&data, &mut deserialize_buffer).unwrap(); + + group.bench_function("deserialize", |b| { + b.iter(|| { + black_box(minicbor::decode::<'_, T>(black_box(&deserialize_buffer)).unwrap()); + }) + }); + + crate::bench_size(name, "minicbor", deserialize_buffer.as_slice()); + + assert!(minicbor::decode::(&deserialize_buffer).unwrap() == *data); + + group.finish(); +} diff --git a/src/datasets/log/mod.rs b/src/datasets/log/mod.rs index bfad34b..3c9a459 100644 --- a/src/datasets/log/mod.rs +++ b/src/datasets/log/mod.rs @@ -36,6 +36,7 @@ use crate::Generate; derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -56,9 +57,13 @@ use crate::Generate; #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Address { #[cfg_attr(feature = "wiring", fixed)] + #[cfg_attr(feature = "minicbor", n(0))] pub x0: u8, + #[cfg_attr(feature = "minicbor", n(1))] pub x1: u8, + #[cfg_attr(feature = "minicbor", n(2))] pub x2: u8, + #[cfg_attr(feature = "minicbor", n(3))] pub x3: u8, } @@ -187,6 +192,7 @@ impl From for Address { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -206,13 +212,20 @@ impl From for Address { #[cfg_attr(feature = "nanoserde", derive(nanoserde::SerBin, nanoserde::DeBin))] #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Log { + #[cfg_attr(feature = "minicbor", n(0))] pub address: Address, + #[cfg_attr(feature = "minicbor", b(1))] pub identity: String, + #[cfg_attr(feature = "minicbor", b(2))] pub userid: String, + #[cfg_attr(feature = "minicbor", b(3))] pub date: String, + #[cfg_attr(feature = "minicbor", b(4))] pub request: String, #[cfg_attr(feature = "wiring", fixed)] + #[cfg_attr(feature = "minicbor", n(5))] pub code: u16, + #[cfg_attr(feature = "minicbor", n(6))] pub size: u64, } @@ -364,6 +377,7 @@ impl From for Log { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -384,6 +398,7 @@ impl From for Log { #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Logs { #[cfg_attr(feature = "bilrost", bilrost(encoding(packed)))] + #[cfg_attr(feature = "minicbor", n(0))] pub logs: Vec, } diff --git a/src/datasets/mesh/mod.rs b/src/datasets/mesh/mod.rs index d5a5f70..0151059 100644 --- a/src/datasets/mesh/mod.rs +++ b/src/datasets/mesh/mod.rs @@ -37,6 +37,7 @@ use crate::Generate; derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -57,8 +58,11 @@ use crate::Generate; #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Vector3 { #[cfg_attr(feature = "wiring", fixed)] + #[cfg_attr(feature = "minicbor", n(0))] pub x: f32, + #[cfg_attr(feature = "minicbor", n(1))] pub y: f32, + #[cfg_attr(feature = "minicbor", n(2))] pub z: f32, } @@ -127,6 +131,7 @@ impl From for Vector3 { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -147,9 +152,13 @@ impl From for Vector3 { #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Triangle { #[cfg_attr(feature = "wiring", fixed)] + #[cfg_attr(feature = "minicbor", n(0))] pub v0: Vector3, + #[cfg_attr(feature = "minicbor", n(1))] pub v1: Vector3, + #[cfg_attr(feature = "minicbor", n(2))] pub v2: Vector3, + #[cfg_attr(feature = "minicbor", n(3))] pub normal: Vector3, } @@ -228,6 +237,7 @@ impl From for Triangle { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -248,6 +258,7 @@ impl From for Triangle { #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Mesh { #[cfg_attr(feature = "bilrost", bilrost(encoding(packed)))] + #[cfg_attr(feature = "minicbor", n(0))] pub triangles: Vec, } diff --git a/src/datasets/minecraft_savedata/mod.rs b/src/datasets/minecraft_savedata/mod.rs index 201746b..ea13767 100644 --- a/src/datasets/minecraft_savedata/mod.rs +++ b/src/datasets/minecraft_savedata/mod.rs @@ -39,6 +39,7 @@ use crate::{generate_vec, Generate}; derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -60,12 +61,16 @@ use crate::{generate_vec, Generate}; #[repr(u8)] pub enum GameType { #[cfg_attr(feature = "bilrost", bilrost(0))] + #[cfg_attr(feature = "minicbor", n(0))] Survival, #[cfg_attr(feature = "bilrost", bilrost(1))] + #[cfg_attr(feature = "minicbor", n(1))] Creative, #[cfg_attr(feature = "bilrost", bilrost(2))] + #[cfg_attr(feature = "minicbor", n(2))] Adventure, #[cfg_attr(feature = "bilrost", bilrost(3))] + #[cfg_attr(feature = "minicbor", n(3))] Spectator, } @@ -144,6 +149,7 @@ impl From for GameType { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -165,9 +171,12 @@ impl From for GameType { pub struct Item { #[cfg_attr(feature = "bilrost", bilrost(encoding(varint)))] #[cfg_attr(feature = "wiring", fixed(2))] + #[cfg_attr(feature = "minicbor", n(0))] pub count: i8, #[cfg_attr(feature = "bilrost", bilrost(encoding(varint)))] + #[cfg_attr(feature = "minicbor", n(1))] pub slot: u8, + #[cfg_attr(feature = "minicbor", b(2))] pub id: String, } @@ -259,6 +268,7 @@ impl From for Item { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -279,12 +289,19 @@ impl From for Item { #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Abilities { #[cfg_attr(feature = "wiring", fixed)] + #[cfg_attr(feature = "minicbor", n(0))] pub walk_speed: f32, + #[cfg_attr(feature = "minicbor", n(1))] pub fly_speed: f32, + #[cfg_attr(feature = "minicbor", n(2))] pub may_fly: bool, + #[cfg_attr(feature = "minicbor", n(3))] pub flying: bool, + #[cfg_attr(feature = "minicbor", n(4))] pub invulnerable: bool, + #[cfg_attr(feature = "minicbor", n(5))] pub may_build: bool, + #[cfg_attr(feature = "minicbor", n(6))] pub instabuild: bool, } @@ -377,6 +394,7 @@ impl From for Abilities { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -396,24 +414,40 @@ impl From for Abilities { #[cfg_attr(feature = "nanoserde", derive(nanoserde::SerBin, nanoserde::DeBin))] #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Entity { + #[cfg_attr(feature = "minicbor", b(0))] pub id: String, #[cfg_attr(feature = "wiring", fixed(11))] + #[cfg_attr(feature = "minicbor", n(1))] pub pos: (f64, f64, f64), + #[cfg_attr(feature = "minicbor", n(2))] pub motion: (f64, f64, f64), + #[cfg_attr(feature = "minicbor", n(3))] pub rotation: (f32, f32), + #[cfg_attr(feature = "minicbor", n(4))] pub fall_distance: f32, + #[cfg_attr(feature = "minicbor", n(5))] pub fire: u16, + #[cfg_attr(feature = "minicbor", n(6))] pub air: u16, + #[cfg_attr(feature = "minicbor", n(7))] pub on_ground: bool, + #[cfg_attr(feature = "minicbor", n(8))] pub no_gravity: bool, + #[cfg_attr(feature = "minicbor", n(9))] pub invulnerable: bool, + #[cfg_attr(feature = "minicbor", n(10))] pub portal_cooldown: i32, #[cfg_attr(feature = "bilrost", bilrost(encoding = "packed"))] + #[cfg_attr(feature = "minicbor", n(11))] pub uuid: [u32; 4], + #[cfg_attr(feature = "minicbor", n(12))] pub custom_name: Option, #[cfg_attr(feature = "wiring", fixed)] + #[cfg_attr(feature = "minicbor", n(13))] pub custom_name_visible: bool, + #[cfg_attr(feature = "minicbor", n(14))] pub silent: bool, + #[cfg_attr(feature = "minicbor", n(15))] pub glowing: bool, } @@ -630,6 +664,7 @@ impl From for Entity { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -650,17 +685,27 @@ impl From for Entity { #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct RecipeBook { #[cfg_attr(feature = "bilrost", bilrost(encoding(packed)))] + #[cfg_attr(feature = "minicbor", n(0))] pub recipes: Vec, #[cfg_attr(feature = "bilrost", bilrost(encoding(packed)))] + #[cfg_attr(feature = "minicbor", n(1))] pub to_be_displayed: Vec, #[cfg_attr(feature = "wiring", fixed)] + #[cfg_attr(feature = "minicbor", n(2))] pub is_filtering_craftable: bool, + #[cfg_attr(feature = "minicbor", n(3))] pub is_gui_open: bool, + #[cfg_attr(feature = "minicbor", n(4))] pub is_furnace_filtering_craftable: bool, + #[cfg_attr(feature = "minicbor", n(5))] pub is_furnace_gui_open: bool, + #[cfg_attr(feature = "minicbor", n(6))] pub is_blasting_furnace_filtering_craftable: bool, + #[cfg_attr(feature = "minicbor", n(7))] pub is_blasting_furnace_gui_open: bool, + #[cfg_attr(feature = "minicbor", n(8))] pub is_smoker_filtering_craftable: bool, + #[cfg_attr(feature = "minicbor", n(9))] pub is_smoker_gui_open: bool, } @@ -822,6 +867,7 @@ impl From for RecipeBook { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -842,36 +888,64 @@ impl From for RecipeBook { #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Player { #[cfg_attr(feature = "wiring", fixed(3))] + #[cfg_attr(feature = "minicbor", n(0))] pub game_type: GameType, + #[cfg_attr(feature = "minicbor", n(1))] pub previous_game_type: GameType, + #[cfg_attr(feature = "minicbor", n(2))] pub score: i64, + #[cfg_attr(feature = "minicbor", b(3))] pub dimension: String, + #[cfg_attr(feature = "minicbor", b(4))] pub selected_item_slot: u32, + #[cfg_attr(feature = "minicbor", n(5))] pub selected_item: Item, + #[cfg_attr(feature = "minicbor", b(6))] pub spawn_dimension: Option, #[cfg_attr(feature = "wiring", fixed(3))] + #[cfg_attr(feature = "minicbor", n(7))] pub spawn_x: i64, + #[cfg_attr(feature = "minicbor", n(8))] pub spawn_y: i64, + #[cfg_attr(feature = "minicbor", n(9))] pub spawn_z: i64, + #[cfg_attr(feature = "minicbor", n(10))] pub spawn_forced: Option, #[cfg_attr(feature = "wiring", fixed(8))] + #[cfg_attr(feature = "minicbor", n(11))] pub sleep_timer: u16, + #[cfg_attr(feature = "minicbor", n(12))] pub food_exhaustion_level: f32, + #[cfg_attr(feature = "minicbor", n(13))] pub food_saturation_level: f32, + #[cfg_attr(feature = "minicbor", n(14))] pub food_tick_timer: u32, + #[cfg_attr(feature = "minicbor", n(15))] pub xp_level: u32, + #[cfg_attr(feature = "minicbor", n(16))] pub xp_p: f32, + #[cfg_attr(feature = "minicbor", n(17))] pub xp_total: i32, + #[cfg_attr(feature = "minicbor", n(18))] pub xp_seed: i32, + #[cfg_attr(feature = "minicbor", n(19))] pub inventory: Vec, + #[cfg_attr(feature = "minicbor", n(20))] pub ender_items: Vec, + #[cfg_attr(feature = "minicbor", n(21))] pub abilities: Abilities, + #[cfg_attr(feature = "minicbor", n(22))] pub entered_nether_position: Option<(f64, f64, f64)>, #[cfg_attr(feature = "bilrost", bilrost(encoding = "(packed, general)"))] + #[cfg_attr(feature = "minicbor", n(23))] pub root_vehicle: Option<([u32; 4], Entity)>, + #[cfg_attr(feature = "minicbor", n(24))] pub shoulder_entity_left: Option, + #[cfg_attr(feature = "minicbor", n(25))] pub shoulder_entity_right: Option, + #[cfg_attr(feature = "minicbor", n(26))] pub seen_credits: bool, + #[cfg_attr(feature = "minicbor", n(27))] pub recipe_book: RecipeBook, } @@ -1210,6 +1284,7 @@ impl From for Player { derive(borsh::BorshSerialize, borsh::BorshDeserialize) )] #[cfg_attr(feature = "databuf", derive(databuf::Encode, databuf::Decode))] +#[cfg_attr(feature = "minicbor", derive(minicbor::Encode, minicbor::Decode))] #[cfg_attr(feature = "msgpacker", derive(msgpacker::MsgPacker))] #[cfg_attr( feature = "rkyv", @@ -1230,6 +1305,7 @@ impl From for Player { #[cfg_attr(feature = "wiring", derive(Wiring, Unwiring))] pub struct Players { #[cfg_attr(feature = "bilrost", bilrost(encoding(packed)))] + #[cfg_attr(feature = "minicbor", n(0))] pub players: Vec, } diff --git a/src/lib.rs b/src/lib.rs index dca32e0..9f15f84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,8 @@ pub mod bench_databuf; pub mod bench_dlhn; #[cfg(feature = "flatbuffers")] pub mod bench_flatbuffers; +#[cfg(feature = "minicbor")] +pub mod bench_minicbor; #[cfg(feature = "msgpacker")] pub mod bench_msgpacker; #[cfg(feature = "nachricht-serde")]