1#[fp_macros::document_module]
6mod inner {
7 use crate::{
8 classes::{CloneableFn, Monoid, Semigroup},
9 functions::identity,
10 };
11 use fp_macros::{document_fields, document_parameters, document_type_parameters};
12 use std::{
13 fmt::{self, Debug, Formatter},
14 hash::Hash,
15 };
16
17 #[document_type_parameters(
31 "The lifetime of the function and its captured data.",
32 "The brand of the cloneable function wrapper.",
33 "The input and output type of the function."
34 )]
35 #[document_fields("The wrapped function.")]
39 pub struct Endofunction<'a, FnBrand: CloneableFn, A>(
49 pub <FnBrand as CloneableFn>::Of<'a, A, A>,
50 );
51
52 #[document_type_parameters(
53 "The lifetime of the function and its captured data.",
54 "The brand of the function (e.g., `RcFnBrand`).",
55 "The input and output type of the function."
56 )]
57 impl<'a, FnBrand: CloneableFn, A> Endofunction<'a, FnBrand, A> {
58 #[document_signature]
65 #[document_parameters("The function to wrap.")]
69 pub fn new(f: <FnBrand as CloneableFn>::Of<'a, A, A>) -> Self {
83 Self(f)
84 }
85 }
86
87 #[document_type_parameters(
90 "The lifetime of the function and its captured data.",
91 "The brand of the function (e.g., `RcFnBrand`).",
92 "The input and output type of the function."
93 )]
94 #[document_parameters("The function to clone.")]
95 impl<'a, FnBrand: CloneableFn, A> Clone for Endofunction<'a, FnBrand, A> {
96 #[document_signature]
99 fn clone(&self) -> Self {
100 Self::new(self.0.clone())
101 }
102 }
103
104 #[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> Debug for Endofunction<'a, FnBrand, A>
113 where
114 <FnBrand as CloneableFn>::Of<'a, A, A>: Debug,
115 {
116 #[document_signature]
119 #[document_parameters("The formatter to use.")]
123 fn fmt(
124 &self,
125 fmt: &mut Formatter<'_>,
126 ) -> fmt::Result {
127 fmt.debug_tuple("Endofunction").field(&self.0).finish()
128 }
129 }
130
131 #[document_type_parameters(
134 "The lifetime of the function and its captured data.",
135 "The brand of the function (e.g., `RcFnBrand`).",
136 "The input and output type of the function."
137 )]
138 impl<'a, FnBrand: CloneableFn, A> Eq for Endofunction<'a, FnBrand, A> where
139 <FnBrand as CloneableFn>::Of<'a, A, A>: Eq
140 {
141 }
142
143 #[document_type_parameters(
146 "The lifetime of the function and its captured data.",
147 "The brand of the function (e.g., `RcFnBrand`).",
148 "The input and output type of the function."
149 )]
150 #[document_parameters("The function to hash.")]
151 impl<'a, FnBrand: CloneableFn, A> Hash for Endofunction<'a, FnBrand, A>
152 where
153 <FnBrand as CloneableFn>::Of<'a, A, A>: Hash,
154 {
155 #[document_signature]
158 #[document_type_parameters("The type of the hasher.")]
162 #[document_parameters("The hasher state to update.")]
166 fn hash<H: std::hash::Hasher>(
167 &self,
168 state: &mut H,
169 ) {
170 self.0.hash(state);
171 }
172 }
173
174 #[document_type_parameters(
177 "The lifetime of the function and its captured data.",
178 "The brand of the function (e.g., `RcFnBrand`).",
179 "The input and output type of the function."
180 )]
181 #[document_parameters("The function to compare.")]
182 impl<'a, FnBrand: CloneableFn, A> Ord for Endofunction<'a, FnBrand, A>
183 where
184 <FnBrand as CloneableFn>::Of<'a, A, A>: Ord,
185 {
186 #[document_signature]
189 #[document_parameters("The other function to compare to.")]
193 fn cmp(
194 &self,
195 other: &Self,
196 ) -> std::cmp::Ordering {
197 self.0.cmp(&other.0)
198 }
199 }
200
201 #[document_type_parameters(
204 "The lifetime of the function and its captured data.",
205 "The brand of the function (e.g., `RcFnBrand`).",
206 "The input and output type of the function."
207 )]
208 #[document_parameters("The function to compare.")]
209 impl<'a, FnBrand: CloneableFn, A> PartialEq for Endofunction<'a, FnBrand, A>
210 where
211 <FnBrand as CloneableFn>::Of<'a, A, A>: PartialEq,
212 {
213 #[document_signature]
216 #[document_parameters("The other function to compare to.")]
220 fn eq(
221 &self,
222 other: &Self,
223 ) -> bool {
224 self.0 == other.0
225 }
226 }
227
228 #[document_type_parameters(
231 "The lifetime of the function and its captured data.",
232 "The brand of the function (e.g., `RcFnBrand`).",
233 "The input and output type of the function."
234 )]
235 #[document_parameters("The function to compare.")]
236 impl<'a, FnBrand: CloneableFn, A> PartialOrd for Endofunction<'a, FnBrand, A>
237 where
238 <FnBrand as CloneableFn>::Of<'a, A, A>: PartialOrd,
239 {
240 #[document_signature]
243 #[document_parameters("The other function to compare to.")]
247 fn partial_cmp(
248 &self,
249 other: &Self,
250 ) -> Option<std::cmp::Ordering> {
251 self.0.partial_cmp(&other.0)
252 }
253 }
254
255 #[document_type_parameters(
258 "The lifetime of the function and its captured data.",
259 "The brand of the function (e.g., `RcFnBrand`).",
260 "The input and output type of the function."
261 )]
262 impl<'a, FnBrand: 'a + CloneableFn, A: 'a> Semigroup for Endofunction<'a, FnBrand, A> {
263 #[document_signature]
272 #[document_parameters(
276 "The second function to apply (the outer function).",
277 "The first function to apply (the inner function)."
278 )]
279 fn append(
297 a: Self,
298 b: Self,
299 ) -> Self {
300 let f = a.0;
301 let g = b.0;
302 Self::new(<FnBrand as CloneableFn>::new(move |x| f(g(x))))
304 }
305 }
306
307 #[document_type_parameters(
310 "The lifetime of the function and its captured data.",
311 "The brand of the function (e.g., `RcFnBrand`).",
312 "The input and output type of the function."
313 )]
314 impl<'a, FnBrand: 'a + CloneableFn, A: 'a> Monoid for Endofunction<'a, FnBrand, A> {
315 #[document_signature]
322 fn empty() -> Self {
336 Self::new(<FnBrand as CloneableFn>::new(identity))
337 }
338 }
339}
340pub use inner::*;
341
342#[cfg(test)]
343mod tests {
344 use super::*;
345 use crate::{
346 brands::RcFnBrand,
347 classes::{cloneable_fn::CloneableFn, monoid::empty, semigroup::append},
348 };
349 use quickcheck_macros::quickcheck;
350
351 #[quickcheck]
355 fn semigroup_associativity(val: i32) -> bool {
356 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
357 x.wrapping_add(1)
358 }));
359 let g = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
360 x.wrapping_mul(2)
361 }));
362 let h = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
363 x.wrapping_sub(3)
364 }));
365
366 let lhs = append(f.clone(), append(g.clone(), h.clone()));
367 let rhs = append(append(f, g), h);
368
369 lhs.0(val) == rhs.0(val)
370 }
371
372 #[quickcheck]
376 fn monoid_left_identity(val: i32) -> bool {
377 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
378 x.wrapping_add(1)
379 }));
380 let id = empty::<Endofunction<RcFnBrand, i32>>();
381
382 let res = append(id, f.clone());
383 res.0(val) == f.0(val)
384 }
385
386 #[quickcheck]
388 fn monoid_right_identity(val: i32) -> bool {
389 let f = Endofunction::<RcFnBrand, _>::new(<RcFnBrand as CloneableFn>::new(|x: i32| {
390 x.wrapping_add(1)
391 }));
392 let id = empty::<Endofunction<RcFnBrand, i32>>();
393
394 let res = append(f.clone(), id);
395 res.0(val) == f.0(val)
396 }
397}