use std::collections::BTreeMap;
use super::{DictMap, VmValue};
pub trait DictInsert {
fn dict_insert(&mut self, key: String, value: VmValue);
}
impl DictInsert for BTreeMap<String, VmValue> {
fn dict_insert(&mut self, key: String, value: VmValue) {
self.insert(key, value);
}
}
impl DictInsert for DictMap {
fn dict_insert(&mut self, key: String, value: VmValue) {
self.insert(key, value);
}
}
pub trait VmDictExt {
fn put(&mut self, key: &str, value: VmValue);
fn put_str(&mut self, key: &str, value: impl AsRef<str>);
fn put_opt_str(&mut self, key: &str, value: Option<impl AsRef<str>>);
fn put_opt(&mut self, key: &str, value: Option<VmValue>);
fn put_bool(&mut self, key: &str, value: bool);
fn put_int(&mut self, key: &str, value: i64);
}
pub trait DictRetain {
fn retain(&mut self, keep: impl FnMut(&String, &mut VmValue) -> bool);
}
impl DictRetain for DictMap {
fn retain(&mut self, mut keep: impl FnMut(&String, &mut VmValue) -> bool) {
let mut result = DictMap::new();
for (k, v) in self.iter() {
let mut v = v.clone();
if keep(k, &mut v) {
result.insert(k.clone(), v);
}
}
*self = result;
}
}
impl<M: DictInsert> VmDictExt for M {
fn put(&mut self, key: &str, value: VmValue) {
self.dict_insert(key.to_string(), value);
}
fn put_str(&mut self, key: &str, value: impl AsRef<str>) {
self.dict_insert(key.to_string(), VmValue::string(value));
}
fn put_opt_str(&mut self, key: &str, value: Option<impl AsRef<str>>) {
if let Some(value) = value {
self.dict_insert(key.to_string(), VmValue::string(value));
}
}
fn put_opt(&mut self, key: &str, value: Option<VmValue>) {
if let Some(value) = value {
self.dict_insert(key.to_string(), value);
}
}
fn put_bool(&mut self, key: &str, value: bool) {
self.dict_insert(key.to_string(), VmValue::Bool(value));
}
fn put_int(&mut self, key: &str, value: i64) {
self.dict_insert(key.to_string(), VmValue::Int(value));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn put_str_matches_manual_construction() {
let mut dict = BTreeMap::new();
dict.put_str("k", "v");
match dict.get("k") {
Some(VmValue::String(s)) => assert_eq!(s.as_ref(), "v"),
other => panic!("expected string value, got {other:?}"),
}
}
#[test]
fn put_opt_str_skips_none_and_inserts_some() {
let mut dict = BTreeMap::new();
dict.put_opt_str("present", Some("v"));
dict.put_opt_str("absent", None::<&str>);
assert!(dict.contains_key("present"));
assert!(!dict.contains_key("absent"));
}
#[test]
fn put_handles_scalars() {
let mut dict = BTreeMap::new();
dict.put_bool("b", true);
dict.put_int("n", 7);
dict.put("nil", VmValue::Nil);
assert!(matches!(dict.get("b"), Some(VmValue::Bool(true))));
assert!(matches!(dict.get("n"), Some(VmValue::Int(7))));
assert!(matches!(dict.get("nil"), Some(VmValue::Nil)));
}
}