chain_trans/
lib.rs

1//! Library for conveniently combining and applying to structures.
2//!
3//! See [`Trans`] for more info.
4#![no_std]
5
6/// Basic, universal transformations on types.
7///
8/// The `trans*` functions take *owned* structures and return other *owned* structures - i.e. they
9/// are a *transformation* of a structure that acts like a pipeline. Because this consumes the
10/// structures these functions are only implemented on [`Sized`] types.
11///
12/// The `chain*` functions allow you to chain functions that take their argument by reference
13/// (shared or mutually-exclusive), without needing temporary variables. These functions always
14/// return a reference to [`Self`] of some kind, so you can continuously  
15pub trait Trans {
16    /// Apply a transformation function from self to any arbitrary type, consuming `self`.
17    ///
18    /// Allows chaining function calls on an object in-place, similar to how you might use
19    /// [`core::iter::Iterator::map`] but on arbitrary expressions and types.
20    ///
21    /// # Examples
22    ///
23    /// Basic example of operational flow.
24    ///
25    /// ```rust
26    /// use chain_trans::Trans;
27    ///
28    /// let bare_integer = 32;
29    /// let as_some_and_halved = bare_integer
30    ///     .trans(|a| a >> 1)
31    ///     .trans(Some);
32    ///
33    /// assert_eq!(as_some_and_halved, Some(16));
34    /// ```
35    #[inline]
36    fn trans<T>(self, to_apply: impl FnOnce(Self) -> T) -> T
37    where
38        Self: Sized,
39    {
40        to_apply(self)
41    }
42
43    /// Apply a function that works on mutually exclusive references to self as if it were an
44    /// ownership-taking transformation like you would pass to [`Trans::trans`]
45    #[inline]
46    fn trans_mut(mut self, to_apply: impl FnOnce(&mut Self)) -> Self
47    where
48        Self: Sized,
49    {
50        to_apply(&mut self);
51        self
52    }
53
54    /// Apply a function that works on shared references to self as a consuming transformation, in
55    /// the style of [`Trans::trans`]
56    ///
57    /// # Examples
58    /// Easy inline logging.
59    ///
60    /// ```rust
61    /// use chain_trans::Trans;
62    ///
63    /// let final_val = 3u64
64    ///     .trans(|a| a * 3)
65    ///     .trans(|a| a + 4)
66    ///     .trans_inspect(|intermediary_val| eprintln!("Intermediary value is {intermediary_val:#?}"))
67    ///     .trans(|a| a * 2)
68    ///     .trans(Some)
69    ///     .trans_inspect(|final_val| eprintln!("We eventually got {final_val:#?}"));
70    /// ```
71    #[inline]
72    fn trans_inspect(self, to_apply: impl FnOnce(&Self)) -> Self
73    where
74        Self: Sized,
75    {
76        to_apply(&self);
77        self
78    }
79
80    /// Modify the object reference with the given function, returning the object reference
81    /// once again. This turns arbitrary functions into fluent-style calls.
82    ///
83    /// # Examples
84    /// Adding environment variables to a [`std::process::Command`] in-place before spawning.
85    /// ```rust,no_run
86    /// # fn main() -> Result<(), std::io::Error> {
87    /// use chain_trans::Trans;
88    /// use std::process::Command;
89    ///
90    /// pub fn set_my_env_var(cmd: &mut Command) {
91    ///     cmd.env("MY_SPECIAL_VAR", "MY_SPECIAL_VAL");
92    /// }
93    ///
94    /// let mut child_proc = Command::new("ls")
95    ///     .arg("-l")
96    ///     .chain_mut(set_my_env_var)
97    ///     .spawn()?;
98    /// child_proc.wait()?;
99    /// # Ok(())
100    /// # }
101    /// ```
102    #[inline]
103    fn chain_mut(&mut self, to_apply: impl FnOnce(&mut Self)) -> &'_ mut Self {
104        to_apply(self);
105        self
106    }
107
108    #[inline]
109    /// Inspect a shared reference to a structure with a function and
110    /// return the reference again, for easy function chaining. It's uses are
111    /// similar to that of [`Trans::trans_inspect`]
112    fn chain_inspect(&self, to_apply: impl FnOnce(&Self)) -> &'_ Self {
113        to_apply(self);
114        self
115    }
116}
117
118impl<T: ?Sized> Trans for T {}
119
120/// Useful items to include in your dependant crate.
121pub mod prelude {
122    pub use super::Trans;
123}