1use std::sync::Arc;
14
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16use smallvec::SmallVec;
17
18use crate::{CoreError, CoreResult, DbString, Value};
19
20const MAX_PROPERTY_COUNT: usize = u32::MAX as usize;
21
22#[derive(Clone, Debug, PartialEq)]
24pub enum PropertyMap {
25 Standard(SmallVec<[(DbString, Value); 6]>),
27 Compact {
29 keys: Arc<[DbString]>,
31 values: SmallVec<[Option<Value>; 6]>,
33 },
34}
35
36impl PropertyMap {
37 #[must_use]
39 pub fn new() -> Self {
40 Self::Standard(SmallVec::new())
41 }
42
43 pub fn from_pairs(pairs: impl IntoIterator<Item = (DbString, Value)>) -> CoreResult<Self> {
52 let mut entries = pairs
53 .into_iter()
54 .collect::<SmallVec<[(DbString, Value); 6]>>();
55 if entries.len() <= 1 {
56 return Ok(Self::Standard(entries));
57 }
58 entries.sort_by(|(lhs, _), (rhs, _)| lhs.cmp(rhs));
61
62 let mut deduped = SmallVec::new();
63 for (key, value) in entries {
64 if let Some((last_key, last_value)) = deduped.last_mut()
65 && last_key == &key
66 {
67 *last_value = value;
68 continue;
69 }
70 deduped.push((key, value));
71 }
72 ensure_within_cap(deduped.len())?;
73 Ok(Self::Standard(deduped))
74 }
75
76 pub fn compact(
86 keys: impl IntoIterator<Item = DbString>,
87 values: impl IntoIterator<Item = Option<Value>>,
88 ) -> CoreResult<Self> {
89 let keys: SmallVec<[DbString; 6]> = keys.into_iter().collect();
90 let values: SmallVec<[Option<Value>; 6]> = values.into_iter().collect();
91 if keys.len() != values.len() {
92 return Err(CoreError::CompactKeyValueLengthMismatch {
93 keys: keys.len(),
94 values: values.len(),
95 });
96 }
97 ensure_within_cap(keys.len())?;
98 if keys.len() <= 1 {
99 return Ok(Self::Compact {
100 keys: Arc::from(keys.into_vec()),
101 values,
102 });
103 }
104
105 let mut slots: SmallVec<[(DbString, Option<Value>); 6]> =
106 keys.into_iter().zip(values).collect();
107 slots.sort_by(|(lhs, _), (rhs, _)| lhs.cmp(rhs));
108
109 let mut deduped: SmallVec<[(DbString, Option<Value>); 6]> = SmallVec::new();
110 for (key, value) in slots {
111 if let Some((last_key, last_value)) = deduped.last_mut()
112 && last_key == &key
113 {
114 *last_value = value;
115 continue;
116 }
117 deduped.push((key, value));
118 }
119 let (keys, values): (Vec<_>, SmallVec<_>) = deduped.into_iter().unzip();
120 Ok(Self::Compact {
121 keys: Arc::from(keys),
122 values,
123 })
124 }
125
126 #[must_use]
128 pub fn get(&self, key: &DbString) -> Option<&Value> {
129 match self {
130 Self::Standard(entries) => entries
131 .binary_search_by(|(entry_key, _)| entry_key.cmp(key))
132 .ok()
133 .map(|idx| &entries[idx].1),
134 Self::Compact { keys, values } => keys
135 .binary_search(key)
136 .ok()
137 .and_then(|idx| values.get(idx))
138 .and_then(Option::as_ref),
139 }
140 }
141
142 pub fn set(&mut self, key: DbString, value: Value) -> CoreResult<()> {
153 match self {
154 Self::Standard(entries) => set_standard(entries, key, value),
155 Self::Compact { keys, values } => match keys.binary_search(&key) {
156 Ok(idx) => {
157 values[idx] = Some(value);
158 Ok(())
159 }
160 Err(_) => {
161 let mut entries = compact_to_standard(keys, values);
162 set_standard(&mut entries, key, value)?;
163 *self = Self::Standard(entries);
164 Ok(())
165 }
166 },
167 }
168 }
169
170 pub fn remove(&mut self, key: &DbString) -> Option<Value> {
172 match self {
173 Self::Standard(entries) => entries
174 .binary_search_by(|(entry_key, _)| entry_key.cmp(key))
175 .ok()
176 .map(|idx| entries.remove(idx).1),
177 Self::Compact { keys, values } => keys
178 .binary_search(key)
179 .ok()
180 .and_then(|idx| values.get_mut(idx))
181 .and_then(Option::take),
182 }
183 }
184
185 #[must_use]
187 pub fn len(&self) -> usize {
188 match self {
189 Self::Standard(entries) => entries.len(),
190 Self::Compact { values, .. } => values.iter().filter(|value| value.is_some()).count(),
191 }
192 }
193
194 #[must_use]
196 pub fn is_empty(&self) -> bool {
197 self.len() == 0
198 }
199
200 #[must_use]
207 pub fn iter(&self) -> PropertyMapIter<'_> {
208 match self {
209 Self::Standard(entries) => PropertyMapIter::Standard(entries.iter()),
210 Self::Compact { keys, values } => PropertyMapIter::Compact {
211 keys: keys.iter(),
212 values: values.iter(),
213 },
214 }
215 }
216
217 #[must_use]
219 pub fn keys(&self) -> PropertyMapKeys<'_> {
220 PropertyMapKeys(self.iter())
221 }
222
223 #[must_use]
225 pub fn values(&self) -> PropertyMapValues<'_> {
226 PropertyMapValues(self.iter())
227 }
228
229 #[must_use]
231 pub fn contains_key(&self, key: &DbString) -> bool {
232 self.get(key).is_some()
233 }
234
235 #[cfg(test)]
236 fn sorted_invariant_holds(&self) -> bool {
237 match self {
238 Self::Standard(entries) => entries.windows(2).all(|pair| pair[0].0 < pair[1].0),
239 Self::Compact { keys, values } => {
240 keys.len() == values.len() && keys.windows(2).all(|pair| pair[0] < pair[1])
241 }
242 }
243 }
244}
245
246impl Default for PropertyMap {
247 fn default() -> Self {
248 Self::new()
249 }
250}
251
252#[derive(Debug)]
257pub enum PropertyMapIter<'a> {
258 Standard(std::slice::Iter<'a, (DbString, Value)>),
260 Compact {
262 keys: std::slice::Iter<'a, DbString>,
264 values: std::slice::Iter<'a, Option<Value>>,
266 },
267}
268
269impl<'a> Iterator for PropertyMapIter<'a> {
270 type Item = (&'a DbString, &'a Value);
271
272 fn next(&mut self) -> Option<Self::Item> {
273 match self {
274 Self::Standard(entries) => entries.next().map(|(key, value)| (key, value)),
275 Self::Compact { keys, values } => loop {
276 let value = values.next()?;
279 let key = keys.next()?;
280 if let Some(value) = value.as_ref() {
281 return Some((key, value));
282 }
283 },
284 }
285 }
286}
287
288#[derive(Debug)]
290pub struct PropertyMapKeys<'a>(PropertyMapIter<'a>);
291
292impl<'a> Iterator for PropertyMapKeys<'a> {
293 type Item = &'a DbString;
294
295 fn next(&mut self) -> Option<Self::Item> {
296 self.0.next().map(|(key, _)| key)
297 }
298}
299
300#[derive(Debug)]
302pub struct PropertyMapValues<'a>(PropertyMapIter<'a>);
303
304impl<'a> Iterator for PropertyMapValues<'a> {
305 type Item = &'a Value;
306
307 fn next(&mut self) -> Option<Self::Item> {
308 self.0.next().map(|(_, value)| value)
309 }
310}
311
312#[derive(Deserialize, Serialize)]
313enum PropertyMapWire {
314 Standard(SmallVec<[(DbString, Value); 6]>),
315 Compact {
316 keys: Arc<[DbString]>,
317 values: SmallVec<[Option<Value>; 6]>,
318 },
319}
320
321impl Serialize for PropertyMap {
322 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
323 where
324 S: Serializer,
325 {
326 match self {
335 Self::Standard(entries) => {
336 let mut entries = entries.clone();
337 entries.sort_by(|(lhs, _), (rhs, _)| lhs.as_str().cmp(rhs.as_str()));
338 PropertyMapWire::Standard(entries).serialize(serializer)
339 }
340 Self::Compact { keys, values } => {
341 if keys.len() == values.len() && compact_keys_are_canonical(keys) {
342 return PropertyMapWire::Compact {
343 keys: Arc::clone(keys),
344 values: values.clone(),
345 }
346 .serialize(serializer);
347 }
348
349 let mut pairs: Vec<(DbString, Option<Value>)> =
350 keys.iter().cloned().zip(values.iter().cloned()).collect();
351 pairs.sort_by(|(lhs, _), (rhs, _)| lhs.as_str().cmp(rhs.as_str()));
352 let (keys, values): (Vec<_>, SmallVec<_>) = pairs.into_iter().unzip();
353 PropertyMapWire::Compact {
354 keys: Arc::from(keys),
355 values,
356 }
357 .serialize(serializer)
358 }
359 }
360 }
361}
362
363fn compact_keys_are_canonical(keys: &[DbString]) -> bool {
364 keys.windows(2).all(|pair| pair[0] < pair[1])
365}
366
367impl<'de> Deserialize<'de> for PropertyMap {
368 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
369 where
370 D: Deserializer<'de>,
371 {
372 let wire = PropertyMapWire::deserialize(deserializer)?;
378 match wire {
379 PropertyMapWire::Standard(entries) => {
380 for window in entries.windows(2) {
381 if window[0].0 >= window[1].0 {
382 return Err(serde::de::Error::custom(
383 "PropertyMap::Standard entries must be sorted by DbString order with no duplicate keys",
384 ));
385 }
386 }
387 Ok(Self::Standard(entries))
388 }
389 PropertyMapWire::Compact { keys, values } => {
390 if keys.len() != values.len() {
391 return Err(serde::de::Error::custom(format!(
392 "PropertyMap::Compact key/value length mismatch: {} keys, {} values",
393 keys.len(),
394 values.len(),
395 )));
396 }
397 for window in keys.windows(2) {
398 if window[0] >= window[1] {
399 return Err(serde::de::Error::custom(
400 "PropertyMap::Compact keys must be sorted by DbString order with no duplicates",
401 ));
402 }
403 }
404 Ok(Self::Compact { keys, values })
405 }
406 }
407 }
408}
409
410fn ensure_within_cap(count: usize) -> CoreResult<()> {
411 if count > MAX_PROPERTY_COUNT {
412 Err(CoreError::ConstructedValueTooLarge {
413 got: count,
414 max: u32::MAX,
415 })
416 } else {
417 Ok(())
418 }
419}
420
421fn set_standard(
422 entries: &mut SmallVec<[(DbString, Value); 6]>,
423 key: DbString,
424 value: Value,
425) -> CoreResult<()> {
426 match entries.binary_search_by(|(entry_key, _)| entry_key.cmp(&key)) {
427 Ok(idx) => {
428 entries[idx].1 = value;
429 Ok(())
430 }
431 Err(idx) => {
432 ensure_within_cap(entries.len().saturating_add(1))?;
433 entries.insert(idx, (key, value));
434 Ok(())
435 }
436 }
437}
438
439fn compact_to_standard(
440 keys: &Arc<[DbString]>,
441 values: &SmallVec<[Option<Value>; 6]>,
442) -> SmallVec<[(DbString, Value); 6]> {
443 keys.iter()
444 .cloned()
445 .zip(values.iter())
446 .filter_map(|(key, value)| value.clone().map(|value| (key, value)))
447 .collect()
448}
449
450#[cfg(test)]
451mod tests;