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