1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! A `Registry` is to be intended as a big container from which we can extract data based on their type.
//! A simple example is the `HashMap<TypeId, Box<Any>>`
//! A [`System`](crate::system::System) is any function that accepts any number (up to 15 because of implementation details)
//! of arguments supporting the `FromRegistry` trait.
/// Defines how a custom datatype can be extracted from a registry to be passed into a system.
/// ```
/// use aanyx::system::FromRegistry;
/// # struct MyRegistry {}
/// # struct MyDataType {}
///
/// impl MyDataType { pub fn return_true( &self ) -> bool { true } }
///
/// impl FromRegistry< MyRegistry > for MyDataType {
/// fn from_registry( registry: &MyRegistry ) -> Self {
/// // Logic to extract MyDatatype
/// MyDataType {}
/// }
/// }
/// # let my_registry = MyRegistry {};
/// assert!( MyDataType::from_registry( &my_registry ).return_true() )
/// ```
/// It is automatically implemented for tuples up to 15 parameters. This can anyway be extend by nesting tuples.
/// ```
/// use aanyx::system::FromRegistry;
/// # struct MyRegistry {}
/// # let my_registry = MyRegistry {};
/// # trait MyDefault:Default {}
/// # impl FromRegistry< MyRegistry > for String { fn from_registry( _registry: &MyRegistry ) -> Self { Self::default() } }
/// # impl FromRegistry< MyRegistry > for u8 { fn from_registry( _registry: &MyRegistry ) -> Self { Self::default() } }
/// # impl FromRegistry< MyRegistry > for usize { fn from_registry( _registry: &MyRegistry ) -> Self { Self::default() } }
///
/// // These are equivalents
/// let (a0, b0, c0 /*, others... */) = <(String, u8, usize /*, Others... */)>::from_registry( &my_registry );
/// let ((a1, b1), c1, /* others... */ ) = <((String, u8), usize /*, Others... */)>::from_registry( &my_registry );
///
/// // In general that's not true. It depends on the registry. This example makes them all equals for simplicity
/// assert_eq!( a0, a1 );
/// assert_eq!( b0, b1 );
/// assert_eq!( c0, c1 );
/// ```
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
impl_from_registry!;
/// A system is a trait that allows a function to be called giving only a registry and letting the compiler
/// figure out what needs to be extracted from that registry in order to call the function
/// ```
/// use aanyx::system::System;
/// use std::rc::Rc;
///
/// struct Data<T>{ data: Rc<T> }
///
/// # use aanyx::system::FromRegistry;
/// # impl FromRegistry<(Rc<Person>, Location)> for Data<Person> { fn from_registry( (person, _) :&(Rc<Person>, Location)) -> Self { Data { data: Rc::clone(person) } }}
/// // Simulate other data
/// struct Location {}
/// struct Person{ name: String, age: u8 }
/// fn old_enough( person: Data<Person> ) -> bool { person.data.age > 30 }
///
/// let registry0 = ( Rc::new(Person{ name: String::from("Alice"), age: 24u8 }), Location { /* Location data */ }) ;
/// let registry1 = ( Rc::new(Person{ name: String::from("Bob"), age: 31u8 }), Location { /* Location data */ });
/// let registry2 = ( Rc::new(Person{ name: String::from("Charlie"), age: 1u8 }), Location { /* Location data */ });
///
/// assert_eq!( old_enough.apply( ®istry0 ), false );
/// assert_eq!( old_enough.apply( ®istry1 ), true );
/// assert_eq!( old_enough.apply( ®istry2 ), false );
/// ```
/// ## Closures
/// A closure can be made into a `System` only if the closure accepts no arguments
/// ```
/// use aanyx::system::System;
///
/// fn always_true() -> bool { true }
/// let always_true_wrapper = ||{ always_true.apply( &()) };
///
/// // The &() is required because the `System.apply` expects an argument although the closure has 0 arguments
/// assert!( always_true_wrapper.apply( &() ) );
/// ```
///
/// ```
/// use aanyx::system::System;
/// use std::rc::Rc;
/// let registry = Rc::new(());
/// let registry_copy = Rc::clone( ®istry );
///
/// fn always_true() -> bool { true }
/// let always_true_wrapper = move ||{ always_true.apply( ®istry_copy ) };
///
/// assert!( always_true_wrapper.apply( ®istry ))
/// ```
/// ## Performance analysis
/// Benchamrks performed suggests that the overhead of calling a system insted of the original function is negligible.
///
/// ## Async programming
/// Actually the system supports async functions, but arguments extraction from registry is not async.
///
/// ## Safety
/// Calling a unsafe function through the `System` trait will not generate any new unsafeties, but the function will still be unsafe.
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;
impl_system_for!;