From 1f261cede30701c9c7111b8bd4b504ac3bf7cdbf Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sat, 16 Oct 2021 14:49:18 +0200 Subject: [PATCH] Added support for atomic integers --- Cargo.toml | 3 +- src/features/atomic.rs | 137 +++++++++++++++++++++++++++++++++++++++++ src/features/mod.rs | 5 ++ tests/alloc.rs | 14 ++++- tests/atomic.rs | 49 +++++++++++++++ tests/std.rs | 21 +++---- tests/utils.rs | 52 +++++++++++----- 7 files changed, 253 insertions(+), 28 deletions(-) create mode 100644 src/features/atomic.rs create mode 100644 tests/atomic.rs diff --git a/Cargo.toml b/Cargo.toml index 2fc5727..b195863 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,10 @@ description = "A binary serialization / deserialization strategy for transformin edition = "2018" [features] -default = ["std", "derive"] +default = ["std", "derive", "atomic"] std = ["alloc"] alloc = [] +atomic = [] derive = ["bincode_derive"] [dependencies] diff --git a/src/features/atomic.rs b/src/features/atomic.rs new file mode 100644 index 0000000..dbbe2a0 --- /dev/null +++ b/src/features/atomic.rs @@ -0,0 +1,137 @@ +use crate::{de::Decodable, enc::Encodeable}; +use core::sync::atomic::{ + AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, + AtomicU64, AtomicU8, AtomicUsize, Ordering, +}; + +impl Encodeable for AtomicBool { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicBool { + fn decode(decoder: D) -> Result { + Ok(AtomicBool::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicU8 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicU8 { + fn decode(decoder: D) -> Result { + Ok(AtomicU8::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicU16 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicU16 { + fn decode(decoder: D) -> Result { + Ok(AtomicU16::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicU32 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicU32 { + fn decode(decoder: D) -> Result { + Ok(AtomicU32::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicU64 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicU64 { + fn decode(decoder: D) -> Result { + Ok(AtomicU64::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicUsize { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicUsize { + fn decode(decoder: D) -> Result { + Ok(AtomicUsize::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicI8 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicI8 { + fn decode(decoder: D) -> Result { + Ok(AtomicI8::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicI16 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicI16 { + fn decode(decoder: D) -> Result { + Ok(AtomicI16::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicI32 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicI32 { + fn decode(decoder: D) -> Result { + Ok(AtomicI32::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicI64 { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicI64 { + fn decode(decoder: D) -> Result { + Ok(AtomicI64::new(Decodable::decode(decoder)?)) + } +} + +impl Encodeable for AtomicIsize { + fn encode(&self, encoder: E) -> Result<(), crate::error::EncodeError> { + self.load(Ordering::SeqCst).encode(encoder) + } +} + +impl Decodable for AtomicIsize { + fn decode(decoder: D) -> Result { + Ok(AtomicIsize::new(Decodable::decode(decoder)?)) + } +} diff --git a/src/features/mod.rs b/src/features/mod.rs index 25ba517..ab1b309 100644 --- a/src/features/mod.rs +++ b/src/features/mod.rs @@ -1,3 +1,8 @@ +#[cfg(feature = "atomic")] +mod atomic; +#[cfg(feature = "atomic")] +pub use self::atomic::*; + #[cfg(feature = "alloc")] mod impl_alloc; #[cfg(feature = "alloc")] diff --git a/tests/alloc.rs b/tests/alloc.rs index 211284a..5f561b8 100644 --- a/tests/alloc.rs +++ b/tests/alloc.rs @@ -8,7 +8,7 @@ use alloc::borrow::Cow; use alloc::collections::*; use alloc::rc::Rc; use alloc::sync::Arc; -use utils::the_same; +use utils::{the_same, the_same_with_comparer}; struct Foo { pub a: u32, @@ -55,6 +55,18 @@ fn test_alloc_commons() { the_same(Cow::::Borrowed(&5)); the_same(Rc::::new(5)); the_same(Arc::::new(5)); + the_same_with_comparer( + { + let mut map = BinaryHeap::::new(); + map.push(1); + map.push(2); + map.push(3); + map.push(4); + map.push(5); + map + }, + |a, b| a.into_iter().collect::>() == b.into_iter().collect::>(), + ); the_same({ let mut map = BTreeMap::::new(); map.insert(5, -5); diff --git a/tests/atomic.rs b/tests/atomic.rs new file mode 100644 index 0000000..41e53e8 --- /dev/null +++ b/tests/atomic.rs @@ -0,0 +1,49 @@ +#![cfg(feature = "atomic")] + +mod utils; + +use core::sync::atomic::{ + AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, + AtomicU64, AtomicU8, AtomicUsize, Ordering, +}; +use utils::the_same_with_comparer; + +#[test] +fn test_atomic_commons() { + the_same_with_comparer(AtomicBool::new(true), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicBool::new(false), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicU8::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicU16::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicU32::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicU64::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicUsize::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicI8::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicI16::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicI32::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicI64::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); + the_same_with_comparer(AtomicIsize::new(0), |a, b| { + a.load(Ordering::SeqCst) == b.load(Ordering::SeqCst) + }); +} diff --git a/tests/std.rs b/tests/std.rs index d94fe0a..b804656 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -11,6 +11,8 @@ use std::{ }; use utils::the_same; +use crate::utils::the_same_with_comparer; + struct Foo { pub a: u32, pub b: u32, @@ -79,7 +81,14 @@ fn test_std_commons() { 0, 0, ))); + the_same_with_comparer(Mutex::new("Hello world".to_string()), |a, b| { + &*a.lock().unwrap() == &*b.lock().unwrap() + }); + the_same_with_comparer(RwLock::new("Hello world".to_string()), |a, b| { + &*a.read().unwrap() == &*b.read().unwrap() + }); + // Borrowed values let config = bincode::config::Default; let mut buffer = [0u8; 1024]; @@ -89,18 +98,6 @@ fn test_std_commons() { let decoded: &CStr = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); assert_eq!(cstr, decoded); - // Mutex - let mutex = Mutex::new("Hello world".to_string()); - let len = bincode::encode_into_slice_with_config(&mutex, &mut buffer, config).unwrap(); - let decoded: Mutex = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); - assert_eq!(&*mutex.lock().unwrap(), &*decoded.lock().unwrap()); - - // RwLock - let rwlock = RwLock::new("Hello world".to_string()); - let len = bincode::encode_into_slice_with_config(&rwlock, &mut buffer, config).unwrap(); - let decoded: RwLock = bincode::decode_with_config(&mut buffer[..len], config).unwrap(); - assert_eq!(&*rwlock.read().unwrap(), &*decoded.read().unwrap()); - // Path let path = Path::new("C:/Program Files/Foo"); let len = bincode::encode_into_slice_with_config(path, &mut buffer, config).unwrap(); diff --git a/tests/utils.rs b/tests/utils.rs index 2823a6a..3aa4e79 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -1,13 +1,14 @@ use bincode::config::{self, Config}; use core::fmt::Debug; -fn the_same_with_config(element: V, config: C) +fn the_same_with_config(element: &V, config: C, cmp: CMP) where - V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, + V: bincode::enc::Encodeable + bincode::de::Decodable + Debug + 'static, C: Config, + CMP: Fn(&V, &V) -> bool, { let mut buffer = [0u8; 1024]; - let len = bincode::encode_into_slice_with_config(element.clone(), &mut buffer, config).unwrap(); + let len = bincode::encode_into_slice_with_config(&element, &mut buffer, config).unwrap(); println!( "{:?}: {:?} ({:?})", element, @@ -16,68 +17,91 @@ where ); let decoded: V = bincode::decode_with_config(&mut buffer, config).unwrap(); - assert_eq!(element, decoded); + assert!( + cmp(&element, &decoded), + "Comparison failed\nDecoded: {:?}\nExpected: {:?}\nBytes: {:?}", + decoded, + element, + &buffer[..len], + ); } -pub fn the_same(element: V) +pub fn the_same_with_comparer(element: V, cmp: CMP) where - V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + Clone + 'static, + V: bincode::enc::Encodeable + bincode::de::Decodable + Debug + 'static, + CMP: Fn(&V, &V) -> bool, { // A matrix of each different config option possible the_same_with_config( - element.clone(), + &element, config::Default .with_little_endian() .with_fixed_int_encoding() .skip_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_big_endian() .with_fixed_int_encoding() .skip_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_little_endian() .with_variable_int_encoding() .skip_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_big_endian() .with_variable_int_encoding() .skip_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_little_endian() .with_fixed_int_encoding() .write_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_big_endian() .with_fixed_int_encoding() .write_fixed_array_length(), + &cmp, ); the_same_with_config( - element.clone(), + &element, config::Default .with_little_endian() .with_variable_int_encoding() .write_fixed_array_length(), + &cmp, ); the_same_with_config( - element, + &element, config::Default .with_big_endian() .with_variable_int_encoding() .write_fixed_array_length(), + &cmp, ); } + +#[allow(dead_code)] // This is not used in every test +pub fn the_same(element: V) +where + V: bincode::enc::Encodeable + bincode::de::Decodable + PartialEq + Debug + 'static, +{ + the_same_with_comparer(element, |a, b| a == b); +}