1#[fp_macros::document_module]
6mod inner {
7 use {
8 crate::{
9 classes::*,
10 functions::identity,
11 },
12 fp_macros::*,
13 std::{
14 fmt::{
15 self,
16 Debug,
17 Formatter,
18 },
19 hash::Hash,
20 },
21 };
22
23 #[document_type_parameters(
34 "The lifetime of the function and its captured data.",
35 "The brand of the cloneable function wrapper.",
36 "The input and output type of the function."
37 )]
38 pub struct Endofunction<'a, FnBrand: LiftFn, A: 'a>(
40 pub <FnBrand as CloneFn>::Of<'a, A, A>,
42 );
43
44 #[document_type_parameters(
45 "The lifetime of the function and its captured data.",
46 "The brand of the function (e.g., `RcFnBrand`).",
47 "The input and output type of the function."
48 )]
49 impl<'a, FnBrand: LiftFn, A: 'a> Endofunction<'a, FnBrand, A> {
50 #[document_signature]
54 #[document_parameters("The function to wrap.")]
56 #[document_returns("A new `Endofunction`.")]
58 #[document_examples]
60 pub fn new(f: <FnBrand as CloneFn>::Of<'a, A, A>) -> Self {
72 Self(f)
73 }
74 }
75
76 #[document_type_parameters(
77 "The lifetime of the function and its captured data.",
78 "The brand of the function (e.g., `RcFnBrand`).",
79 "The input and output type of the function."
80 )]
81 #[document_parameters("The function to clone.")]
82 impl<'a, FnBrand: LiftFn, A: 'a> Clone for Endofunction<'a, FnBrand, A> {
83 #[document_signature]
84 #[document_returns("The cloned endofunction.")]
85 #[document_examples]
86 fn clone(&self) -> Self {
98 Self::new(self.0.clone())
99 }
100 }
101
102 #[document_type_parameters(
103 "The lifetime of the function and its captured data.",
104 "The brand of the function (e.g., `RcFnBrand`).",
105 "The input and output type of the function."
106 )]
107 #[document_parameters("The function to format.")]
108 impl<'a, FnBrand: LiftFn, A: 'a> Debug for Endofunction<'a, FnBrand, A>
109 where
110 <FnBrand as CloneFn>::Of<'a, A, A>: Debug,
111 {
112 #[document_signature]
113 #[document_parameters("The formatter to use.")]
114 #[document_returns("The result of the formatting operation.")]
115 #[document_examples]
116 fn fmt(
129 &self,
130 fmt: &mut Formatter<'_>,
131 ) -> fmt::Result {
132 fmt.debug_tuple("Endofunction").field(&self.0).finish()
133 }
134 }
135
136 #[document_type_parameters(
137 "The lifetime of the function and its captured data.",
138 "The brand of the function (e.g., `RcFnBrand`).",
139 "The input and output type of the function."
140 )]
141 impl<'a, FnBrand: LiftFn, A: 'a> Eq for Endofunction<'a, FnBrand, A> where
142 <FnBrand as CloneFn>::Of<'a, A, A>: Eq
143 {
144 }
145
146 #[document_type_parameters(
147 "The lifetime of the function and its captured data.",
148 "The brand of the function (e.g., `RcFnBrand`).",
149 "The input and output type of the function."
150 )]
151 #[document_parameters("The function to hash.")]
152 impl<'a, FnBrand: LiftFn, A: 'a> Hash for Endofunction<'a, FnBrand, A>
153 where
154 <FnBrand as CloneFn>::Of<'a, A, A>: Hash,
155 {
156 #[document_signature]
157 #[document_type_parameters("The type of the hasher.")]
158 #[document_parameters("The hasher state to update.")]
159 #[document_examples]
160 fn hash<H: std::hash::Hasher>(
173 &self,
174 state: &mut H,
175 ) {
176 self.0.hash(state);
177 }
178 }
179
180 #[document_type_parameters(
181 "The lifetime of the function and its captured data.",
182 "The brand of the function (e.g., `RcFnBrand`).",
183 "The input and output type of the function."
184 )]
185 #[document_parameters("The function to compare.")]
186 impl<'a, FnBrand: LiftFn, A: 'a> Ord for Endofunction<'a, FnBrand, A>
187 where
188 <FnBrand as CloneFn>::Of<'a, A, A>: Ord,
189 {
190 #[document_signature]
191 #[document_parameters("The other function to compare to.")]
192 #[document_returns("The ordering of the values.")]
193 #[document_examples]
194 fn cmp(
208 &self,
209 other: &Self,
210 ) -> std::cmp::Ordering {
211 self.0.cmp(&other.0)
212 }
213 }
214
215 #[document_type_parameters(
216 "The lifetime of the function and its captured data.",
217 "The brand of the function (e.g., `RcFnBrand`).",
218 "The input and output type of the function."
219 )]
220 #[document_parameters("The function to compare.")]
221 impl<'a, FnBrand: LiftFn, A: 'a> PartialEq for Endofunction<'a, FnBrand, A>
222 where
223 <FnBrand as CloneFn>::Of<'a, A, A>: PartialEq,
224 {
225 #[document_signature]
226 #[document_parameters("The other function to compare to.")]
227 #[document_returns("True if the values are equal, false otherwise.")]
228 #[document_examples]
229 fn eq(
243 &self,
244 other: &Self,
245 ) -> bool {
246 self.0 == other.0
247 }
248 }
249
250 #[document_type_parameters(
251 "The lifetime of the function and its captured data.",
252 "The brand of the function (e.g., `RcFnBrand`).",
253 "The input and output type of the function."
254 )]
255 #[document_parameters("The function to compare.")]
256 impl<'a, FnBrand: LiftFn, A: 'a> PartialOrd for Endofunction<'a, FnBrand, A>
257 where
258 <FnBrand as CloneFn>::Of<'a, A, A>: PartialOrd,
259 {
260 #[document_signature]
261 #[document_parameters("The other function to compare to.")]
262 #[document_returns("An ordering if the values can be compared, none otherwise.")]
263 #[document_examples]
264 fn partial_cmp(
278 &self,
279 other: &Self,
280 ) -> Option<std::cmp::Ordering> {
281 self.0.partial_cmp(&other.0)
282 }
283 }
284
285 #[document_type_parameters(
286 "The lifetime of the function and its captured data.",
287 "The brand of the function (e.g., `RcFnBrand`).",
288 "The input and output type of the function."
289 )]
290 impl<'a, FnBrand: 'a + LiftFn, A: 'a> Semigroup for Endofunction<'a, FnBrand, A> {
291 #[document_signature]
297 #[document_parameters(
299 "The second function to apply (the outer function).",
300 "The first function to apply (the inner function)."
301 )]
302 #[document_returns("The composed function `a . b`.")]
304 #[document_examples]
305 fn append(
321 a: Self,
322 b: Self,
323 ) -> Self {
324 let f = a.0;
325 let g = b.0;
326 Self::new(<FnBrand as LiftFn>::new(move |x| f(g(x))))
328 }
329 }
330
331 #[document_type_parameters(
332 "The lifetime of the function and its captured data.",
333 "The brand of the function (e.g., `RcFnBrand`).",
334 "The input and output type of the function."
335 )]
336 impl<'a, FnBrand: 'a + LiftFn, A: 'a> Monoid for Endofunction<'a, FnBrand, A> {
337 #[document_signature]
341 #[document_returns("The identity endofunction.")]
343 #[document_examples]
345 fn empty() -> Self {
357 Self::new(<FnBrand as LiftFn>::new(identity))
358 }
359 }
360}
361pub use inner::*;
362
363#[cfg(test)]
364mod tests {
365 use {
366 super::*,
367 crate::{
368 brands::RcFnBrand,
369 classes::*,
370 functions::*,
371 },
372 quickcheck_macros::quickcheck,
373 };
374
375 #[quickcheck]
379 fn semigroup_associativity(val: i32) -> bool {
380 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as LiftFn>::new(|x: i32| {
381 x.wrapping_add(1)
382 }));
383 let g = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as LiftFn>::new(|x: i32| {
384 x.wrapping_mul(2)
385 }));
386 let h = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as LiftFn>::new(|x: i32| {
387 x.wrapping_sub(3)
388 }));
389
390 let lhs = append(f.clone(), append(g.clone(), h.clone()));
391 let rhs = append(append(f, g), h);
392
393 lhs.0(val) == rhs.0(val)
394 }
395
396 #[quickcheck]
400 fn monoid_left_identity(val: i32) -> bool {
401 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as LiftFn>::new(|x: i32| {
402 x.wrapping_add(1)
403 }));
404 let id = empty::<Endofunction<RcFnBrand, i32>>();
405
406 let res = append(id, f.clone());
407 res.0(val) == f.0(val)
408 }
409
410 #[quickcheck]
412 fn monoid_right_identity(val: i32) -> bool {
413 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as LiftFn>::new(|x: i32| {
414 x.wrapping_add(1)
415 }));
416 let id = empty::<Endofunction<RcFnBrand, i32>>();
417
418 let res = append(f.clone(), id);
419 res.0(val) == f.0(val)
420 }
421}