From d53b8c2d7ea27d33d3877456903347f8ecd23ff1 Mon Sep 17 00:00:00 2001 From: Dominik Werder Date: Tue, 29 Apr 2025 12:05:12 +0200 Subject: [PATCH] Type ByteSizeU32 --- .gitignore | 2 + Cargo.toml | 9 ++++ src/lib.rs | 3 ++ src/serde_bytesize.rs | 120 ++++++++++++++++++++++++++++++++++++++++++ src/serde_dummy.rs | 12 +++++ src/serde_instant.rs | 14 +++++ 6 files changed, 160 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/serde_bytesize.rs create mode 100644 src/serde_dummy.rs create mode 100644 src/serde_instant.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b72444 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/Cargo.lock +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d3a34ea --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "daqbuf-serde-helper" +version = "0.0.1" +authors = ["Dominik Werder "] +edition = "2024" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a80d880 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod serde_bytesize; +pub mod serde_dummy; +pub mod serde_instant; diff --git a/src/serde_bytesize.rs b/src/serde_bytesize.rs new file mode 100644 index 0000000..d3d66b0 --- /dev/null +++ b/src/serde_bytesize.rs @@ -0,0 +1,120 @@ +use serde::Deserialize; +use serde::Deserializer; +use serde::Serialize; +use serde::Serializer; +use serde::de::{self, Visitor}; +use std::fmt; + +pub struct ByteSizeU32(u32); + +pub fn serialize(val: &ByteSizeU32, ser: S) -> Result +where + S: Serializer, +{ + let value = val.0; + let (num, unit) = if value % (1 << 20) == 0 { + (value / (1 << 20), "MB") + } else if value % (1 << 10) == 0 { + (value / (1 << 10), "kB") + } else { + (value, "B") + }; + ser.serialize_str(&format!("{} {}", num, unit)) +} + +pub fn deserialize<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + struct ByteSizeVisitor; + + impl<'de> Visitor<'de> for ByteSizeVisitor { + type Value = ByteSizeU32; + + fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str("a u32 or a string representing a byte size (e.g., '12kB', '4 MB')") + } + + fn visit_u64(self, value: u64) -> Result + where + E: de::Error, + { + Ok(ByteSizeU32(value as u32)) + } + + fn visit_u32(self, value: u32) -> Result + where + E: de::Error, + { + Ok(ByteSizeU32(value)) + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + let val = value.trim(); + let (num, unit) = + val.split_at(val.find(|c: char| !c.is_digit(10)).unwrap_or(val.len())); + let num: u32 = num + .trim() + .parse() + .map_err(|e| E::custom(format!("------------{:?}", e)))?; + let mul = match unit.trim() { + "B" => 1, + "kB" => 1 << 10, + "MB" => 1 << 20, + _ => return Err(E::custom(format!("unknown unit: {}", unit))), + }; + Ok(ByteSizeU32(num * mul)) + } + } + + deserializer.deserialize_any(ByteSizeVisitor) +} + +impl Serialize for ByteSizeU32 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serialize(self, serializer) + } +} + +impl<'de> Deserialize<'de> for ByteSizeU32 { + fn deserialize(de: D) -> Result + where + D: Deserializer<'de>, + { + deserialize(de) + } +} + +#[test] +fn test_00() { + #[derive(serde::Serialize, serde::Deserialize)] + struct A { + #[serde(with = "self")] + filesize: ByteSizeU32, + } + let a = A { + filesize: ByteSizeU32(1024 * 1024 * 12), + }; + let s = serde_json::to_string(&a).unwrap(); + assert_eq!(s, r#"{"filesize":"12 MB"}"#); +} + +#[test] +fn test_01() { + let a: ByteSizeU32 = serde_json::from_str("123").unwrap(); + assert_eq!(a.0, 123); + let a: ByteSizeU32 = serde_json::from_str("\"17kB\"").unwrap(); + assert_eq!(a.0, 1024 * 17); + let a: ByteSizeU32 = serde_json::from_str("\"17 kB\"").unwrap(); + assert_eq!(a.0, 1024 * 17); + let a: ByteSizeU32 = serde_json::from_str("\"17 kB \"").unwrap(); + assert_eq!(a.0, 1024 * 17); + let a: ByteSizeU32 = serde_json::from_str("\" 83 MB\"").unwrap(); + assert_eq!(a.0, 1024 * 1024 * 83); +} diff --git a/src/serde_dummy.rs b/src/serde_dummy.rs new file mode 100644 index 0000000..ffbc0eb --- /dev/null +++ b/src/serde_dummy.rs @@ -0,0 +1,12 @@ +#[allow(non_snake_case)] +pub mod serde_dummy { + use serde::Serializer; + + #[allow(unused)] + pub fn serialize(val: &T, ser: S) -> Result + where + S: Serializer, + { + ser.serialize_str("DUMMY") + } +} diff --git a/src/serde_instant.rs b/src/serde_instant.rs new file mode 100644 index 0000000..384b553 --- /dev/null +++ b/src/serde_instant.rs @@ -0,0 +1,14 @@ +#[allow(non_snake_case)] +pub mod serde_Instant_elapsed_ms { + use serde::Serializer; + use std::time::Instant; + + #[allow(unused)] + pub fn serialize(val: &Instant, ser: S) -> Result + where + S: Serializer, + { + let dur = val.elapsed(); + ser.serialize_u64(dur.as_secs() * 1000 + dur.subsec_millis() as u64) + } +}