# nclosure `nclosure` is a library designed to ease the use of closures and generic, composable computation in APIs where anonymous trait objects, like `impl FnOnce` cannot currently be placed. In particular, it provides an ergonomic method of defining closures such that the *state* embedded within the closure can be separated from the raw `fn` pointer, which can be encoded in the type system with a named type. Furthermore, it provides versions of the `FnOnce`, `FnMut` and `Fn` traits that can be implemented in a custom manner upon structures. This allows for the encoding of composed computation into nameable types, of which this crate provides some, hence allowing for it's use as a return type in areas of code where anonymous types are not yet allowed. # Closure types The primary function of this crate is to enable using traits with functions that provide computations as output or that may require specific, *nameable* representations of computation as input for storage. In this crate, a *closure* refers to a bundle of some specific *state*, along with a separate *function pointer*. Standard rust closures are also essentially this, but each closure is an entirely new, *unnameable* type in Rust, and hence difficult to put into uniform storage without allocation/boxing/dynamic dispatch/etc. The closures in the `nclosure` crate are uniform types such that you can store different function pointers or state values in one closure type. ## [`ClosureOnce`] This type is a closure that can only be called once, and it consumes it's inner state. Remember, though - the inner state of the closure is able to hold things like references just fine. It is what you almost always want for any one-shot computation. ## [`ClosureMut`] This is a closure that can be called repeatedly to generate values, mutating it's inner state - this means that calling it requires exclusive references to the closure. If you just need to hold a reference for a single computation, [`ClosureOnce`] will do just fine. ## [`Closure`] This holds a bare computation that can be called repeatedly without holding an exclusive reference to it's internal state, including stuff like cross threads. This is the most general form of closure - it could own it's state or it could hold some other reference. # Traits As a consequence of the current inability to define your own [`Fn`] , [`FnMut`] , and [`FnOnce`] implementations on custom types - like the various closure types defined here - this crate also defines it's own custom computation types that are a superset of the built-in types as a workaround (in particular, [`Co`] , [`CoMut`] and [`CoOnce`] , which are automatically implemented for the Rust core traits). These can be freely converted to the Rust core impl-trait types using [`as_fn_once`] , [`as_fn_mut`] , and [`as_fn`] . # Examples Section containing example usages of this crate. The benefit of using this crate is that the resulting computation type is nameable solely in terms of inner state, arguments, and return values - as opposed to being an opaque `impl FnMut` type. This enables several things. Not only does it make it easier to define storage for closures, it also allows easier usage of automatically derived (or otherwise) traits - for instance, with respect to thread synchronisation and `Co`/`CoMut`/`CoOnce`. In particular, the compositional methods provided by this trait preserve the repeatability (`Co` vs `CoMut` vs `CoOnce`) of their generic parameters, which means that a single method can preserve the repeatability of arbitrary composition of functions because the resulting composition is itself a named type rather than an anonymous `impl Fn`/`impl FnMut`/`impl FnOnce` type. ## Closure Constructions Some examples of how to ergonomically construct nameable closures using this crate. ### Counter The first example is the construction of a closure that generates increasing values, illustrating the simple means of constructing a closure state. ```rust use nclosure::prelude::*; /// Count from the given number upwards. pub fn count_from(a: usize) -> ClosureMut { single_closure_state(a) .finalise_mut(|count, ()| { let result = *count; *count += 1; result }) } // Note that unfortunately we have to provide an empty tuple argument, because the computation traits have their arguments as a tuple. let mut counter = count_from(5).as_fn_mut(); let first = counter(()); let second = counter(()); let third = counter(()); assert_eq!((first, second, third), (5, 6, 7)) ``` ### Fibonacci This demonstrates the construction of a more complex closure state using the fluent API, to produce the fibonacci sequence. ```rust use nclosure::prelude::*; /// Make a function that generates the Fibonacci sequence, starting from 0 pub fn fibonacci() -> ClosureMut<(usize, usize), (), usize> { // Note the way this fluently creates a tuple closure_state().and(0).and(1) // And the way this fluently accesses it by mutable reference to each component // with names. // If you keep the names of state parameters aligned with the arguments to // this function you can get near-native closure ergonomics feel. .finalise_mut(|(current, next), ()| { let result = *current; (*current, *next) = (*next, *next + *current); result }) } let mut fibgen = fibonacci().as_fn_mut(); let vals = [fibgen(()), fibgen(()), fibgen(()), fibgen(()), fibgen(()), fibgen(())]; assert_eq!(vals, [0usize, 1, 1, 2, 3, 5]); ``` ## Closure Composition One of the useful aspects of this crate is the clean composition of computation and state, in a manner that produces nameable types. This section illustrates methods for doing that. ### Chaining Closures (Squared Counter) This illustrates an example of chaining closures together in a nameable fashion. ```rust use nclosure::prelude::*; use core::ops::Mul; pub fn counter() -> ClosureMut { single_closure_state(0usize) .finalise_mut(|ctr, ()| { let res = *ctr; *ctr += 1; res }) } /// Square the output of a function /// Note here that the output type is actually *named*, which enables /// some very useful properties. In particular, if the input computation /// implements `Co` or `CoMut` instead of just `CoOnce`, then the /// composed computation will also implement those traits (at least as /// long as the chained computations also implement them). pub fn square_result>(input_computation: IC) -> nclosure::Chain<(IC, fn(IC::Output) -> ::Output)> where IC::Output: Mul + Copy { input_computation.and_then(|v| v * v) } // Note how when the counter is `CoMut`, the resulting function is also. let mut squared_ctr = square_result(counter()).as_fn_mut(); let vals = [squared_ctr(()), squared_ctr(()), squared_ctr(()), squared_ctr(())]; assert_eq!(vals, [0usize, 1, 4, 9]) ```