use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use super::{Object, Repr};
use crate::value::Value;
impl Object {
pub fn insert(&mut self, key: Value, value: Value) -> Option<Value> {
match core::mem::take(&mut self.repr) {
Repr::Empty => {
let mut m = BTreeMap::new();
m.insert(key, value);
self.repr = Repr::BTree(m);
None
}
Repr::Frozen(mut v) => {
if let Ok(i) = v.binary_search_by(|(k, _)| k.cmp(&key)) {
let prev = core::mem::replace(&mut v[i].1, value);
self.repr = Repr::Frozen(v);
return Some(prev);
}
self.repr = Self::thawed_repr(v);
self.insert(key, value)
}
Repr::BTree(mut m) => {
let prev = m.insert(key, value);
self.repr = Repr::BTree(m);
prev
}
}
}
pub fn remove(&mut self, key: &Value) -> Option<Value> {
match core::mem::take(&mut self.repr) {
Repr::Empty => {
self.repr = Repr::Empty;
None
}
Repr::Frozen(v) => {
if v.binary_search_by(|(k, _)| k.cmp(key)).is_err() {
self.repr = Repr::Frozen(v);
return None;
}
self.repr = Self::thawed_repr(v);
self.remove(key)
}
Repr::BTree(mut m) => {
let prev = m.remove(key);
self.repr = Repr::BTree(m);
prev
}
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&Value, &mut Value) -> bool,
{
match core::mem::take(&mut self.repr) {
Repr::Empty => {
self.repr = Repr::Empty;
}
Repr::Frozen(v) => {
self.repr = Self::thawed_repr(v);
self.retain(f);
}
Repr::BTree(mut m) => {
m.retain(|k, v| f(k, v));
self.repr = Repr::BTree(m);
}
}
}
#[inline]
pub fn clear(&mut self) {
self.repr = Repr::Empty;
}
pub fn append(&mut self, other: &mut Object) {
let drained: Vec<(Value, Value)> = match core::mem::take(&mut other.repr) {
Repr::Empty => Vec::new(),
Repr::Frozen(v) => Vec::from(v),
Repr::BTree(m) => m.into_iter().collect(),
};
other.repr = Repr::Empty;
for (k, v) in drained {
self.insert(k, v);
}
}
pub fn get_or_insert_with<F: FnOnce() -> Value>(
&mut self,
key: Value,
default: F,
) -> &mut Value {
self.repr.get_or_insert_with(key, default)
}
}
impl Repr {
fn get_or_insert_with<F: FnOnce() -> Value>(&mut self, key: Value, default: F) -> &mut Value {
let frozen_index = match self {
Repr::Frozen(v) => v.binary_search_by(|(k, _)| k.cmp(&key)).ok(),
_ => None,
};
if frozen_index.is_none() {
match self {
Repr::Empty => *self = Repr::BTree(BTreeMap::new()),
Repr::BTree(m) => return m.entry(key).or_insert_with(default),
Repr::Frozen(_) => {
let repr = core::mem::take(self);
*self = match repr {
Repr::Frozen(v) => Object::thawed_repr(v),
other => other,
};
}
}
return self.get_or_insert_with(key, default);
}
match (self, frozen_index) {
(Repr::Frozen(v), Some(i)) => &mut v[i].1,
(this, _) => this.get_or_insert_with(key, default),
}
}
}