use crate::error::{CRDTError, CRDTResult};
use crate::memory::MemoryConfig;
use crate::traits::{BoundedCRDT, CRDT, RealTimeCRDT};
#[cfg(feature = "hardware-atomic")]
use core::cell::UnsafeCell;
#[cfg(feature = "hardware-atomic")]
use core::sync::atomic::{AtomicUsize, Ordering};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug)]
pub struct GSet<T, C: MemoryConfig, const CAPACITY: usize = 16> {
#[cfg(not(feature = "hardware-atomic"))]
elements: [Option<T>; CAPACITY],
#[cfg(not(feature = "hardware-atomic"))]
count: usize,
#[cfg(feature = "hardware-atomic")]
elements: UnsafeCell<[Option<T>; CAPACITY]>,
#[cfg(feature = "hardware-atomic")]
count: AtomicUsize,
_phantom: core::marker::PhantomData<C>,
}
#[cfg(feature = "hardware-atomic")]
unsafe impl<T, C: MemoryConfig> Sync for GSet<T, C>
where
T: Send,
C: Send + Sync,
{
}
impl<T, C: MemoryConfig, const CAPACITY: usize> Clone for GSet<T, C, CAPACITY>
where
T: Clone,
{
fn clone(&self) -> Self {
#[cfg(not(feature = "hardware-atomic"))]
{
Self {
elements: self.elements.clone(),
count: self.count,
_phantom: core::marker::PhantomData,
}
}
#[cfg(feature = "hardware-atomic")]
{
let cloned_elements = unsafe { (*self.elements.get()).clone() };
Self {
elements: UnsafeCell::new(cloned_elements),
count: AtomicUsize::new(self.count.load(Ordering::Relaxed)),
_phantom: core::marker::PhantomData,
}
}
}
}
impl<T, C: MemoryConfig, const CAPACITY: usize> GSet<T, C, CAPACITY>
where
T: Clone + PartialEq,
{
pub fn with_capacity() -> Self {
#[cfg(not(feature = "hardware-atomic"))]
{
Self {
elements: [const { None }; CAPACITY],
count: 0,
_phantom: core::marker::PhantomData,
}
}
#[cfg(feature = "hardware-atomic")]
{
Self {
elements: UnsafeCell::new([const { None }; CAPACITY]),
count: AtomicUsize::new(0),
_phantom: core::marker::PhantomData,
}
}
}
}
impl<T, C: MemoryConfig> GSet<T, C, 16>
where
T: Clone + PartialEq,
{
pub fn new() -> Self {
Self::with_capacity()
}
}
impl<T, C: MemoryConfig, const CAPACITY: usize> GSet<T, C, CAPACITY>
where
T: Clone + PartialEq,
{
#[cfg(not(feature = "hardware-atomic"))]
pub fn insert(&mut self, element: T) -> CRDTResult<bool> {
for existing in self.elements.iter().take(self.count) {
if let Some(existing_element) = existing {
if *existing_element == element {
return Ok(false); }
}
}
if self.count >= CAPACITY {
return Err(CRDTError::BufferOverflow);
}
self.elements[self.count] = Some(element);
self.count += 1;
Ok(true)
}
#[cfg(feature = "hardware-atomic")]
pub fn insert(&self, element: T) -> CRDTResult<bool> {
loop {
let current_count = self.count.load(Ordering::Relaxed);
let elements_ptr = self.elements.get();
let elements_ref = unsafe { &*elements_ptr };
for existing in elements_ref.iter().take(current_count) {
if let Some(existing_element) = existing {
if *existing_element == element {
return Ok(false); }
}
}
if current_count >= CAPACITY {
return Err(CRDTError::BufferOverflow);
}
match self.count.compare_exchange_weak(
current_count,
current_count + 1,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => {
let elements_mut = unsafe { &mut *elements_ptr };
elements_mut[current_count] = Some(element);
return Ok(true);
}
Err(_) => {
continue;
}
}
}
}
pub fn contains(&self, element: &T) -> bool {
#[cfg(not(feature = "hardware-atomic"))]
{
for existing in self.elements.iter().take(self.count) {
if let Some(existing_element) = existing {
if existing_element == element {
return true;
}
}
}
false
}
#[cfg(feature = "hardware-atomic")]
{
let current_count = self.count.load(Ordering::Relaxed);
let elements_ref = unsafe { &*self.elements.get() };
for existing in elements_ref.iter().take(current_count) {
if let Some(existing_element) = existing {
if existing_element == element {
return true;
}
}
}
false
}
}
pub fn len(&self) -> usize {
#[cfg(not(feature = "hardware-atomic"))]
{
self.count
}
#[cfg(feature = "hardware-atomic")]
{
self.count.load(Ordering::Relaxed)
}
}
pub fn is_empty(&self) -> bool {
#[cfg(not(feature = "hardware-atomic"))]
{
self.count == 0
}
#[cfg(feature = "hardware-atomic")]
{
self.count.load(Ordering::Relaxed) == 0
}
}
pub fn is_full(&self) -> bool {
#[cfg(not(feature = "hardware-atomic"))]
{
self.count >= CAPACITY
}
#[cfg(feature = "hardware-atomic")]
{
self.count.load(Ordering::Relaxed) >= CAPACITY
}
}
pub fn capacity(&self) -> usize {
CAPACITY
}
pub fn remaining_capacity(&self) -> usize {
#[cfg(not(feature = "hardware-atomic"))]
{
CAPACITY - self.count
}
#[cfg(feature = "hardware-atomic")]
{
CAPACITY - self.count.load(Ordering::Relaxed)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
#[cfg(not(feature = "hardware-atomic"))]
{
self.elements
.iter()
.take(self.count)
.filter_map(|opt| opt.as_ref())
}
#[cfg(feature = "hardware-atomic")]
{
let current_count = self.count.load(Ordering::Relaxed);
let elements_ref = unsafe { &*self.elements.get() };
let mut collected = [None; 16];
let mut idx = 0;
for opt in elements_ref.iter().take(current_count) {
if let Some(element) = opt.as_ref() {
collected[idx] = Some(element);
idx += 1;
}
}
collected.into_iter().take(idx).flatten()
}
}
pub fn to_array(&self) -> [Option<T>; CAPACITY] {
#[cfg(not(feature = "hardware-atomic"))]
{
self.elements.clone()
}
#[cfg(feature = "hardware-atomic")]
{
let elements_ref = unsafe { &*self.elements.get() };
elements_ref.clone()
}
}
pub fn is_subset(&self, other: &Self) -> bool {
for element in self.iter() {
if !other.contains(element) {
return false;
}
}
true
}
pub fn is_superset(&self, other: &Self) -> bool {
other.is_subset(self)
}
pub fn union(&self, other: &Self) -> CRDTResult<Self>
where
T: core::fmt::Debug,
{
let mut result = self.clone();
result.merge(other)?;
Ok(result)
}
}
#[cfg(feature = "serde")]
impl<T, C: MemoryConfig, const CAPACITY: usize> Serialize for GSet<T, C, CAPACITY>
where
T: Serialize + Clone + PartialEq,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeStruct;
let mut state = serializer.serialize_struct("GSet", 2)?;
#[cfg(not(feature = "hardware-atomic"))]
{
state.serialize_field("elements", &&self.elements[..self.count])?;
state.serialize_field("count", &self.count)?;
}
#[cfg(feature = "hardware-atomic")]
{
let current_count = self.count.load(Ordering::Relaxed);
let elements_ref = unsafe { &*self.elements.get() };
state.serialize_field("elements", &&elements_ref[..current_count])?;
state.serialize_field("count", ¤t_count)?;
}
state.end()
}
}
#[cfg(feature = "serde")]
impl<'de, T, C: MemoryConfig, const CAPACITY: usize> Deserialize<'de> for GSet<T, C, CAPACITY>
where
T: Deserialize<'de> + Clone + PartialEq,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use core::fmt;
use serde::de::{self, MapAccess, Visitor};
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "snake_case")]
enum Field {
Elements,
Count,
}
struct GSetVisitor<T, C: MemoryConfig, const CAPACITY: usize> {
_phantom: core::marker::PhantomData<(T, C)>,
}
impl<'de, T, C: MemoryConfig, const CAPACITY: usize> Visitor<'de> for GSetVisitor<T, C, CAPACITY>
where
T: Deserialize<'de> + Clone + PartialEq,
{
type Value = GSet<T, C, CAPACITY>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct GSet")
}
fn visit_map<V>(self, mut map: V) -> Result<GSet<T, C, CAPACITY>, V::Error>
where
V: MapAccess<'de>,
{
let mut elements = None;
let mut count = None;
while let Some(key) = map.next_key()? {
match key {
Field::Elements => {
if elements.is_some() {
return Err(de::Error::duplicate_field("elements"));
}
use serde::de::SeqAccess;
struct ElementsDeserializer<T, const CAPACITY: usize> {
_phantom: core::marker::PhantomData<T>,
}
impl<'de, T, const CAPACITY: usize> serde::de::DeserializeSeed<'de>
for ElementsDeserializer<T, CAPACITY>
where
T: Deserialize<'de>,
{
type Value = [Option<T>; CAPACITY];
fn deserialize<D>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct ElementsVisitor<T, const CAPACITY: usize> {
_phantom: core::marker::PhantomData<T>,
}
impl<'de, T, const CAPACITY: usize> serde::de::Visitor<'de> for ElementsVisitor<T, CAPACITY>
where
T: Deserialize<'de>,
{
type Value = [Option<T>; CAPACITY];
fn expecting(
&self,
formatter: &mut core::fmt::Formatter,
) -> core::fmt::Result
{
write!(
formatter,
"a sequence of at most {} elements",
CAPACITY
)
}
fn visit_seq<A>(
self,
mut seq: A,
) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut array = [const { None }; CAPACITY];
let mut index = 0;
while let Some(element) =
seq.next_element::<Option<T>>()?
{
if index >= CAPACITY {
return Err(serde::de::Error::custom(
"too many elements for capacity",
));
}
array[index] = element;
index += 1;
}
Ok(array)
}
}
deserializer.deserialize_seq(ElementsVisitor::<T, CAPACITY> {
_phantom: core::marker::PhantomData,
})
}
}
let elements_array =
map.next_value_seed(ElementsDeserializer::<T, CAPACITY> {
_phantom: core::marker::PhantomData,
})?;
elements = Some(elements_array);
}
Field::Count => {
if count.is_some() {
return Err(de::Error::duplicate_field("count"));
}
count = Some(map.next_value::<usize>()?);
}
}
}
let elements_array =
elements.ok_or_else(|| de::Error::missing_field("elements"))?;
let count = count.ok_or_else(|| de::Error::missing_field("count"))?;
if count > CAPACITY {
return Err(de::Error::custom("count exceeds capacity"));
}
#[cfg(not(feature = "hardware-atomic"))]
{
Ok(GSet {
elements: elements_array,
count,
_phantom: core::marker::PhantomData,
})
}
#[cfg(feature = "hardware-atomic")]
{
Ok(GSet {
elements: UnsafeCell::new(elements_array),
count: AtomicUsize::new(count),
_phantom: core::marker::PhantomData,
})
}
}
}
const FIELDS: &[&str] = &["elements", "count"];
deserializer.deserialize_struct(
"GSet",
FIELDS,
GSetVisitor {
_phantom: core::marker::PhantomData,
},
)
}
}
impl<T, C: MemoryConfig> Default for GSet<T, C>
where
T: Clone + PartialEq,
{
fn default() -> Self {
Self::new()
}
}
impl<T, C: MemoryConfig, const CAPACITY: usize> CRDT<C> for GSet<T, C, CAPACITY>
where
T: Clone + PartialEq + core::fmt::Debug,
{
type Error = CRDTError;
fn merge(&mut self, other: &Self) -> CRDTResult<()> {
#[cfg(not(feature = "hardware-atomic"))]
{
for element in other.iter() {
if !self.contains(element) {
if self.count >= CAPACITY {
return Err(CRDTError::BufferOverflow);
}
self.elements[self.count] = Some(element.clone());
self.count += 1;
}
}
}
#[cfg(feature = "hardware-atomic")]
{
for element in other.iter() {
if !self.contains(element) {
let current_count = self.count.load(Ordering::Relaxed);
if current_count >= 16 {
return Err(CRDTError::BufferOverflow);
}
match self.count.compare_exchange_weak(
current_count,
current_count + 1,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => {
let elements_mut = unsafe { &mut *self.elements.get() };
elements_mut[current_count] = Some(element.clone());
}
Err(_) => {
continue;
}
}
}
}
}
Ok(())
}
fn eq(&self, other: &Self) -> bool {
#[cfg(not(feature = "hardware-atomic"))]
{
if self.count != other.count {
return false;
}
for element in self.iter() {
if !other.contains(element) {
return false;
}
}
true
}
#[cfg(feature = "hardware-atomic")]
{
let self_count = self.count.load(Ordering::Relaxed);
let other_count = other.count.load(Ordering::Relaxed);
if self_count != other_count {
return false;
}
for element in self.iter() {
if !other.contains(element) {
return false;
}
}
true
}
}
fn size_bytes(&self) -> usize {
core::mem::size_of::<Self>()
}
fn validate(&self) -> CRDTResult<()> {
#[cfg(not(feature = "hardware-atomic"))]
{
if self.count > 16 {
return Err(CRDTError::ConfigurationExceeded);
}
if self.count > C::MAX_SET_ELEMENTS {
return Err(CRDTError::ConfigurationExceeded);
}
for i in 0..self.count {
if let Some(ref element_i) = self.elements[i] {
for j in (i + 1)..self.count {
if let Some(ref element_j) = self.elements[j] {
if element_i == element_j {
return Err(CRDTError::InvalidState);
}
}
}
}
}
}
#[cfg(feature = "hardware-atomic")]
{
let current_count = self.count.load(Ordering::Relaxed);
let elements_ref = unsafe { &*self.elements.get() };
if current_count > 16 {
return Err(CRDTError::ConfigurationExceeded);
}
if current_count > C::MAX_SET_ELEMENTS {
return Err(CRDTError::ConfigurationExceeded);
}
for i in 0..current_count {
if let Some(ref element_i) = elements_ref[i] {
for j in (i + 1)..current_count {
if let Some(ref element_j) = elements_ref[j] {
if element_i == element_j {
return Err(CRDTError::InvalidState);
}
}
}
}
}
}
Ok(())
}
fn state_hash(&self) -> u32 {
let mut hash = 0u32;
for element in self.iter() {
let element_ptr = element as *const T as usize;
hash ^= element_ptr as u32;
}
#[cfg(not(feature = "hardware-atomic"))]
{
hash ^= self.count as u32;
}
#[cfg(feature = "hardware-atomic")]
{
hash ^= self.count.load(Ordering::Relaxed) as u32;
}
hash
}
fn can_merge(&self, other: &Self) -> bool {
let mut unique_in_other = 0;
for element in other.iter() {
if !self.contains(element) {
unique_in_other += 1;
}
}
#[cfg(not(feature = "hardware-atomic"))]
{
self.count + unique_in_other <= 16
}
#[cfg(feature = "hardware-atomic")]
{
self.count.load(Ordering::Relaxed) + unique_in_other <= 16
}
}
}
impl<T, C: MemoryConfig, const CAPACITY: usize> BoundedCRDT<C> for GSet<T, C, CAPACITY>
where
T: Clone + PartialEq + core::fmt::Debug,
{
const MAX_SIZE_BYTES: usize = core::mem::size_of::<Self>();
const MAX_ELEMENTS: usize = CAPACITY;
fn memory_usage(&self) -> usize {
core::mem::size_of::<Self>()
}
fn element_count(&self) -> usize {
#[cfg(not(feature = "hardware-atomic"))]
{
self.count
}
#[cfg(feature = "hardware-atomic")]
{
self.count.load(Ordering::Relaxed)
}
}
fn compact(&mut self) -> CRDTResult<usize> {
Ok(0)
}
fn can_add_element(&self) -> bool {
self.element_count() < Self::MAX_ELEMENTS
}
}
impl<T, C: MemoryConfig, const CAPACITY: usize> RealTimeCRDT<C> for GSet<T, C, CAPACITY>
where
T: Clone + PartialEq + core::fmt::Debug,
{
const MAX_MERGE_CYCLES: u32 = 200; const MAX_VALIDATE_CYCLES: u32 = 100;
const MAX_SERIALIZE_CYCLES: u32 = 150;
fn merge_bounded(&mut self, other: &Self) -> CRDTResult<()> {
self.merge(other)
}
fn validate_bounded(&self) -> CRDTResult<()> {
self.validate()
}
fn remaining_budget(&self) -> Option<u32> {
None
}
fn set_budget(&mut self, _cycles: u32) {
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::memory::DefaultConfig;
#[test]
fn test_new_set() {
let set = GSet::<u32, DefaultConfig>::new();
assert!(set.is_empty());
assert_eq!(set.len(), 0);
assert_eq!(set.capacity(), 16);
assert_eq!(set.remaining_capacity(), 16);
assert!(!set.is_full());
}
#[test]
fn test_insert() {
let mut set = GSet::<u32, DefaultConfig>::new();
assert!(set.insert(42).unwrap());
assert_eq!(set.len(), 1);
assert!(!set.is_empty());
assert!(set.contains(&42));
assert!(!set.insert(42).unwrap());
assert_eq!(set.len(), 1);
assert!(set.insert(43).unwrap());
assert_eq!(set.len(), 2);
assert!(set.contains(&43));
}
#[test]
fn test_contains() {
let mut set = GSet::<u32, DefaultConfig>::new();
assert!(!set.contains(&42));
set.insert(42).unwrap();
assert!(set.contains(&42));
assert!(!set.contains(&43));
set.insert(43).unwrap();
assert!(set.contains(&42));
assert!(set.contains(&43));
assert!(!set.contains(&44));
}
#[test]
fn test_capacity_limits() {
let mut set = GSet::<u32, DefaultConfig>::new();
for i in 0..16 {
assert!(set.insert(i).is_ok());
}
assert!(set.is_full());
assert_eq!(set.remaining_capacity(), 0);
assert!(set.insert(16).is_err());
}
#[test]
fn test_iter() {
let mut set = GSet::<u32, DefaultConfig>::new();
set.insert(1).unwrap();
set.insert(3).unwrap();
set.insert(2).unwrap();
let mut elements = [0u32; 3];
let mut i = 0;
for element in set.iter() {
elements[i] = *element;
i += 1;
}
elements.sort(); assert_eq!(elements, [1, 2, 3]);
}
#[test]
fn test_to_array() {
let mut set = GSet::<u32, DefaultConfig>::new();
set.insert(1).unwrap();
set.insert(3).unwrap();
set.insert(2).unwrap();
let array = set.to_array();
let mut elements = [0u32; 3];
let mut i = 0;
for opt in array.iter() {
if let Some(val) = opt {
elements[i] = *val;
i += 1;
}
}
elements.sort(); assert_eq!(elements, [1, 2, 3]);
}
#[test]
fn test_merge() {
let mut set1 = GSet::<u32, DefaultConfig>::new();
let mut set2 = GSet::<u32, DefaultConfig>::new();
set1.insert(1).unwrap();
set1.insert(2).unwrap();
set2.insert(2).unwrap();
set2.insert(3).unwrap();
assert_eq!(set1.len(), 2);
assert_eq!(set2.len(), 2);
set1.merge(&set2).unwrap();
assert_eq!(set1.len(), 3);
assert!(set1.contains(&1));
assert!(set1.contains(&2));
assert!(set1.contains(&3));
}
#[test]
fn test_merge_overflow() {
let mut set1 = GSet::<u32, DefaultConfig>::new();
let mut set2 = GSet::<u32, DefaultConfig>::new();
for i in 0..16 {
set1.insert(i).unwrap();
}
set2.insert(100).unwrap();
assert!(set1.merge(&set2).is_err());
}
#[test]
fn test_merge_idempotent() {
let mut set1 = GSet::<u32, DefaultConfig>::new();
let set2 = GSet::<u32, DefaultConfig>::new();
set1.insert(42).unwrap();
set1.merge(&set2).unwrap();
let len1 = set1.len();
set1.merge(&set2).unwrap();
let len2 = set1.len();
assert_eq!(len1, len2);
}
#[test]
fn test_merge_commutative() {
let mut set1a = GSet::<u32, DefaultConfig>::new();
let mut set1b = GSet::<u32, DefaultConfig>::new();
let mut set2 = GSet::<u32, DefaultConfig>::new();
let mut set3 = GSet::<u32, DefaultConfig>::new();
set1a.insert(1).unwrap();
set1b.insert(1).unwrap();
set2.insert(2).unwrap();
set3.insert(3).unwrap();
set1a.merge(&set2).unwrap();
set1a.merge(&set3).unwrap();
set1b.merge(&set3).unwrap();
set1b.merge(&set2).unwrap();
assert_eq!(set1a.len(), set1b.len());
assert!(set1a.eq(&set1b));
}
#[test]
fn test_subset_superset() {
let mut set1 = GSet::<u32, DefaultConfig>::new();
let mut set2 = GSet::<u32, DefaultConfig>::new();
set1.insert(1).unwrap();
set1.insert(2).unwrap();
set2.insert(1).unwrap();
set2.insert(2).unwrap();
set2.insert(3).unwrap();
assert!(set1.is_subset(&set2));
assert!(!set2.is_subset(&set1));
assert!(!set1.is_superset(&set2));
assert!(set2.is_superset(&set1));
}
#[test]
fn test_union() {
let mut set1 = GSet::<u32, DefaultConfig>::new();
let mut set2 = GSet::<u32, DefaultConfig>::new();
set1.insert(1).unwrap();
set1.insert(2).unwrap();
set2.insert(2).unwrap();
set2.insert(3).unwrap();
let union = set1.union(&set2).unwrap();
assert_eq!(union.len(), 3);
assert!(union.contains(&1));
assert!(union.contains(&2));
assert!(union.contains(&3));
assert_eq!(set1.len(), 2);
assert_eq!(set2.len(), 2);
}
#[test]
fn test_bounded_crdt() {
let mut set = GSet::<u32, DefaultConfig>::new();
set.insert(42).unwrap();
assert_eq!(set.element_count(), 1);
assert!(set.memory_usage() > 0);
assert!(set.can_add_element());
for i in 1..16 {
set.insert(i).unwrap();
}
assert_eq!(set.element_count(), 16);
assert!(!set.can_add_element());
}
#[test]
fn test_validation() {
let mut set = GSet::<u32, DefaultConfig>::new();
set.insert(42).unwrap();
assert!(set.validate().is_ok());
}
#[test]
fn test_real_time_crdt() {
let mut set1 = GSet::<u32, DefaultConfig>::new();
let set2 = GSet::<u32, DefaultConfig>::new();
assert!(set1.merge_bounded(&set2).is_ok());
assert!(set1.validate_bounded().is_ok());
}
#[test]
fn test_can_merge() {
let mut set1 = GSet::<u32, DefaultConfig>::new();
let mut set2 = GSet::<u32, DefaultConfig>::new();
for i in 0..16 {
set1.insert(i).unwrap();
}
assert!(set1.can_merge(&set2));
set2.insert(5).unwrap();
assert!(set1.can_merge(&set2));
set2.insert(100).unwrap();
assert!(!set1.can_merge(&set2));
}
#[test]
fn test_eq() {
let mut set1 = GSet::<u32, DefaultConfig>::new();
let mut set2 = GSet::<u32, DefaultConfig>::new();
assert!(set1.eq(&set2));
set1.insert(1).unwrap();
set1.insert(2).unwrap();
set2.insert(2).unwrap();
set2.insert(1).unwrap();
assert!(set1.eq(&set2));
set2.insert(3).unwrap();
assert!(!set1.eq(&set2));
}
#[test]
fn test_with_capacity() {
let set = GSet::<u32, DefaultConfig, 32>::with_capacity();
assert!(set.is_empty());
assert_eq!(set.len(), 0);
assert_eq!(set.capacity(), 32);
assert_eq!(set.remaining_capacity(), 32);
assert!(!set.is_full());
}
#[test]
fn test_custom_capacity_operations() {
let mut set = GSet::<u32, DefaultConfig, 8>::with_capacity();
assert!(set.insert(42).is_ok());
assert_eq!(set.len(), 1);
assert!(set.contains(&42));
assert_eq!(set.capacity(), 8);
for i in 1..8 {
assert!(set.insert(i).is_ok());
}
assert!(set.is_full());
assert_eq!(set.remaining_capacity(), 0);
assert!(set.insert(100).is_err());
}
#[test]
fn test_capacity_merge() {
let mut set1 = GSet::<u32, DefaultConfig, 8>::with_capacity();
let mut set2 = GSet::<u32, DefaultConfig, 8>::with_capacity();
set1.insert(1).unwrap();
set1.insert(2).unwrap();
set2.insert(2).unwrap();
set2.insert(3).unwrap();
set1.merge(&set2).unwrap();
assert_eq!(set1.len(), 3);
assert!(set1.contains(&1));
assert!(set1.contains(&2));
assert!(set1.contains(&3));
}
#[cfg(all(test, feature = "serde"))]
mod serde_tests {
use super::*;
#[test]
fn test_serialize_deserialize() {
let mut set = GSet::<i32, DefaultConfig>::new();
set.insert(42).unwrap();
set.insert(100).unwrap();
set.insert(200).unwrap();
assert_eq!(set.len(), 3);
assert!(set.contains(&42));
assert!(set.contains(&100));
assert!(set.contains(&200));
}
#[test]
fn test_atomic_vs_standard_compatibility() {
let mut set = GSet::<i32, DefaultConfig>::new();
set.insert(42).unwrap();
set.insert(84).unwrap();
set.insert(126).unwrap();
assert_eq!(set.len(), 3);
assert!(set.contains(&42));
assert!(set.contains(&84));
assert!(set.contains(&126));
}
#[test]
fn test_empty_set_serialization() {
let set = GSet::<i32, DefaultConfig>::new();
assert_eq!(set.len(), 0);
assert!(set.is_empty());
}
#[test]
fn test_custom_capacity_serialization() {
let mut set = GSet::<i32, DefaultConfig, 8>::with_capacity();
set.insert(100).unwrap();
set.insert(200).unwrap();
set.insert(300).unwrap();
assert_eq!(set.len(), 3);
assert_eq!(set.capacity(), 8);
assert!(set.contains(&100));
assert!(set.contains(&200));
assert!(set.contains(&300));
}
}
}