nclosure 0.1.0

Provides composable, nameable closure types with separated states and functionality for use in APIs where anonymous types are unavailable
Documentation
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
#![doc = include_str!("../README.md")]
#![no_std]
// Automatic feature docs.
#![cfg_attr(doc, feature(doc_auto_cfg))]

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(feature = "std")]
extern crate std;

/// A closure containing bundled state, that takes the given arguments and produces the given
/// output.
///
/// If you need a computation that can be repeated, take a look at [`ClosureMut`] and [`Closure`].
/// If you just need to modify some external state once - that you have an external reference to -
/// you can use a normal mutable reference as the state just fine.
#[derive(Clone, Copy, Debug)]
pub struct ClosureOnce<S, Args, Out> {
    /// The internal state bundled with the computation.
    state: S,
    computation: fn(S, Args) -> Out,
}

impl<S, A, O> ClosureOnce<S, A, O> {
    /// Construct the closure from state and operation.
    ///
    /// [`state_builder::ClosureState`] and [`closure_state`] provide convenience methods for building up closure
    /// states. This lets you create a closure directly.
    pub fn new(s: S, operation: impl Into<fn(S, A) -> O>) -> Self {
        Self {
            state: s,
            computation: operation.into(),
        }
    }
    
    /// Construct a normal rust closure from this. Convenience function for [`crate::as_fn_once`]
    #[inline(always)]
    pub fn as_fn_once(self) -> impl FnOnce(A) -> O {
        as_fn_once(self)
    }  
}

/// A closure containing bundled state, that can be generically mutated when generating output.
///
/// Note that because we store a bare function pointer, there is no clean way to have an output
/// dependent on the input. As such, you *can't* return references to the state that only last as
/// long as the closure. This closure can be repeatedly called.
#[derive(Clone, Copy)]
pub struct ClosureMut<S, Args, Out> {
    state: S,
    computation: fn(&mut S, Args) -> Out,
}

impl<S, A, O> ClosureMut<S, A, O> {
    /// Construct the closure from state and operation.
    ///
    /// [`state_builder::ClosureState`] and [`closure_state`] provide convenience methods for building up closure
    /// states. This lets you create a closure directly.
    pub fn new(s: S, operation: impl Into<fn(&mut S, A) -> O>) -> Self {
        Self {
            state: s,
            computation: operation.into(),
        }
    }

    
    /// Construct a normal rust closure from this. Convenience function for [`crate::as_fn_mut`]
    #[inline(always)]
    pub fn as_fn_mut(self) -> impl FnMut(A) -> O {
        as_fn_mut(self)
    }  
}

/// A closure containing bundled state, that can be called repeatedly on an shared reference to
/// it's internal state.
///
/// For cases where the closure must consume the state or otherwise should only be performed once, see [`ClosureOnce`].
/// For cases where the closure can change the state as it is called repeatedly, see [`ClosureMut`].
#[derive(Clone, Copy)]
pub struct Closure<S, Args, Out> {
    state: S,
    computation: fn(&S, Args) -> Out,
}

impl<S, A, O> Closure<S, A, O> {
    /// Construct the closure from state and operation.
    ///
    /// [`state_builder::ClosureState`] and [`closure_state`] provide convenience methods for building up closure
    /// states. This lets you create a closure directly.
    pub fn new(s: S, operation: impl Into<fn(&S, A) -> O>) -> Self {
        Self {
            state: s,
            computation: operation.into(),
        }
    }

    /// Construct a normal rust closure from this. Convenience function for [`crate::as_fn`]
    #[inline(always)]
    pub fn as_fn(self) -> impl Fn(A) -> O {
        as_fn(self)
    }  
}

/// Replacement for [`FnOnce`] - representing a single bundled computation - until that can be manually
/// implemented. Designed to use the same API.
///
/// Automatically implemented for all [`FnOnce`].
pub trait CoOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}

/// Replacement for [`FnOnce`] - representing a repeatable bundled computation that mutates state -
/// until that can be manually implemented. Designed to use the same API as [`FnMut`], even though
/// it somewhat restricts dependency on internal state in returned references (in particular, due
/// to lack of a generic-associated-type parameterised on self-lifetime).
///
/// Automatically implemented for all [`FnMut`].
pub trait CoMut<Args>: CoOnce<Args> {
    fn call_mut(&mut self, args: Args) -> Self::Output;
}

/// Replacement for [`Fn`] - representing a repeatable bundled computation without mutation, until
/// the standard trait can be manually implemented. Designed to use the same API as [`Fn`], even
/// though it somewhat restricts dependency on internal computational state in returned references
/// (which would be usable if we allowed the usage of a self-lifetime-parameter for a
/// generic-associated-type).
///
/// Automatically implemented for all [`Fn`]
pub trait Co<Args>: CoMut<Args> {
    fn call(&self, args: Args) -> Self::Output;
}

