Skip to main content

yoagent_state/
fork.rs

1use crate::{Event, EventId, ForkId, Graph, StateError, replay};
2use serde::{Deserialize, Serialize};
3use std::collections::BTreeSet;
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub struct ForkSnapshot {
7    pub id: ForkId,
8    pub parent_event: Option<EventId>,
9    pub events: Vec<Event>,
10    pub graph: Graph,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub struct GraphDiff {
15    pub added_nodes: Vec<String>,
16    pub removed_nodes: Vec<String>,
17    pub changed_nodes: Vec<String>,
18    pub added_relations: Vec<String>,
19    pub removed_relations: Vec<String>,
20}
21
22pub fn fork_events_at(
23    events: &[Event],
24    id: ForkId,
25    parent_event: Option<EventId>,
26) -> Result<ForkSnapshot, StateError> {
27    let cutoff = match &parent_event {
28        Some(parent_event) => {
29            events
30                .iter()
31                .position(|event| &event.id == parent_event)
32                .ok_or_else(|| StateError::EventNotFound(parent_event.clone()))?
33                + 1
34        }
35        None => events.len(),
36    };
37    let forked_events = events.iter().take(cutoff).cloned().collect::<Vec<_>>();
38    let graph = replay(&forked_events)?;
39    Ok(ForkSnapshot {
40        id,
41        parent_event,
42        events: forked_events,
43        graph,
44    })
45}
46
47pub fn diff_graphs(left: &Graph, right: &Graph) -> GraphDiff {
48    let left_nodes = left
49        .nodes
50        .keys()
51        .map(|id| id.0.clone())
52        .collect::<BTreeSet<_>>();
53    let right_nodes = right
54        .nodes
55        .keys()
56        .map(|id| id.0.clone())
57        .collect::<BTreeSet<_>>();
58
59    let changed_nodes = left
60        .nodes
61        .iter()
62        .filter_map(|(id, node)| {
63            right
64                .nodes
65                .get(id)
66                .filter(|right_node| *right_node != node)
67                .map(|_| id.0.clone())
68        })
69        .collect();
70
71    let left_relations = left
72        .relations
73        .iter()
74        .map(|rel| format!("{}:{}:{}", rel.from, rel.rel, rel.to))
75        .collect::<BTreeSet<_>>();
76    let right_relations = right
77        .relations
78        .iter()
79        .map(|rel| format!("{}:{}:{}", rel.from, rel.rel, rel.to))
80        .collect::<BTreeSet<_>>();
81
82    GraphDiff {
83        added_nodes: right_nodes.difference(&left_nodes).cloned().collect(),
84        removed_nodes: left_nodes.difference(&right_nodes).cloned().collect(),
85        changed_nodes,
86        added_relations: right_relations
87            .difference(&left_relations)
88            .cloned()
89            .collect(),
90        removed_relations: left_relations
91            .difference(&right_relations)
92            .cloned()
93            .collect(),
94    }
95}