composable_indexes/aggregation/
generic.rs

1use crate::{
2    ShallowClone,
3    core::{Index, Insert, Remove, Seal, Update},
4};
5
6/// Implements an `Index` given state operations.
7///
8/// Example:
9///
10/// ```rust
11/// use composable_indexes::{Collection, aggregation};
12/// let sum_aggregate = aggregation::GenericAggregate::new(
13///     // initial state
14///     0,
15///     // query function
16///     |state: &i64| *state,
17///     // insert function
18///     |state: &mut i64, value: &i64| *state += *value,
19///     // remove function
20///     |state: &mut i64, value: &i64| *state -= *value,
21/// );
22/// let mut collection = Collection::new(sum_aggregate);
23/// collection.insert(2);
24/// collection.insert(3);
25/// assert_eq!(collection.query(|ix| ix.get()), 5);
26/// ```
27#[derive(Clone)]
28pub struct GenericAggregate<In, Query, State> {
29    current_state: State,
30    query: fn(st: &State) -> Query,
31    insert: fn(&mut State, &In),
32    remove: fn(&mut State, &In),
33}
34
35impl<In, Query, State> GenericAggregate<In, Query, State> {
36    pub fn new(
37        initial_state: State,
38        query: fn(&State) -> Query,
39        insert: fn(&mut State, &In),
40        remove: fn(&mut State, &In),
41    ) -> Self {
42        Self {
43            current_state: initial_state,
44            query,
45            insert,
46            remove,
47        }
48    }
49}
50
51impl<In, Query, State> Index<In> for GenericAggregate<In, Query, State>
52where
53    State: 'static,
54    Query: 'static,
55    In: 'static,
56{
57    #[inline]
58    fn insert(&mut self, _seal: Seal, op: &Insert<In>) {
59        (self.insert)(&mut self.current_state, op.new);
60    }
61
62    #[inline]
63    fn remove(&mut self, _seal: Seal, op: &Remove<In>) {
64        (self.remove)(&mut self.current_state, op.existing);
65    }
66}
67
68impl<In, Query: Clone, State> GenericAggregate<In, Query, State> {
69    #[inline]
70    pub fn get(&self) -> Query {
71        (self.query)(&self.current_state)
72    }
73}
74
75impl<In: Clone, Query: Clone, State: Clone> ShallowClone for GenericAggregate<In, Query, State> {}
76
77/// Given an algebraic group, implement an [`Index`].
78///
79/// Example:
80///
81/// ```rust
82/// use composable_indexes::{Collection, aggregation};
83///
84/// let number_of_a = aggregation::MonoidalAggregate::new(
85//      // empty value
86///     0,
87///     // input function
88///     |x: &String| x.chars().filter(|&c| c == 'a').count() as i64,
89///     // combine function
90///     |a: &i64, b: &i64| a + b,
91///     // invert function
92///     |a: &i64| -a,
93///     // output function
94///     |a: &i64| *a,
95/// );
96///
97/// let mut collection = Collection::new(number_of_a);
98/// collection.insert("apple".to_string());
99/// collection.insert("banana".to_string());
100/// assert_eq!(collection.query(|ix| ix.get()), 4);
101/// ```
102pub struct MonoidalAggregate<T, S, O> {
103    state: S,
104    input: fn(&T) -> S,
105    combine: fn(&S, &S) -> S,
106    invert: fn(&S) -> S,
107    output: fn(&S) -> O,
108}
109
110impl<T, S, O> MonoidalAggregate<T, S, O> {
111    pub fn new(
112        empty: S,
113        input: fn(&T) -> S,
114        combine: fn(&S, &S) -> S,
115        invert: fn(&S) -> S,
116        output: fn(&S) -> O,
117    ) -> Self {
118        Self {
119            state: empty,
120            input,
121            combine,
122            invert,
123            output,
124        }
125    }
126
127    pub fn get(&self) -> O {
128        (self.output)(&self.state)
129    }
130}
131
132impl<T, S, O> Index<T> for MonoidalAggregate<T, S, O> {
133    #[inline]
134    fn insert(&mut self, _seal: Seal, op: &Insert<T>) {
135        let inp = (self.input)(op.new);
136        self.state = (self.combine)(&self.state, &inp);
137    }
138
139    #[inline]
140    fn remove(&mut self, _seal: Seal, op: &Remove<T>) {
141        let inp = (self.input)(op.existing);
142        let inv = (self.invert)(&inp);
143        self.state = (self.combine)(&self.state, &inv);
144    }
145
146    #[inline]
147    fn update(&mut self, _seal: Seal, op: &Update<T>) {
148        let old_ = (self.input)(op.existing);
149        let new_ = (self.input)(op.new);
150        let diff = (self.combine)(&(self.invert)(&old_), &new_);
151        self.state = (self.combine)(&self.state, &diff);
152    }
153}
154
155impl<T, S: Clone, O> Clone for MonoidalAggregate<T, S, O> {
156    fn clone(&self) -> Self {
157        MonoidalAggregate {
158            state: self.state.clone(),
159            input: self.input,
160            combine: self.combine,
161            invert: self.invert,
162            output: self.output,
163        }
164    }
165}
166
167impl<T, S: Clone, O> ShallowClone for MonoidalAggregate<T, S, O> {}