1#![allow(async_fn_in_trait)]
4
5extern crate self as alux_ext;
6
7pub use alux_ext_macros as macros;
12pub use alux_ext_macros::ext;
13pub use extend;
18
19use core::future::Future;
20
21pub trait ApplyAlg<Context, Args> {
23 type Output;
25
26 fn apply(&self, context: Context, args: Args) -> impl Future<Output = Self::Output> + Send;
28}
29
30pub trait HandlerContextAlg<Context> {
32 type Handle: AsRef<Context> + Clone + Send + Sync + 'static;
34}
35
36pub trait OperationAlg {
38 type Context;
40 type Args;
42
43 const ARG_NAMES: &'static [&'static str];
45}
46
47#[cfg(test)]
48mod tests {
49 use super::{ApplyAlg, OperationAlg, ext};
50 use std::sync::Arc;
51
52 trait ValueAlg {
53 fn value(&self) -> u32;
54 }
55
56 struct Value(u32);
57
58 impl ValueAlg for Value {
59 fn value(&self) -> u32 {
60 self.0
61 }
62 }
63
64 #[ext(name = ValueExt, defunc)]
65 impl<This> This
66 where
67 This: ValueAlg,
68 {
69 async fn value_plus(&self, increment: u32) -> u32 {
70 self.value() + increment
71 }
72 }
73
74 #[ext(name = DescribeExt, supertraits = ValueAlg + Sized)]
75 impl<This> This
76 where
77 This: ValueAlg,
78 {
79 fn describe(&self) -> String {
80 self.value().to_string()
81 }
82 }
83
84 #[tokio::test]
85 async fn preserves_extension_methods_and_defunctionalizes_their_application() {
86 let value = Arc::new(Value(40));
87
88 assert_eq!(value.value_plus(2).await, 42);
89 assert_eq!(ValuePlusOperation::<Value>::default().apply(value, (2,)).await, 42);
90 assert_eq!(<ValuePlusOperation<Value> as OperationAlg>::ARG_NAMES, &["increment"]);
91 }
92
93 #[test]
94 fn remains_compatible_with_ordinary_extensions() {
95 assert_eq!(Value(42).describe(), "42");
96 }
97}