Skip to main content

wesichain_core/
state.rs

1use serde::{de::DeserializeOwned, Deserialize, Serialize};
2use std::collections::HashSet;
3use std::hash::Hash;
4
5/// Trait for defining how to merge concurrent updates for a specific field.
6pub trait Reducer<T>: Send + Sync {
7    fn reduce(&self, current: T, update: T) -> T;
8}
9
10/// Reducer that overwrites the current value with the update (Last-Write-Wins).
11pub struct Overwrite;
12impl<T> Reducer<T> for Overwrite {
13    fn reduce(&self, _current: T, update: T) -> T {
14        update
15    }
16}
17
18/// Reducer that appends the update to the current value (for Vec<T>).
19pub struct Append;
20impl<T> Reducer<Vec<T>> for Append {
21    fn reduce(&self, mut current: Vec<T>, mut update: Vec<T>) -> Vec<T> {
22        current.append(&mut update);
23        current
24    }
25}
26
27/// Reducer that computes the union of the current and update sets (for HashSet<T>).
28pub struct Union;
29impl<T: Eq + Hash> Reducer<HashSet<T>> for Union {
30    fn reduce(&self, mut current: HashSet<T>, update: HashSet<T>) -> HashSet<T> {
31        current.extend(update);
32        current
33    }
34}
35
36pub trait StateSchema:
37    Serialize + DeserializeOwned + Clone + Default + Send + Sync + std::fmt::Debug + 'static
38{
39    type Update: Serialize
40        + DeserializeOwned
41        + Clone
42        + Default
43        + Send
44        + Sync
45        + std::fmt::Debug
46        + 'static;
47
48    fn apply(current: &Self, update: Self::Update) -> Self;
49
50    /// Human-readable representation for tracing/debugging.
51    /// Override for custom formatting; default uses JSON serialization.
52    fn trace_repr(&self) -> String {
53        serde_json::to_string_pretty(self).unwrap_or_else(|_| "<unserializable>".to_string())
54    }
55}
56
57pub trait StateReducer: StateSchema {
58    fn reduce(current: &Self, update: Self::Update) -> Self {
59        <Self as StateSchema>::apply(current, update)
60    }
61}
62
63impl<T: StateSchema> StateReducer for T {}
64
65#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
66#[serde(bound = "S: StateSchema")]
67pub struct GraphState<S: StateSchema> {
68    pub data: S,
69}
70
71impl<S: StateSchema> GraphState<S> {
72    pub fn new(data: S) -> Self {
73        Self { data }
74    }
75
76    pub fn apply_update(self, update: StateUpdate<S>) -> Self {
77        Self {
78            data: S::apply(&self.data, update.data),
79        }
80    }
81
82    pub fn apply(self, update: StateUpdate<S>) -> Self {
83        self.apply_update(update)
84    }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
88#[serde(bound = "S: StateSchema")]
89pub struct StateUpdate<S: StateSchema> {
90    pub data: S::Update,
91}
92#[cfg(test)]
93#[path = "state_tests.rs"]
94mod state_tests;
95impl<S: StateSchema> StateUpdate<S> {
96    pub fn new(data: S::Update) -> Self {
97        Self { data }
98    }
99}