beet_utils/utils/
pipeline.rs

1/// Basically a `FnOnce` trait, but not nightly and a little less awkward to implement.
2pub trait Pipeline<In, Out = In> {
3	/// Consume self and apply to the target
4	fn apply(self, value: In) -> Out;
5}
6
7impl<F, In, Out> Pipeline<In, Out> for F
8where
9	F: FnOnce(In) -> Out,
10{
11	fn apply(self, value: In) -> Out { self(value) }
12}
13
14
15/// Utilities for method-chaining on any type.
16/// Very similar in its goals to [`tap`](https://crates.io/crates/tap)
17pub trait PipelineTarget: Sized {
18	/// Similar to [`Iterator::map`] but for any type, not just iterators.
19	fn xmap<O>(self, func: impl FnOnce(Self) -> O) -> O { func(self) }
20	/// Similar to [`Iterator::inspect`] but for any type, not just iterators.
21	fn xtap(mut self, func: impl FnOnce(&mut Self)) -> Self {
22		func(&mut self);
23		self
24	}
25	/// just print the value and return it
26	fn xdebug(self) -> Self
27	where
28		Self: std::fmt::Debug,
29	{
30		println!("{:?}", self);
31		self
32	}
33	/// just print the value and return it
34	fn xdisplay(self) -> Self
35	where
36		Self: std::fmt::Display,
37	{
38		println!("{}", self);
39		self
40	}
41	/// Similar to [`Iterator::inspect`] but for any type, not just iterators, and mutable.
42	fn xtap_mut(&mut self, func: impl FnOnce(&mut Self)) -> &mut Self {
43		func(self);
44		self
45	}
46	/// Similar to [`Iterator::map`] but for any type, not just iterators,
47	/// using a custom [`Pipeline`] trait which behaves similarly to a `FnOnce` trait,
48	/// but available on stable rust.
49	fn xpipe<P: Pipeline<Self, O>, O>(self, pipeline: P) -> O {
50		pipeline.apply(self)
51	}
52
53	/// Convenience wrapper for `&self` in method chaining contexts.
54	fn xref(&self) -> &Self { self }
55	/// Convenience wrapper for `&mut self` in method chaining contexts.
56	fn xmut(&mut self) -> &mut Self { self }
57	/// Wraps the value in a [`Result::Ok`]
58	///
59	/// ## Example
60	///
61	/// ```rust
62	/// # use beet_utils::prelude::*;
63	/// assert_eq!("foo".xok::<()>(), Ok("foo"));
64	/// ```
65	fn xok<E>(self) -> Result<Self, E> { Ok(self) }
66	/// Wraps the value in an [`Option::Some`]
67	/// ## Example
68	///
69	/// ```rust
70	/// # use beet_utils::prelude::*;
71	/// assert_eq!("foo".xsome(), Some("foo"));
72	/// ```
73	fn xsome(self) -> Option<Self> { Some(self) }
74
75	/// Convenience wrapper for [`Into::into`].
76	/// ```rust
77	/// # use beet_utils::prelude::*;
78	/// assert_eq!(7_u32.xinto::<u64>(), 7);
79	/// ```
80	fn xinto<T: From<Self>>(self) -> T { T::from(self) }
81}
82impl<T: Sized> PipelineTarget for T {}
83
84
85/// Utilities for method-chaining on any type.
86/// Very similar in its goals to [`tap`](https://crates.io/crates/tap)
87pub trait PipelineTargetIter<T>: Sized + IntoIterator<Item = T> {
88	/// Similar to [`IntoIterator::into_iter().map(func).collect()`]
89	fn xmap_each<O>(self, func: impl FnMut(T) -> O) -> Vec<O> {
90		self.into_iter().map(func).collect()
91	}
92	/// Similar to [`IntoIterator::into_iter().filter_map(func).collect()`]
93	/// but flattens the results.
94	fn xtry_filter_map<O, E>(
95		self,
96		mut func: impl FnMut(T) -> Result<Option<O>, E>,
97	) -> Result<Vec<O>, E> {
98		let mut out = Vec::new();
99		for item in self.into_iter() {
100			match (func)(item) {
101				Ok(Some(o)) => out.push(o),
102				Ok(None) => {}
103				Err(e) => return Err(e),
104			}
105		}
106		Ok(out)
107	}
108}
109
110impl<T: Sized, I: IntoIterator<Item = T>> PipelineTargetIter<T> for I {}
111
112pub trait PipelineTargetVec<T> {
113	/// Similar to [`Vec::extend`] but returns [`Self`]
114	fn xtend<I: IntoIterator<Item = T>>(self, iter: I) -> Self;
115}
116
117impl<T, T2> PipelineTargetVec<T> for T2
118where
119	T2: AsMut<Vec<T>>,
120{
121	fn xtend<I: IntoIterator<Item = T>>(mut self, iter: I) -> Self {
122		self.as_mut().extend(iter);
123		self
124	}
125}
126
127pub trait PipelineTargetString {
128	/// Similar to [`String::push_str`] but returns [`Self`]
129	fn xtend(self, item: impl AsRef<str>) -> Self;
130}
131
132impl PipelineTargetString for String {
133	fn xtend(mut self, item: impl AsRef<str>) -> Self {
134		self.push_str(item.as_ref());
135		self
136	}
137}