1use smallvec::SmallVec;
2
3use crate::model::TreeModel;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum TreeInsertPosition<Id> {
8 First,
9 Last,
10 Before(Id),
11 After(Id),
12}
13
14impl<Id: PartialEq> TreeInsertPosition<Id> {
15 #[must_use]
19 pub fn index_in(&self, siblings: &[Id]) -> Option<usize> {
20 match self {
21 Self::First => Some(0),
22 Self::Last => Some(siblings.len()),
23 Self::Before(anchor) => siblings.iter().position(|sibling| sibling == anchor),
24 Self::After(anchor) => siblings
25 .iter()
26 .position(|sibling| sibling == anchor)
27 .and_then(|index| index.checked_add(1)),
28 }
29 }
30}
31
32#[derive(Clone, Debug, PartialEq, Eq)]
34pub enum TreeEditCommand<Id> {
35 CreateChild {
36 parent: Id,
37 },
38 Rename {
39 node: Id,
40 },
41 Move {
42 nodes: SmallVec<[Id; 4]>,
43 parent: Id,
44 position: TreeInsertPosition<Id>,
45 },
46 Detach {
47 nodes: SmallVec<[Id; 4]>,
48 },
49 Delete {
50 nodes: SmallVec<[Id; 4]>,
51 },
52}
53
54#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
56pub enum TreeSelectionUpdate<Id> {
57 #[default]
58 Keep,
59 Select(Id),
60 Clear,
61}
62
63#[derive(Clone, Debug, Default, PartialEq, Eq)]
65pub struct TreeChangeSet<Id> {
66 pub inserted: SmallVec<[Id; 4]>,
67 pub moved: SmallVec<[Id; 4]>,
68 pub removed: SmallVec<[Id; 4]>,
69 pub selection: TreeSelectionUpdate<Id>,
70}
71
72pub trait TreeEditor: TreeModel {
74 type Error;
75
76 fn apply(
82 &mut self,
83 command: TreeEditCommand<Self::Id>,
84 ) -> Result<TreeChangeSet<Self::Id>, Self::Error>;
85}
86
87#[cfg(test)]
88mod tests {
89 use super::TreeInsertPosition;
90
91 #[test]
92 fn insert_positions_resolve_against_siblings() {
93 let siblings = [10, 20, 30];
94 assert_eq!(TreeInsertPosition::First.index_in(&siblings), Some(0));
95 assert_eq!(TreeInsertPosition::Last.index_in(&siblings), Some(3));
96 assert_eq!(TreeInsertPosition::Before(20).index_in(&siblings), Some(1));
97 assert_eq!(TreeInsertPosition::After(20).index_in(&siblings), Some(2));
98 assert_eq!(TreeInsertPosition::Before(40).index_in(&siblings), None);
99 }
100}