impl<A, O, F: FnOnce(A) -> O> CoOnce<A> for F {
    type Output = O;

    #[inline(always)]
    fn call_once(self, args: A) -> Self::Output {
        (self)(args)
    }
}

impl<A, O, F: FnMut(A) -> O> CoMut<A> for F {
    #[inline(always)]
    fn call_mut(&mut self, args: A) -> Self::Output {
        (self)(args)
    }
}

impl<A, O, F: Fn(A) -> O> Co<A> for F {
    #[inline(always)]
    fn call(&self, args: A) -> Self::Output {
        (self)(args)
    }
}



impl<S, A, O> CoOnce<A> for ClosureOnce<S, A, O> {
    type Output = O;

    #[inline(always)]
    fn call_once(self, args: A) -> Self::Output {
        (self.computation)(self.state, args)
    }
}

impl<S, A, O> CoOnce<A> for ClosureMut<S, A, O> {
    type Output = O;

    #[inline(always)]
    fn call_once(mut self, args: A) -> Self::Output {
        (self.computation)(&mut self.state, args)
    }
}
impl<S, A, O> CoMut<A> for ClosureMut<S, A, O> {
    #[inline(always)]
    fn call_mut(&mut self, args: A) -> Self::Output {
        (self.computation)(&mut self.state, args)
    }
}

impl<S, A, O> CoOnce<A> for Closure<S, A, O> {
    type Output = O;

    #[inline(always)]
    fn call_once(self, args: A) -> Self::Output {
        (self.computation)(&self.state, args)
    }
}
impl<S, A, O> CoMut<A> for Closure<S, A, O> {
    #[inline(always)]
    fn call_mut(&mut self, args: A) -> Self::Output {
        (self.computation)(&self.state, args)
    }
}
impl<S, A, O> Co<A> for Closure<S, A, O> {
    #[inline(always)]
    fn call(&self, args: A) -> Self::Output {
        (self.computation)(&self.state, args)
    }
}

/// Start building a closure state.
///
/// This is useful, because fluent APIs are provided for closure states containing tuples, to avoid
/// lots of nested tuple parameters when providing multiple state components. See
/// [`state_builder::ClosureState`] for more details.
#[inline(always)]
pub const fn closure_state() -> state_builder::ClosureState<()> {
    state_builder::ClosureState(())
}

/// Build a simple single-value closure state.
///
/// If you only have one value in your closure state, this provides an easier API and 
/// type signature than [`closure_state`].
///
/// If you later find that you need more than one value in your closure state, have a look
/// at [`state_builder::ClosureState::as_tuple`], which will wrap a value inside a singlet tuple
/// such that you can then use the fluent APIs mentioned in [`closure_state`].
pub const fn single_closure_state<S>(s: S) -> state_builder::ClosureState<S> {
    state_builder::ClosureState(s)
}

/// Utilities for building and finalising closure state ergonomically.
pub mod state_builder {
    use super::{Closure, ClosureMut, ClosureOnce};

    #[derive(Clone, Copy, Debug, Default)]
    /// Closure state constructor.
    pub struct ClosureState<S>(pub S);
    impl<S> ClosureState<S> {
        /// Construct a new closure builder state.
        #[inline]
        pub const fn with_state(s: S) -> Self {
            Self(s)
        }

        /// Wrap a single value as a singlet tuple for the fluent APIs
        #[inline]
        pub fn as_tuple(self) -> ClosureState<(S,)> {
            ClosureState::with_state((self.0,))
        }

        /// Finalise the state with a function to run as a repeatable closure.
        ///
        /// Use when you want to build a [`Closure`]. This can also be provided a non capturing
        /// rust closure as a parameter using [*closure to fn coercion*][ctfcoerce], which should
        /// enable good ergonomics.
        ///
        /// [ctfcoerce]: https://rust-lang.github.io/rfcs/1558-closure-to-fn-coercion.html
        #[inline]
        pub fn finalise<A, O>(self, fin: fn(&S, A) -> O) -> Closure<S, A, O> {
            Closure::new(self.0, fin) 
        }

        /// Finalise the state with a function to run as a repeatable closure that can exclusively
        /// access the internal state for mutation.
        ///
        /// Use when you want to build a [`ClosureMut`]. This can also be provided a non-capturing
        /// rust closure as a parameter using [*closure to fn coercion*][ctfcoerce] for good
        /// ergonomics.
        ///
        /// [ctfcoerce]: https://rust-lang.github.io/rfcs/1558-closure-to-fn-coercion.html
        #[inline]
        pub fn finalise_mut<A, O>(self, fin: fn(&mut S, A) -> O) -> ClosureMut<S, A, O> {
            ClosureMut::new(self.0, fin)
        }

