1use core::future::Future;
5use core::marker::PhantomData;
6
7pub trait ApplyAlg<Context, Args> {
9 type Output;
11
12 fn apply(&self, context: Context, args: Args) -> impl Future<Output = Self::Output> + Send;
14}
15
16pub trait HandlerContextAlg<Context: ?Sized> {
18 type Handle: AsRef<Context> + Clone + Send + Sync + 'static;
20}
21
22pub trait OperationAlg {
24 type Context: ?Sized;
26 type Args;
28
29 const DOC: &'static str;
35
36 const NAME: &'static str;
42
43 const ARG_NAMES: &'static [&'static str];
45}
46
47pub struct StatedArg<Arg>(PhantomData<fn() -> Arg>);
51
52impl<Arg> StatedArg<Arg> {
53 #[must_use]
55 pub const fn new() -> Self {
56 Self(PhantomData)
57 }
58}
59
60impl<Arg> Default for StatedArg<Arg> {
61 fn default() -> Self {
62 Self::new()
63 }
64}
65
66pub struct ContextArg;
69
70#[cfg(test)]
71mod tests {
72 use super::{ApplyAlg, OperationAlg};
73 use crate::ext;
74 use std::sync::Arc;
75
76 trait ValueAlg {
77 fn value(&self) -> u32;
78 }
79
80 struct Value(u32);
81
82 impl ValueAlg for Value {
83 fn value(&self) -> u32 {
84 self.0
85 }
86 }
87
88 #[ext(name = ValueExt, defunc)]
89 impl<This> This
90 where
91 This: ValueAlg,
92 {
93 async fn value_plus(&self, increment: u32) -> u32 {
95 self.value() + increment
96 }
97 }
98
99 #[ext(name = DescribeExt)]
100 impl<This> This
101 where
102 This: ValueAlg,
103 {
104 fn describe(&self) -> String {
105 self.value().to_string()
106 }
107 }
108
109 trait ReadAlg {
110 type Item;
111 type Key;
112
113 fn read(&self, key: Self::Key) -> Self::Item;
114 }
115
116 struct Reader;
117
118 impl ReadAlg for Reader {
119 type Item = String;
120 type Key = u32;
121
122 fn read(&self, key: u32) -> String {
123 key.to_string()
124 }
125 }
126
127 #[ext(name = ReadExt, defunc)]
128 impl<This, Item, Key> This
129 where
130 This: ReadAlg<Item = Item, Key = Key>,
131 Item: Send,
132 Key: Send,
133 {
134 async fn read_suffixed(&self, key: Key, suffix: Item) -> (Item, Item) {
135 (self.read(key), suffix)
136 }
137 }
138
139 #[tokio::test]
140 async fn preserves_named_parameters_bound_through_the_context() {
141 let reader = Arc::new(Reader);
142 let operation = ReadSuffixedOperation::<Reader>::default();
143
144 assert_eq!(
145 reader.read_suffixed(4, "!".to_owned()).await,
146 operation.apply(reader.clone(), (4, "!".to_owned())).await,
147 );
148 assert_eq!(<ReadSuffixedOperation<Reader> as OperationAlg>::ARG_NAMES, &["key", "suffix"]);
149 }
150
151 #[tokio::test]
152 async fn preserves_extension_methods_and_defunctionalizes_their_application() {
153 let value = Arc::new(Value(40));
154
155 assert_eq!(value.value_plus(2).await, 42);
156 assert_eq!(ValuePlusOperation::<Value>::default().apply(value, (2,)).await, 42);
157 assert_eq!(<ValuePlusOperation<Value> as OperationAlg>::NAME, "value_plus");
158 assert_eq!(<ValuePlusOperation<Value> as OperationAlg>::DOC, "Adds `increment` to the value.");
159 assert_eq!(<ValuePlusOperation<Value> as OperationAlg>::ARG_NAMES, &["increment"]);
160 }
161
162 trait BytesAlg {
163 type Error;
164 type Name;
165
166 fn push(&mut self, bytes: &[u8]) -> Result<(), Self::Error>;
167 fn leaf(&self, name: &Self::Name) -> Self::Name;
168 }
169
170 #[derive(Default)]
171 struct Buffer(Vec<u8>);
172
173 impl BytesAlg for Buffer {
174 type Error = ();
175 type Name = String;
176
177 fn push(&mut self, bytes: &[u8]) -> Result<(), ()> {
178 self.0.extend_from_slice(bytes);
179 Ok(())
180 }
181
182 fn leaf(&self, name: &String) -> String {
183 name.rsplit('/').next().unwrap_or_default().to_owned()
184 }
185 }
186
187 impl AsRef<[u8]> for Buffer {
188 fn as_ref(&self) -> &[u8] {
189 &self.0
190 }
191 }
192
193 impl AsMut<Buffer> for Buffer {
194 fn as_mut(&mut self) -> &mut Buffer {
195 self
196 }
197 }
198
199 #[ext(name = BytesExt, defunc)]
200 impl<This> This
201 where
202 This: BytesAlg,
203 {
204 fn append(&mut self, bytes: &[u8]) -> Result<(), This::Error> {
206 self.push(bytes)
207 }
208
209 fn leaves(&self, names: &[This::Name]) -> Vec<This::Name> {
211 names.iter().map(|name| self.leaf(name)).collect()
212 }
213
214 fn head(&self, count: usize) -> &[u8]
216 where
217 This: AsRef<[u8]>,
218 {
219 &self.as_ref()[..count]
220 }
221
222 fn select<Predicate>(&self, bytes: Vec<u8>, predicate: Predicate) -> Vec<u8>
224 where
225 Predicate: Fn(u8) -> bool,
226 {
227 bytes.into_iter().filter(|byte| predicate(*byte)).collect()
228 }
229 }
230
231 #[tokio::test]
232 async fn applies_operations_to_borrowed_arguments() {
233 let bytes = [1, 2, 3];
234 let mut buffer = Buffer::default();
235 AppendOperation::<Buffer>::default().apply(&mut buffer, (&bytes[..],)).await.unwrap();
236 assert_eq!(buffer.0, [1, 2, 3]);
237 assert_eq!(<AppendOperation<Buffer> as OperationAlg>::ARG_NAMES, &["bytes"]);
238
239 let names = ["a/b".to_owned(), "c".to_owned()];
240 let leaves = LeavesOperation::<Buffer>::default().apply(Arc::new(Buffer::default()), (&names[..],)).await;
241 assert_eq!(leaves, ["b", "c"]);
242 }
243
244 trait TallyAlg {
245 fn bump(&mut self) -> u32;
246 }
247
248 #[derive(Default)]
250 struct Tally(std::cell::Cell<u32>);
251
252 impl TallyAlg for Tally {
253 fn bump(&mut self) -> u32 {
254 self.0.set(self.0.get() + 1);
255 self.0.get()
256 }
257 }
258
259 #[ext(name = TallyExt, defunc)]
260 impl<This> This
261 where
262 This: TallyAlg,
263 {
264 async fn bump_twice(&mut self) -> u32 {
265 self.bump();
266 self.bump()
267 }
268 }
269
270 #[tokio::test]
271 async fn applies_a_mutable_operation_to_an_owned_handle_whose_context_is_not_sync() {
272 fn sent<Running: Send>(running: Running) -> Running {
273 running
274 }
275
276 let operation = BumpTwiceOperation::<Tally>::default();
277 let running = operation.apply(Box::new(Tally::default()), ());
278 assert_eq!(sent(running).await, 2);
279 }
280
281 #[tokio::test]
282 async fn answers_a_borrowed_output_to_a_borrowed_handle() {
283 let buffer = Buffer(vec![1, 2, 3]);
284 let head = HeadOperation::<Buffer>::default().apply(&buffer, (2,)).await;
285 assert_eq!(head, [1, 2]);
286 assert_eq!(head, buffer.head(2));
287 }
288
289 #[ext(name = PrefixExt, defunc)]
290 impl<This> This
291 where
292 This: AsRef<[u8]> + ?Sized,
293 {
294 fn prefix(&self, count: usize) -> &[u8] {
296 &self.as_ref()[..count.min(self.as_ref().len())]
297 }
298 }
299
300 #[tokio::test]
301 async fn applies_an_operation_over_an_unsized_carrier() {
302 let bytes: &[u8] = &[1, 2, 3];
303 assert_eq!(PrefixOperation::<[u8]>::default().apply(bytes, (5,)).await, [1, 2, 3]);
304 assert_eq!(PrefixOperation::<[u8]>::default().apply(bytes, (1,)).await, bytes.prefix(1));
305 }
306
307 trait Counter {
308 fn count(&self) -> usize;
309 fn bump(&mut self);
310 }
311
312 impl Counter for Buffer {
313 fn count(&self) -> usize {
314 self.0.len()
315 }
316
317 fn bump(&mut self) {
318 self.0.push(0);
319 }
320 }
321
322 #[ext(name = CounterExt, defunc)]
323 impl<This> This
324 where
325 This: Counter + ?Sized,
326 {
327 fn counted(&self, more: usize) -> usize {
329 self.count() + more
330 }
331
332 fn bumped(&mut self) -> usize {
334 self.bump();
335 self.count()
336 }
337 }
338
339 #[tokio::test]
340 async fn applies_an_operation_to_an_unsized_context_through_any_borrow() {
341 let counted = CountedOperation::<dyn Counter + Send + Sync>::default();
342 let shared: Arc<dyn Counter + Send + Sync> = Arc::new(Buffer(vec![1, 2]));
343 assert_eq!(counted.apply(Arc::clone(&shared), (1,)).await, 3);
344 assert_eq!(counted.apply(&*shared, (2,)).await, 4);
345
346 let mut owned: Box<dyn Counter + Send + Sync> = Box::new(Buffer(vec![1]));
347 let bumped = BumpedOperation::<dyn Counter + Send + Sync>::default();
348 assert_eq!(bumped.apply(&mut *owned, ()).await, 2);
349 assert_eq!(bumped.apply(owned, ()).await, 3);
350 }
351
352 #[tokio::test]
353 async fn selects_the_type_parameters_a_method_declares() {
354 fn odd(byte: u8) -> bool {
355 byte % 2 == 1
356 }
357 let operation = SelectOperation::<Buffer, fn(u8) -> bool>::default();
358 let selected = operation.apply(Arc::new(Buffer::default()), (vec![1, 2, 3], odd as fn(u8) -> bool)).await;
359 assert_eq!(selected, [1, 3]);
360 assert_eq!(<SelectOperation<Buffer, fn(u8) -> bool> as OperationAlg>::ARG_NAMES, &["bytes", "predicate"]);
361 }
362
363 #[test]
364 fn remains_compatible_with_ordinary_extensions() {
365 assert_eq!(Value(42).describe(), "42");
366 }
367}