1#![allow(clippy::unnecessary_literal_bound)]
8
9use std::any::Any;
10
11use fsqlite_error::Result;
12use fsqlite_types::SqliteValue;
13
14use crate::FunctionArity;
15
16pub trait WindowFunction: Send + Sync {
31 type State: Send;
33
34 fn initial_state(&self) -> Self::State;
36
37 fn step(&self, state: &mut Self::State, args: &[SqliteValue]) -> Result<()>;
39
40 fn inverse(&self, state: &mut Self::State, args: &[SqliteValue]) -> Result<()>;
46
47 fn value(&self, state: &Self::State) -> Result<SqliteValue>;
52
53 fn finalize(&self, state: Self::State) -> Result<SqliteValue>;
55
56 fn num_args(&self) -> i32;
58
59 fn min_args(&self) -> i32 {
66 0
67 }
68
69 fn max_args(&self) -> Option<i32> {
74 None
75 }
76
77 fn arity(&self) -> FunctionArity {
83 let declared = self.num_args();
84 FunctionArity::from_declared_args(declared, || (self.min_args(), self.max_args()))
85 }
86
87 fn name(&self) -> &str;
89}
90
91pub struct WindowAdapter<F> {
94 inner: F,
95}
96
97impl<F> WindowAdapter<F> {
98 pub const fn new(inner: F) -> Self {
100 Self { inner }
101 }
102}
103
104impl<F> WindowFunction for WindowAdapter<F>
105where
106 F: WindowFunction,
107 F::State: 'static,
108{
109 type State = Box<dyn Any + Send>;
110
111 fn initial_state(&self) -> Self::State {
112 Box::new(self.inner.initial_state())
113 }
114
115 fn step(&self, state: &mut Self::State, args: &[SqliteValue]) -> Result<()> {
116 let concrete = state
117 .downcast_mut::<F::State>()
118 .expect("window state type mismatch");
119 self.inner.step(concrete, args)
120 }
121
122 fn inverse(&self, state: &mut Self::State, args: &[SqliteValue]) -> Result<()> {
123 let concrete = state
124 .downcast_mut::<F::State>()
125 .expect("window state type mismatch");
126 self.inner.inverse(concrete, args)
127 }
128
129 fn value(&self, state: &Self::State) -> Result<SqliteValue> {
130 let concrete = state
131 .downcast_ref::<F::State>()
132 .expect("window state type mismatch");
133 self.inner.value(concrete)
134 }
135
136 fn finalize(&self, state: Self::State) -> Result<SqliteValue> {
137 let concrete = *state
138 .downcast::<F::State>()
139 .expect("window state type mismatch");
140 self.inner.finalize(concrete)
141 }
142
143 fn num_args(&self) -> i32 {
144 self.inner.num_args()
145 }
146
147 fn min_args(&self) -> i32 {
148 self.inner.min_args()
149 }
150
151 fn max_args(&self) -> Option<i32> {
152 self.inner.max_args()
153 }
154
155 fn arity(&self) -> FunctionArity {
156 self.inner.arity()
157 }
158
159 fn name(&self) -> &str {
160 self.inner.name()
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 struct WindowSum;
171
172 impl WindowFunction for WindowSum {
173 type State = i64;
174
175 fn initial_state(&self) -> i64 {
176 0
177 }
178
179 fn step(&self, state: &mut i64, args: &[SqliteValue]) -> Result<()> {
180 *state += args[0].to_integer();
181 Ok(())
182 }
183
184 fn inverse(&self, state: &mut i64, args: &[SqliteValue]) -> Result<()> {
185 *state -= args[0].to_integer();
186 Ok(())
187 }
188
189 fn value(&self, state: &i64) -> Result<SqliteValue> {
190 Ok(SqliteValue::Integer(*state))
191 }
192
193 fn finalize(&self, state: i64) -> Result<SqliteValue> {
194 Ok(SqliteValue::Integer(state))
195 }
196
197 fn num_args(&self) -> i32 {
198 1
199 }
200
201 fn name(&self) -> &str {
202 "window_sum"
203 }
204 }
205
206 #[test]
207 fn test_window_function_step_and_inverse() {
208 let f = WindowSum;
209 let mut state = f.initial_state();
210
211 f.step(&mut state, &[SqliteValue::Integer(10)]).unwrap();
213 f.step(&mut state, &[SqliteValue::Integer(20)]).unwrap();
214 f.step(&mut state, &[SqliteValue::Integer(30)]).unwrap();
215 assert_eq!(f.value(&state).unwrap(), SqliteValue::Integer(60));
216
217 f.inverse(&mut state, &[SqliteValue::Integer(10)]).unwrap();
219 f.step(&mut state, &[SqliteValue::Integer(40)]).unwrap();
220 assert_eq!(f.value(&state).unwrap(), SqliteValue::Integer(90));
221
222 f.inverse(&mut state, &[SqliteValue::Integer(20)]).unwrap();
224 assert_eq!(f.value(&state).unwrap(), SqliteValue::Integer(70));
225 }
226
227 #[test]
228 fn test_window_function_value_without_consuming() {
229 let f = WindowSum;
230 let mut state = f.initial_state();
231
232 f.step(&mut state, &[SqliteValue::Integer(42)]).unwrap();
233
234 assert_eq!(f.value(&state).unwrap(), SqliteValue::Integer(42));
236 assert_eq!(f.value(&state).unwrap(), SqliteValue::Integer(42));
237 assert_eq!(f.value(&state).unwrap(), SqliteValue::Integer(42));
238
239 f.step(&mut state, &[SqliteValue::Integer(8)]).unwrap();
241 assert_eq!(f.value(&state).unwrap(), SqliteValue::Integer(50));
242 }
243
244 #[test]
245 fn test_window_function_finalize_consumes() {
246 let f = WindowSum;
247 let mut state = f.initial_state();
248
249 f.step(&mut state, &[SqliteValue::Integer(10)]).unwrap();
250 f.step(&mut state, &[SqliteValue::Integer(32)]).unwrap();
251
252 let result = f.finalize(state).unwrap();
254 assert_eq!(result, SqliteValue::Integer(42));
255 }
257}