64 lines
1.6 KiB
Rust
64 lines
1.6 KiB
Rust
|
use std::{collections::HashMap, sync::{Arc, RwLock}};
|
||
|
|
||
|
use crate::value::Value;
|
||
|
|
||
|
#[derive(Debug, Clone)]
|
||
|
pub struct Env<'env> {
|
||
|
values: Arc<RwLock<HashMap<String, Value>>>,
|
||
|
parent: Option<&'env Env<'env>>,
|
||
|
}
|
||
|
|
||
|
impl Env<'_> {
|
||
|
pub fn new() -> Self {
|
||
|
Env {
|
||
|
values: Default::default(),
|
||
|
parent: None,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn get(&self, name: &str) -> Option<Value> {
|
||
|
if let Some(v) = self.values.read().unwrap().get(name) {
|
||
|
Some(v.clone())
|
||
|
} else if let Some(parent) = &self.parent {
|
||
|
parent.get(name)
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn set(&self, name: &str, value: impl Into<Value>) {
|
||
|
let value = value.into();
|
||
|
if !self.set_recursive(name, &value) {
|
||
|
self.values.write().unwrap().insert(name.to_string(), value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn set_recursive(&self, name: &str, value: &Value) -> bool {
|
||
|
if let Some(v) = self.values.write().unwrap().get_mut(name) {
|
||
|
*v = value.clone();
|
||
|
true
|
||
|
} else if let Some(parent) = self.parent {
|
||
|
parent.set_recursive(name, value)
|
||
|
} else {
|
||
|
false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn update(&self, name: &str, f: impl FnOnce(&Value) -> Value) {
|
||
|
if let Some(v) = self.values.write().unwrap().get_mut(name) {
|
||
|
*v = f(v);
|
||
|
} else if let Some(parent) = self.parent {
|
||
|
parent.update(name, f);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'env> Env<'env> {
|
||
|
pub fn new_with_parent(parent: &'env Env<'env>) -> Self {
|
||
|
Env {
|
||
|
values: Default::default(),
|
||
|
parent: Some(parent),
|
||
|
}
|
||
|
}
|
||
|
}
|