use std::collections::HashMap;
use std::sync::Arc;
use crate::state::State;
#[derive(Debug, Clone)]
pub enum ChangeOperation {
Put,
Delete,
}
#[derive(Debug, Clone)]
pub struct ChangeRecord {
pub key: String,
pub operation: ChangeOperation,
pub value: serde_json::Value,
}
pub struct BranchState {
base: Arc<State>,
local: HashMap<String, serde_json::Value>,
changes: Vec<ChangeRecord>,
}
impl Clone for BranchState {
fn clone(&self) -> Self {
Self {
base: Arc::clone(&self.base),
local: self.local.clone(),
changes: self.changes.clone(),
}
}
}
impl std::fmt::Debug for BranchState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BranchState")
.field("base_keys", &self.base.len())
.field("local_keys", &self.local.len())
.field("changes", &self.changes.len())
.finish()
}
}
impl BranchState {
pub fn from_state(state: State) -> Self {
Self {
base: Arc::new(state),
local: HashMap::new(),
changes: Vec::new(),
}
}
pub fn empty() -> Self {
Self::from_state(State::new())
}
pub fn get(&self, key: &str) -> Option<&serde_json::Value> {
self.local.get(key).or_else(|| self.base.get(key))
}
pub fn get_ref(&self, key: &str) -> Option<&serde_json::Value> {
self.local.get(key).or_else(|| self.base.get(key))
}
pub fn get_typed<T: serde::de::DeserializeOwned>(&self, key: &str) -> Option<T> {
self.get(key)
.and_then(|v| serde_json::from_value(v.clone()).ok())
}
pub fn set(&mut self, key: impl Into<String>, value: serde_json::Value) {
let key = key.into();
self.changes.push(ChangeRecord {
key: key.clone(),
operation: ChangeOperation::Put,
value: value.clone(),
});
self.local.insert(key, value);
}
pub fn remove(&mut self, key: &str) {
self.changes.push(ChangeRecord {
key: key.to_string(),
operation: ChangeOperation::Delete,
value: serde_json::Value::Null,
});
self.local.remove(key);
}
pub fn fork(&self) -> BranchState {
let state = self.to_state();
BranchState {
base: Arc::new(state),
local: HashMap::new(),
changes: Vec::new(),
}
}
pub fn to_state(&self) -> State {
let mut state = self.base.as_ref().clone();
for (key, value) in &self.local {
state.insert(key.clone(), value.clone());
}
state
}
pub fn changes(&self) -> &[ChangeRecord] {
&self.changes
}
pub fn clear_changes(&mut self) {
self.changes.clear();
}
pub fn keys(&self) -> Vec<String> {
let mut keys: Vec<String> = self.base.keys().cloned().collect();
for key in self.local.keys() {
if !keys.contains(key) {
keys.push(key.clone());
}
}
keys
}
pub fn contains(&self, key: &str) -> bool {
self.local.contains_key(key) || self.base.contains_key(key)
}
pub fn base(&self) -> &State {
&self.base
}
}