diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 07:03:50 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 07:03:50 +0000 |
commit | 0bff6f8ef80ed454777a10d0b354b029722f18fe (patch) | |
tree | 619b140d4e933acdbc6d87f524856c1a682011ad /src/serde.rs | |
parent | c7a0ca3f7fc2a1505551536e0b90e0d209a2a824 (diff) | |
parent | eeb16f6eac71f26869b8e85d27fa5a7162f323d3 (diff) | |
download | slab-0bff6f8ef80ed454777a10d0b354b029722f18fe.tar.gz |
Snap for 8564071 from eeb16f6eac71f26869b8e85d27fa5a7162f323d3 to mainline-permission-releaseaml_per_331913010aml_per_331812030aml_per_331710050aml_per_331611010aml_per_331512020aml_per_331411000aml_per_331313010aml_per_331115020aml_per_331019040aml_per_330912010aml_per_330811030android13-mainline-permission-release
Change-Id: I4ce64beb749d9ca07eafe358934eeca49e4be40f
Diffstat (limited to 'src/serde.rs')
-rw-r--r-- | src/serde.rs | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/serde.rs b/src/serde.rs new file mode 100644 index 0000000..7ffe8e0 --- /dev/null +++ b/src/serde.rs @@ -0,0 +1,101 @@ +use core::fmt; +use core::marker::PhantomData; + +use serde::de::{Deserialize, Deserializer, MapAccess, Visitor}; +use serde::ser::{Serialize, SerializeMap, Serializer}; + +use super::{Entry, Slab}; + +impl<T> Serialize for Slab<T> +where + T: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut map_serializer = serializer.serialize_map(Some(self.len()))?; + for (key, value) in self { + map_serializer.serialize_key(&key)?; + map_serializer.serialize_value(value)?; + } + map_serializer.end() + } +} + +struct SlabVisitor<T>(PhantomData<T>); + +impl<'de, T> Visitor<'de> for SlabVisitor<T> +where + T: Deserialize<'de>, +{ + type Value = Slab<T>; + + fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "a map") + } + + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> + where + A: MapAccess<'de>, + { + let mut slab = Slab::with_capacity(map.size_hint().unwrap_or(0)); + + // same as FromIterator impl + let mut vacant_list_broken = false; + let mut first_vacant_index = None; + while let Some((key, value)) = map.next_entry()? { + if key < slab.entries.len() { + // iterator is not sorted, might need to recreate vacant list + if let Entry::Vacant(_) = slab.entries[key] { + vacant_list_broken = true; + slab.len += 1; + } + // if an element with this key already exists, replace it. + // This is consistent with HashMap and BtreeMap + slab.entries[key] = Entry::Occupied(value); + } else { + if first_vacant_index.is_none() && slab.entries.len() < key { + first_vacant_index = Some(slab.entries.len()); + } + // insert holes as necessary + while slab.entries.len() < key { + // add the entry to the start of the vacant list + let next = slab.next; + slab.next = slab.entries.len(); + slab.entries.push(Entry::Vacant(next)); + } + slab.entries.push(Entry::Occupied(value)); + slab.len += 1; + } + } + if slab.len == slab.entries.len() { + // no vacant entries, so next might not have been updated + slab.next = slab.entries.len(); + } else if vacant_list_broken { + slab.recreate_vacant_list(); + } else if let Some(first_vacant_index) = first_vacant_index { + let next = slab.entries.len(); + match &mut slab.entries[first_vacant_index] { + Entry::Vacant(n) => *n = next, + _ => unreachable!(), + } + } else { + unreachable!() + } + + Ok(slab) + } +} + +impl<'de, T> Deserialize<'de> for Slab<T> +where + T: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(SlabVisitor(PhantomData)) + } +} |