        /// Finalise the state with a consuming function that takes the state and arguments in
        /// an owning manner.
        ///
        /// Use when you want to build a [`ClosureOnce`]. This can also be provided a non-capturing
        /// rust closure as a parameter using [*closure to fn coercion*][ctfcoerce] for good
        /// ergonomics.
        ///
        /// [ctfcoerce]: https://rust-lang.github.io/rfcs/1558-closure-to-fn-coercion.html
        #[inline]
        pub fn finalise_once<A, O>(self, fin: fn(S, A) -> O) -> ClosureOnce<S, A, O> {
            ClosureOnce::new(self.0, fin)
        } 
    }

    impl ClosureState<()> {
        /// Add another stateful parameter.
        #[inline(always)]
        pub const fn and<TX>(self, other: TX) -> ClosureState<(TX,)> {
            ClosureState::with_state((other,))
        }
    }

    /// Generate non-nested tuple extension methods for closure states. This operation is done
    /// recursively. Parameter names are peeled off backwards, but that doesn't really matter as long
    /// as the new one is constructed with the same order the old was deconstructed.
    macro_rules! tuple_closure_state_flat{
        ($first_param_name:ident $($existing_params:ident)*) => {
            impl <$($existing_params,)* $first_param_name> ClosureState<($($existing_params,)* $first_param_name,)> {
                /// Add another stateful parameter.
                ///
                /// Note this function is *not* const, because it deconstructs self even though the
                /// values themselves are left alone.
                #[inline(always)]
                // Macro and reusing names makes things easier.
                #[allow(non_snake_case)]
                pub fn and<TX>(self, n: TX) -> ClosureState<($($existing_params,)* $first_param_name, TX,)> {
                    let ($($existing_params,)* $first_param_name,) = self.0;
                    ClosureState(($($existing_params,)* $first_param_name, n))
                }
            }

            tuple_closure_state_flat!{$($existing_params)*}
        };
        // no more tuples.
        {} => {}
    }

    tuple_closure_state_flat! {T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10}

}


/// Module for composition of computation. For example, the ability to chain a number of arbitrary
/// computation bundles together.
///
/// Note that these *will* blow up the stack if you aren't careful, but the defined
/// combined-computation structures contain intrinsic methods that ensure that structures do not
/// have deeply-nested generic type parameters.
pub mod compose {
    use super::{Co, CoMut, CoOnce};

    /// Represents an arbitrary number of computations chained into each other.
    ///
    /// The type parameter is a tuple consisting of a list of computations. Intrinsic methods are
    /// provided that shadow the methods on various extension traits for chaining, so that there is
    /// less deep recursion in type parameters when chaining many computations together.
    ///
    /// Note that generally these methods do not have type constraints, those are applied to
    /// implementations of traits rather than on a type level - like how the stdlib does for it's
    /// own data structures. This is to ease interaction between the [`Co`], [`CoMut`], and  [`CoOnce`]
    /// variations on traits by having a unified interface for each.
    #[derive(Clone, Copy)]
    pub struct Chain<ComputationTuple>(pub ComputationTuple);

