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}