1#[fp_macros::document_module]
6mod inner {
7 use {
8 crate::{
9 classes::{
10 CloneableFn,
11 Monoid,
12 Semigroup,
13 },
14 functions::identity,
15 },
16 fp_macros::*,
17 std::{
18 fmt::{
19 self,
20 Debug,
21 Formatter,
22 },
23 hash::Hash,
24 },
25 };
26
27 #[document_type_parameters(
38 "The lifetime of the function and its captured data.",
39 "The brand of the cloneable function wrapper.",
40 "The input and output type of the function."
41 )]
42 pub struct Endofunction<'a, FnBrand: CloneableFn, A: 'a>(
44 pub <FnBrand as CloneableFn>::Of<'a, A, A>,
46 );
47
48 #[document_type_parameters(
49 "The lifetime of the function and its captured data.",
50 "The brand of the function (e.g., `RcFnBrand`).",
51 "The input and output type of the function."
52 )]
53 impl<'a, FnBrand: CloneableFn, A: 'a> Endofunction<'a, FnBrand, A> {
54 #[document_signature]
58 #[document_parameters("The function to wrap.")]
60 #[document_returns("A new `Endofunction`.")]
62 #[document_examples]
64 pub fn new(f: <FnBrand as CloneableFn>::Of<'a, A, A>) -> Self {
76 Self(f)
77 }
78 }
79
80 #[document_type_parameters(
81 "The lifetime of the function and its captured data.",
82 "The brand of the function (e.g., `RcFnBrand`).",
83 "The input and output type of the function."
84 )]
85 #[document_parameters("The function to clone.")]
86 impl<'a, FnBrand: CloneableFn, A: 'a> Clone for Endofunction<'a, FnBrand, A> {
87 #[document_signature]
88 #[document_returns("The cloned endofunction.")]
89 #[document_examples]
90 fn clone(&self) -> Self {
102 Self::new(self.0.clone())
103 }
104 }
105
106 #[document_type_parameters(
107 "The lifetime of the function and its captured data.",
108 "The brand of the function (e.g., `RcFnBrand`).",
109 "The input and output type of the function."
110 )]
111 #[document_parameters("The function to format.")]
112 impl<'a, FnBrand: CloneableFn, A: 'a> Debug for Endofunction<'a, FnBrand, A>
113 where
114 <FnBrand as CloneableFn>::Of<'a, A, A>: Debug,
115 {
116 #[document_signature]
117 #[document_parameters("The formatter to use.")]
118 #[document_returns("The result of the formatting operation.")]
119 #[document_examples]
120 fn fmt(
133 &self,
134 fmt: &mut Formatter<'_>,
135 ) -> fmt::Result {
136 fmt.debug_tuple("Endofunction").field(&self.0).finish()
137 }
138 }
139
140 #[document_type_parameters(
141 "The lifetime of the function and its captured data.",
142 "The brand of the function (e.g., `RcFnBrand`).",
143 "The input and output type of the function."
144 )]
145 impl<'a, FnBrand: CloneableFn, A: 'a> Eq for Endofunction<'a, FnBrand, A> where
146 <FnBrand as CloneableFn>::Of<'a, A, A>: Eq
147 {
148 }
149
150 #[document_type_parameters(
151 "The lifetime of the function and its captured data.",
152 "The brand of the function (e.g., `RcFnBrand`).",
153 "The input and output type of the function."
154 )]
155 #[document_parameters("The function to hash.")]
156 impl<'a, FnBrand: CloneableFn, A: 'a> Hash for Endofunction<'a, FnBrand, A>
157 where
158 <FnBrand as CloneableFn>::Of<'a, A, A>: Hash,
159 {
160 #[document_signature]
161 #[document_type_parameters("The type of the hasher.")]
162 #[document_parameters("The hasher state to update.")]
163 #[document_examples]
164 fn hash<H: std::hash::Hasher>(
177 &self,
178 state: &mut H,
179 ) {
180 self.0.hash(state);
181 }
182 }
183
184 #[document_type_parameters(
185 "The lifetime of the function and its captured data.",
186 "The brand of the function (e.g., `RcFnBrand`).",
187 "The input and output type of the function."
188 )]
189 #[document_parameters("The function to compare.")]
190 impl<'a, FnBrand: CloneableFn, A: 'a> Ord for Endofunction<'a, FnBrand, A>
191 where
192 <FnBrand as CloneableFn>::Of<'a, A, A>: Ord,
193 {
194 #[document_signature]
195 #[document_parameters("The other function to compare to.")]
196 #[document_returns("The ordering of the values.")]
197 #[document_examples]
198 fn cmp(
212 &self,
213 other: &Self,
214 ) -> std::cmp::Ordering {
215 self.0.cmp(&other.0)
216 }
217 }
218
219 #[document_type_parameters(
220 "The lifetime of the function and its captured data.",
221 "The brand of the function (e.g., `RcFnBrand`).",
222 "The input and output type of the function."
223 )]
224 #[document_parameters("The function to compare.")]
225 impl<'a, FnBrand: CloneableFn, A: 'a> PartialEq for Endofunction<'a, FnBrand, A>
226 where
227 <FnBrand as CloneableFn>::Of<'a, A, A>: PartialEq,
228 {
229 #[document_signature]
230 #[document_parameters("The other function to compare to.")]
231 #[document_returns("True if the values are equal, false otherwise.")]
232 #[document_examples]
233 fn eq(
247 &self,
248 other: &Self,
249 ) -> bool {
250 self.0 == other.0
251 }
252 }
253
254 #[document_type_parameters(
255 "The lifetime of the function and its captured data.",
256 "The brand of the function (e.g., `RcFnBrand`).",
257 "The input and output type of the function."
258 )]
259 #[document_parameters("The function to compare.")]
260 impl<'a, FnBrand: CloneableFn, A: 'a> PartialOrd for Endofunction<'a, FnBrand, A>
261 where
262 <FnBrand as CloneableFn>::Of<'a, A, A>: PartialOrd,
263 {
264 #[document_signature]
265 #[document_parameters("The other function to compare to.")]
266 #[document_returns("An ordering if the values can be compared, none otherwise.")]
267 #[document_examples]
268 fn partial_cmp(
282 &self,
283 other: &Self,
284 ) -> Option<std::cmp::Ordering> {
285 self.0.partial_cmp(&other.0)
286 }
287 }
288
289 #[document_type_parameters(
290 "The lifetime of the function and its captured data.",
291 "The brand of the function (e.g., `RcFnBrand`).",
292 "The input and output type of the function."
293 )]
294 impl<'a, FnBrand: 'a + CloneableFn, A: 'a> Semigroup for Endofunction<'a, FnBrand, A> {
295 #[document_signature]
301 #[document_parameters(
303 "The second function to apply (the outer function).",
304 "The first function to apply (the inner function)."
305 )]
306 #[document_returns("The composed function `a . b`.")]
308 #[document_examples]
309 fn append(
325 a: Self,
326 b: Self,
327 ) -> Self {
328 let f = a.0;
329 let g = b.0;
330 Self::new(<FnBrand as CloneableFn>::new(move |x| f(g(x))))
332 }
333 }
334
335 #[document_type_parameters(
336 "The lifetime of the function and its captured data.",
337 "The brand of the function (e.g., `RcFnBrand`).",
338 "The input and output type of the function."
339 )]
340 impl<'a, FnBrand: 'a + CloneableFn, A: 'a> Monoid for Endofunction<'a, FnBrand, A> {
341 #[document_signature]
345 #[document_returns("The identity endofunction.")]
347 #[document_examples]
349 fn empty() -> Self {
361 Self::new(<FnBrand as CloneableFn>::new(identity))
362 }
363 }
364}
365pub use inner::*;
366
367#[cfg(test)]
368mod tests {
369 use {
370 super::*,
371 crate::{
372 brands::RcFnBrand,
373 classes::{
374 cloneable_fn::CloneableFn,
375 monoid::empty,
376 semigroup::append,
377 },
378 },
379 quickcheck_macros::quickcheck,
380 };
381
382 #[quickcheck]
386 fn semigroup_associativity(val: i32) -> bool {
387 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
388 x.wrapping_add(1)
389 }));
390 let g = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
391 x.wrapping_mul(2)
392 }));
393 let h = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
394 x.wrapping_sub(3)
395 }));
396
397 let lhs = append(f.clone(), append(g.clone(), h.clone()));
398 let rhs = append(append(f, g), h);
399
400 lhs.0(val) == rhs.0(val)
401 }
402
403 #[quickcheck]
407 fn monoid_left_identity(val: i32) -> bool {
408 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
409 x.wrapping_add(1)
410 }));
411 let id = empty::<Endofunction<RcFnBrand, i32>>();
412
413 let res = append(id, f.clone());
414 res.0(val) == f.0(val)
415 }
416
417 #[quickcheck]
419 fn monoid_right_identity(val: i32) -> bool {
420 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
421 x.wrapping_add(1)
422 }));
423 let id = empty::<Endofunction<RcFnBrand, i32>>();
424
425 let res = append(f.clone(), id);
426 res.0(val) == f.0(val)
427 }
428}