    /// Generate implementations of Co/CoMut/CoOnce
    macro_rules! chain {
        {$first_type_param:ident $last_type_param:ident $($type_param:ident($previous_output_param:ident))*}  => {
            impl<$first_type_param, $($type_param,)* > Chain<($first_type_param, $($type_param,)*)>  {
                /// Chain a new computation after this one.
                #[inline(always)]
                #[allow(non_snake_case)]
                pub fn and_then<TX>(self, next: TX) -> Chain<($first_type_param, $($type_param,)* TX)> {
                    let ($first_type_param, $($type_param,)*) = self.0;
                    Chain(($first_type_param, $($type_param,)* next))
                }

                #[inline]
                /// Convenience function that converts into a standard rust closure.
                ///
                /// Like [`crate::as_fn_once`]
                pub fn as_fn_once<Args>(self) -> impl FnOnce(Args) -> <Self as CoOnce<Args>>::Output where Self: CoOnce<Args> {
                    crate::as_fn_once(self)
                } 
                
                #[inline]
                /// Convenience function that converts into a standard rust closure.
                ///
                /// Like [`crate::as_fn_mut`]
                pub fn as_fn_mut<Args>(self) -> impl FnMut(Args) -> <Self as CoOnce<Args>>::Output where Self: CoMut<Args> {
                    crate::as_fn_mut(self)
                } 
                
                #[inline]
                /// Convenience function that converts into a standard rust closure.
                ///
                /// Like [`crate::as_fn`]
                pub fn as_fn<Args>(self) -> impl Fn(Args) -> <Self as CoOnce<Args>>::Output where Self: Co<Args> {
                    crate::as_fn(self)
                } 
            }

            impl <
                A,
                $first_type_param: CoOnce<A>,
                $($type_param : CoOnce<$previous_output_param::Output>,)*
            > CoOnce<A> for Chain<($first_type_param, $($type_param,)*)> {
                type Output = $last_type_param::Output;

                #[inline]
                #[allow(non_snake_case)]
                fn call_once(self, args: A) -> Self::Output {
                    let Self(($first_type_param, $($type_param,)*)) = self;
                    let args = $first_type_param.call_once(args);
                    $(
                        let args = $type_param.call_once(args);
                    )*
                    args
                }
            }

            impl <
                A,
                $first_type_param: CoMut<A>,
                $($type_param : CoMut<$previous_output_param::Output>,)*
            > CoMut<A> for Chain<($first_type_param, $($type_param,)*)> {
                #[inline]
                #[allow(non_snake_case)]
                fn call_mut(&mut self, args: A) -> Self::Output {
                    let Self(($first_type_param, $($type_param,)*)) = self;
                    let args = $first_type_param.call_mut(args);
                    $(
                        let args = $type_param.call_mut(args);
                    )*
                    args
                }
            }


            impl <
                A,
                $first_type_param: Co<A>,
                $($type_param : Co<$previous_output_param::Output>,)*
            > Co<A> for Chain<($first_type_param, $($type_param,)*)> {
                #[inline]
                #[allow(non_snake_case)]
                fn call(&self, args: A) -> Self::Output {
                    let Self(($first_type_param, $($type_param,)*)) = self;
                    let args = $first_type_param.call(args);
                    $(
                        let args = $type_param.call(args);
                    )*
                    args
                }
            }
        }
    }

    chain! {T0 T11 T1(T0) T2(T1) T3(T2) T4(T3) T5(T4) T6(T5) T7(T6) T8(T7) T9(T8) T10(T9) T11(T10)}
    chain! {T0 T10 T1(T0) T2(T1) T3(T2) T4(T3) T5(T4) T6(T5) T7(T6) T8(T7) T9(T8) T10(T9)}
    chain! {T0 T9 T1(T0) T2(T1) T3(T2) T4(T3) T5(T4) T6(T5) T7(T6) T8(T7) T9(T8)}
    chain! {T0 T8 T1(T0) T2(T1) T3(T2) T4(T3) T5(T4) T6(T5) T7(T6) T8(T7)}
    chain! {T0 T7 T1(T0) T2(T1) T3(T2) T4(T3) T5(T4) T6(T5) T7(T6)}
    chain! {T0 T6 T1(T0) T2(T1) T3(T2) T4(T3) T5(T4) T6(T5)}
    chain! {T0 T5 T1(T0) T2(T1) T3(T2) T4(T3) T5(T4)}
    chain! {T0 T4 T1(T0) T2(T1) T3(T2) T4(T3)}
    chain! {T0 T3 T1(T0) T2(T1) T3(T2)}
    chain! {T0 T2 T1(T0) T2(T1)}
    chain! {T0 T1 T1(T0)}


    /// Universal extension trait for any computation (all computations implement `CoOnce` by
    /// proxy). Contains utility methods for easy composition.
    pub trait CoOnceExt<Arg>: CoOnce<Arg> {
        #[inline(always)]
        /// Perform another computation upon the output of this one.
        fn and_then<T>(self, other: T) -> Chain<(Self, T)>
        where
            Self: Sized,
        {
            Chain((self, other))
        }
    }

    impl<Arg, T: CoOnce<Arg>> CoOnceExt<Arg> for T {}
}

// Get the implementations out of the inner module for easier access
pub use compose::Chain;

/// Convert [`CoOnce`] into [`FnOnce`].
#[inline(always)]
pub fn as_fn_once<Arg, T: CoOnce<Arg>>(t: T) -> impl FnOnce(Arg) -> T::Output {
    move |a| t.call_once(a)
}

/// Convert [`CoMut`] into [`FnMut`]
#[inline(always)]
pub fn as_fn_mut<Arg, T: CoMut<Arg>>(mut t: T) -> impl FnMut(Arg) -> T::Output {
    move |a| t.call_mut(a)
}

/// Convert [`Co`] into [`Fn`]
#[inline(always)]
pub fn as_fn<Arg, T: Co<Arg>>(t: T) -> impl Fn(Arg) -> T::Output {
    move |a| t.call(a)
}

/// Common utility stuff.
///
/// Mostly uses traits and the closure types.
pub mod prelude {
    pub use super::{
        closure_state, single_closure_state, compose::CoOnceExt as _, Closure, ClosureMut, ClosureOnce, Co, CoMut, CoOnce,
    };
}

// MIT License
//
// Copyright (c) 2022 Matti Bryce <mattibryce at protonmail dot com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.