From 25403e61ed1b8d046d445dcc39cfdf43502428f3 Mon Sep 17 00:00:00 2001 From: Rob Walker Date: Sat, 17 Aug 2019 11:11:59 -0700 Subject: [PATCH] add fixed_buf (#5546) --- Cargo.lock | 9 +++ Cargo.toml | 1 + utils/fixed_buf/.gitignore | 2 + utils/fixed_buf/Cargo.toml | 19 +++++ utils/fixed_buf/src/lib.rs | 142 +++++++++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+) create mode 100644 utils/fixed_buf/.gitignore create mode 100644 utils/fixed_buf/Cargo.toml create mode 100644 utils/fixed_buf/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index af522e99a1..cc11bb7a43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3366,6 +3366,15 @@ dependencies = [ "solana-sdk 0.18.0-pre1", ] +[[package]] +name = "solana-fixed-buf" +version = "0.18.0-pre1" +dependencies = [ + "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "solana-genesis" version = "0.18.0-pre1" diff --git a/Cargo.toml b/Cargo.toml index f4a7a58ba6..5b51252b2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ members = [ "sdk-c", "upload-perf", "validator-info", + "utils/fixed_buf", "vote-signer", "wallet", ] diff --git a/utils/fixed_buf/.gitignore b/utils/fixed_buf/.gitignore new file mode 100644 index 0000000000..5404b132db --- /dev/null +++ b/utils/fixed_buf/.gitignore @@ -0,0 +1,2 @@ +/target/ +/farf/ diff --git a/utils/fixed_buf/Cargo.toml b/utils/fixed_buf/Cargo.toml new file mode 100644 index 0000000000..793480debb --- /dev/null +++ b/utils/fixed_buf/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "solana-fixed-buf" +version = "0.18.0-pre1" +description = "A fixed-size byte array that supports bincode serde" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +license = "Apache-2.0" +homepage = "https://solana.com/" +edition = "2018" + +[dependencies] +bincode = "1.1.4" +serde = "1.0.98" + +[lib] +name = "solana_fixed_buf" + +[dev-dependencies] +serde_derive = "1.0.98" diff --git a/utils/fixed_buf/src/lib.rs b/utils/fixed_buf/src/lib.rs new file mode 100644 index 0000000000..4903a68cc5 --- /dev/null +++ b/utils/fixed_buf/src/lib.rs @@ -0,0 +1,142 @@ +//! ser- and deser-ialize-able, fixed-size bufs + +#[macro_export] +macro_rules! fixed_buf { + ($name:ident, $size:expr) => { + fixed_buf!($name, $size, 12); + }; + ($name:ident, $size:expr, $max_print: expr) => { + pub struct $name { + _inner: [u8; $size], + } + + impl Default for $name { + fn default() -> Self { + $name { _inner: [0; $size] } + } + } + + impl PartialEq for $name { + fn eq(&self, other: &Self) -> bool { + self.iter().zip(other.iter()).all(|(me, other)| me == other) + } + } + impl Eq for $name {} + + impl std::ops::Deref for $name { + type Target = [u8; $size]; + fn deref(&self) -> &Self::Target { + &self._inner + } + } + + impl std::ops::DerefMut for $name { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self._inner + } + } + + impl std::fmt::Debug for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "[{}", self[0])?; + for i in 1..self.len().min($max_print) { + write!(f, ", {}", self[i])?; + } + if $max_print < self.len() { + write!(f, ", ...")?; + } + write!(f, "]") + } + } + + impl<'de> serde::Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct Visitor; + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str(stringify!($name)) + } + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: serde::de::Error, + { + if bytes.len() != $size { + Err(serde::de::Error::invalid_length( + bytes.len(), + &stringify!($size), + ))? + } + let mut buf = $name::default(); + buf.copy_from_slice(bytes); + + Ok(buf) + } + } + deserializer.deserialize_bytes(Visitor) + } + } + + impl serde::ser::Serialize for $name { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::ser::Serializer, + { + serializer.serialize_bytes(&self._inner) + } + } + }; +} + +#[cfg(test)] +mod test { + use serde_derive::{Deserialize, Serialize}; + + fixed_buf!(BufMath, 33); + + #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)] + pub struct Foo { + pub foo: u64, + pub buf: BufMath, + } + + fixed_buf!(Buf34, 34, 35); // print even more than is present! + + #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)] + pub struct Foo34 { + pub foo: u64, + pub buf: Buf34, + } + + #[test] + fn test() { + let mut foo = Foo { + foo: 33, + ..Foo::default() + }; + foo.buf[1] = 127; + let ser = bincode::serialize(&foo).unwrap(); + assert_eq!(bincode::deserialize::(&ser).unwrap(), foo); + + assert_eq!( + format!("{:?}", foo), + "Foo { foo: 33, buf: [0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...] }" + ); + + let mut foo = Foo34 { + foo: 34, + ..Foo34::default() + }; + foo.buf[1] = 128; + let ser = bincode::serialize(&foo).unwrap(); + assert_eq!(bincode::deserialize::(&ser).unwrap(), foo); + + assert!(bincode::deserialize::(&ser).is_err()); + + assert_eq!(format!("{:?}", foo), "Foo34 { foo: 34, buf: [0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }"); + } +}