beet_utils/
xtend.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 Xtend: Sized {
18	/// Similar to [`Iterator::map`] but for any type, not just iterators,
19	/// allowing for method chaining.
20	fn xmap<O>(self, func: impl FnOnce(Self) -> O) -> O { func(self) }
21	/// Similar to [`Iterator::inspect`] but for any type, not just iterators.
22	fn xtap(mut self, func: impl FnOnce(&mut Self)) -> Self {
23		func(&mut self);
24		self
25	}
26	/// just print the value and return it
27	fn xprint(self) -> Self
28	where
29		Self: std::fmt::Display,
30	{
31		println!("{}", self);
32		self
33	}
34	/// just print the value and return it, debug
35	fn xprint_debug(self) -> Self
36	where
37		Self: std::fmt::Debug,
38	{
39		println!("{:?}", self);
40		self
41	}
42	/// just print the value and return it, debug formatted
43	fn xprint_debug_formatted(self, prefix: impl AsRef<str>) -> Self
44	where
45		Self: std::fmt::Debug,
46	{
47		println!("{}: {:#?}", prefix.as_ref(), self);
48		self
49	}
50	/// Similar to [`Iterator::inspect`] but for any type, not just iterators, and mutable.
51	fn xtap_mut(&mut self, func: impl FnOnce(&mut Self)) -> &mut Self {
52		func(self);
53		self
54	}
55	/// Similar to [`Iterator::map`] but for any type, not just iterators,
56	/// using a custom [`Pipeline`] trait which behaves similarly to a `FnOnce` trait,
57	/// but available on stable rust.
58	fn xpipe<P: Pipeline<Self, O>, O>(self, pipeline: P) -> O {
59		pipeline.apply(self)
60	}
61
62	/// Convenience wrapper for `&self` in method chaining contexts.
63	fn xref(&self) -> &Self { self }
64	/// Convenience wrapper for `&mut self` in method chaining contexts.
65	fn xmut(&mut self) -> &mut Self { self }
66	/// Wraps the value in a [`Result::Ok`]
67	///
68	/// ## Example
69	///
70	/// ```rust
71	/// # use beet_utils::prelude::*;
72	/// assert_eq!("foo".xok::<()>(), Ok("foo"));
73	/// ```
74	fn xok<E>(self) -> Result<Self, E> { Ok(self) }
75	/// Wraps the value in an [`Option::Some`]
76	/// ## Example
77	///
78	/// ```rust
79	/// # use beet_utils::prelude::*;
80	/// assert_eq!("foo".xsome(), Some("foo"));
81	/// ```
82	fn xsome(self) -> Option<Self> { Some(self) }
83
84	/// Convenience wrapper for [`Into::into`].
85	/// ```rust
86	/// # use beet_utils::prelude::*;
87	/// assert_eq!(7_u32.xinto::<u64>(), 7);
88	/// ```
89	fn xinto<T: From<Self>>(self) -> T { T::from(self) }
90
91	/// Return a `String` containing the `Debug` representation of the value.
92	///
93	/// Unlike `xdebug` which prints the value to stdout and returns the value,
94	/// this method returns the formatted debug string.
95	fn xfmt_debug(&self) -> String
96	where
97		Self: std::fmt::Debug,
98	{
99		format!("{:?}", self)
100	}
101
102	/// Return a `String` containing the `Display` representation of the value.
103	///
104	/// Similar to `xfmt_debug`, but uses the `Display` formatting instead of `Debug`.
105	fn xfmt(&self) -> String
106	where
107		Self: std::fmt::Display,
108	{
109		format!("{}", self)
110	}
111}
112impl<T: Sized> Xtend for T {}
113
114
115/// Utilities for method-chaining on any type.
116/// Very similar in its goals to [`tap`](https://crates.io/crates/tap)
117pub trait XtendIter<T>: Sized + IntoIterator<Item = T> {
118	/// Similar to [`IntoIterator::into_iter().map(func).collect()`]
119	fn xmap_each<O>(self, func: impl FnMut(T) -> O) -> Vec<O> {
120		self.into_iter().map(func).collect()
121	}
122	/// Similar to [`IntoIterator::into_iter().filter_map(func).collect()`]
123	/// but flattens the results.
124	fn xtry_filter_map<O, E>(
125		self,
126		mut func: impl FnMut(T) -> Result<Option<O>, E>,
127	) -> Result<Vec<O>, E> {
128		let mut out = Vec::new();
129		for item in self.into_iter() {
130			match (func)(item) {
131				Ok(Some(o)) => out.push(o),
132				Ok(None) => {}
133				Err(e) => return Err(e),
134			}
135		}
136		Ok(out)
137	}
138}
139
140#[extend::ext(name=XtendBool)]
141pub impl bool {
142	/// Runs the function if `self` is true
143	fn xmap_true<O>(&self, func: impl FnOnce() -> O) -> Option<O> {
144		if *self { Some(func()) } else { None }
145	}
146	/// Runs the function if `self` is false
147	fn xmap_false<O>(&self, func: impl FnOnce() -> O) -> Option<O> {
148		if !*self { Some(func()) } else { None }
149	}
150}
151impl<T: Sized, I: IntoIterator<Item = T>> XtendIter<T> for I {}
152
153
154pub trait XtendVec<T> {
155	/// Similar to [`Vec::extend`] but returns [`Self`]
156	fn xtend<I: IntoIterator<Item = T>>(self, iter: I) -> Self;
157	/// Similar to [`Vec::push`] but returns [`Self`]
158	fn xpush(self, item: T) -> Self;
159}
160
161impl<T, T2> XtendVec<T> for T2
162where
163	T2: AsMut<Vec<T>>,
164{
165	fn xtend<I: IntoIterator<Item = T>>(mut self, iter: I) -> Self {
166		self.as_mut().extend(iter);
167		self
168	}
169
170	fn xpush(mut self, item: T) -> Self {
171		self.as_mut().push(item);
172		self
173	}
174}
175
176pub trait XtendString {
177	/// Similar to [`String::push_str`] but returns [`Self`]
178	fn xtend(self, item: impl AsRef<str>) -> Self;
179}
180
181impl XtendString for String {
182	fn xtend(mut self, item: impl AsRef<str>) -> Self {
183		self.push_str(item.as_ref());
184		self
185	}
186}