amonoid/
borrowed.rs

1use std::borrow::{Borrow, Cow};
2use std::ffi::{OsStr, OsString};
3
4use crate::Monoid;
5
6/// A [`Borrow`] of a [`Monoid`].
7///
8/// This is a precursor to [`MonoidBorrowed`], hence the name.
9///
10/// This trait can be implemented when the assignment `Self -> Self::MonoidOwned` is unique,
11/// but it doesn't require `Self: ToOwned`, so it can be implemented for every monoid
12/// (not just for `M: Clone`).
13///
14/// Note that the `Self` type for this is what's _inside_ a reference,
15/// not the reference itself. For example, this is implemented on `str`, not `&'a str`.
16pub trait PreMonoidBorrowed {
17	/// The owned equivalent of `Self`.
18	type MonoidOwned: Monoid + Borrow<Self>;
19}
20
21/// The [`Borrow`]ed version of a [`Monoid`].
22///
23/// This has no `fn ident()` since that would return a new value,
24/// which can't be borrowed from anywhere.
25///
26/// # Caution
27/// The values `x: Self::MonoidOwned` and `x.borrow(): &Self` should behave identically,
28/// as explained in the documentation of [`Borrow`].
29///
30/// In particular, this means that `combine_borrowed(a.borrow(), b.borrow()) == combine(a, b)` for all `a, b: Self::MonoidOwned`
31/// and the analogous equalities for the other methods need to hold.
32pub trait MonoidBorrowed: PreMonoidBorrowed {
33	/// An implementation of [`Self::MonoidOwned::combine`](Monoid::combine) with borrowed values as inputs instead.
34	fn combine_borrowed(&self, rhs: &Self) -> Self::MonoidOwned;
35
36	/// An overridable method to provide some optimization based on knowledge of `Self::MonoidOwned`.
37	///
38	/// The default implementation just [`borrow`](Borrow::borrow)s `rhs`.
39	#[inline]
40	fn combine_left_borrowed(&self, rhs: Self::MonoidOwned) -> Self::MonoidOwned {
41		self.combine_borrowed(rhs.borrow())
42	}
43
44	/// An overridable method to provide some optimization based on knowledge of `Self::MonoidOwned`.
45	///
46	/// The default implementation just [`borrow`](Borrow::borrow)s `lhs`.
47	#[inline]
48	fn combine_right_borrowed(lhs: Self::MonoidOwned, rhs: &Self) -> Self::MonoidOwned {
49		lhs.borrow().combine_borrowed(rhs)
50	}
51
52	/// Like [`combine_left_borrowed`](Self::combine_left_borrowed), but assigns the result to `rhs`.
53	fn combine_left_borrowed_assign_to(lhs: &Self, rhs: &mut Self::MonoidOwned) {
54		*rhs = Self::combine_borrowed(lhs, (*rhs).borrow());
55	}
56
57	/// Like [`combine_right_borrowed`](Self::combine_right_borrowed), but assigns the result to `lhs`.
58	fn combine_right_borrowed_assign(lhs: &mut Self::MonoidOwned, rhs: &Self) {
59		*lhs = Self::combine_borrowed((*lhs).borrow(), rhs);
60	}
61
62	/// An overridable method to provide some optimization
63	/// based on the fact that [`combine`](Monoid::combine) is associative.
64	fn combine_iter_borrowed<'a, I: Iterator<Item = &'a Self>>(iter: I) -> Self::MonoidOwned
65	where
66		Self: 'a,
67	{
68		iter.fold(Monoid::ident(), Self::combine_right_borrowed)
69	}
70
71	/// An overridable method to provide some optimization based on
72	/// (a) the fact that [`combine`](Monoid::combine) is associative
73	/// and (b) knowledge of `Self::MonoidOwned`.
74	fn combine_iter_cow<'a, I: Iterator<Item = Cow<'a, Self>>>(iter: I) -> Self::MonoidOwned
75	where
76		Self: 'a + ToOwned<Owned = Self::MonoidOwned>,
77	{
78		iter.reduce(Cow::combine)
79			.map_or_else(Monoid::ident, Cow::into_owned)
80	}
81}
82
83impl<M: Monoid> PreMonoidBorrowed for M {
84	type MonoidOwned = Self;
85}
86
87impl<M: Monoid + Clone> MonoidBorrowed for M {
88	fn combine_borrowed(&self, rhs: &Self) -> Self::MonoidOwned {
89		self.clone().combine(rhs.clone())
90	}
91
92	fn combine_right_borrowed_assign(lhs: &mut Self::MonoidOwned, rhs: &Self) {
93		lhs.combine_assign(rhs.clone())
94	}
95
96	fn combine_left_borrowed_assign_to(lhs: &Self, rhs: &mut Self::MonoidOwned) {
97		lhs.clone().combine_assign_to(rhs)
98	}
99}
100
101/// `Cow<M>` is essentially the same thing as `M`, just with a different memory representation.
102impl<'a, M: 'a + ?Sized + MonoidBorrowed + ToOwned<Owned = M::MonoidOwned>> Monoid for Cow<'a, M> {
103	#[inline]
104	fn ident() -> Self {
105		Cow::Owned(M::MonoidOwned::ident())
106	}
107
108	fn combine(self, rhs: Self) -> Self {
109		Cow::Owned(match (self, rhs) {
110			(Cow::Owned(lhs), Cow::Owned(rhs)) => lhs.combine(rhs),
111			(Cow::Borrowed(lhs), Cow::Owned(rhs)) => lhs.combine_left_borrowed(rhs),
112			(Cow::Owned(lhs), Cow::Borrowed(rhs)) => M::combine_right_borrowed(lhs, rhs),
113			(Cow::Borrowed(lhs), Cow::Borrowed(rhs)) => lhs.combine_borrowed(rhs),
114		})
115	}
116
117	fn combine_assign(&mut self, rhs: Self) {
118		match (&mut *self, rhs) {
119			(Cow::Owned(lhs), Cow::Owned(rhs)) => lhs.combine_assign(rhs),
120			(Cow::Owned(lhs), Cow::Borrowed(rhs)) => M::combine_right_borrowed_assign(lhs, rhs),
121			(Cow::Borrowed(lhs), rhs) => {
122				*self = Cow::Owned(match rhs {
123					Cow::Owned(rhs) => lhs.combine_left_borrowed(rhs),
124					Cow::Borrowed(rhs) => lhs.combine_borrowed(rhs),
125				});
126			}
127		}
128	}
129
130	fn combine_assign_to(self, rhs: &mut Self) {
131		match (self, &mut *rhs) {
132			(Cow::Owned(lhs), Cow::Owned(rhs)) => lhs.combine_assign_to(rhs),
133			(Cow::Borrowed(lhs), Cow::Owned(rhs)) => M::combine_left_borrowed_assign_to(lhs, rhs),
134			(lhs, Cow::Borrowed(r)) => {
135				*rhs = Cow::Owned(match lhs {
136					Cow::Owned(lhs) => M::combine_right_borrowed(lhs, r),
137					Cow::Borrowed(lhs) => lhs.combine_borrowed(r),
138				});
139			}
140		}
141	}
142
143	#[inline]
144	fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
145		Cow::Owned(M::combine_iter_cow(iter))
146	}
147}
148
149impl<T> PreMonoidBorrowed for [T] {
150	type MonoidOwned = Vec<T>;
151}
152
153impl<T: Clone> MonoidBorrowed for [T] {
154	#[inline]
155	fn combine_borrowed(&self, rhs: &Self) -> Self::MonoidOwned {
156		Self::combine_right_borrowed(self.to_vec(), rhs)
157	}
158
159	#[inline]
160	fn combine_right_borrowed(mut lhs: Self::MonoidOwned, rhs: &Self) -> Self::MonoidOwned {
161		lhs.extend_from_slice(rhs);
162		lhs
163	}
164
165	#[inline]
166	fn combine_right_borrowed_assign(lhs: &mut Self::MonoidOwned, rhs: &Self) {
167		lhs.extend_from_slice(rhs);
168	}
169}
170
171impl PreMonoidBorrowed for str {
172	type MonoidOwned = String;
173}
174
175impl MonoidBorrowed for str {
176	#[inline]
177	fn combine_borrowed(&self, rhs: &Self) -> Self::MonoidOwned {
178		self.to_string() + rhs
179	}
180
181	#[inline]
182	fn combine_right_borrowed(lhs: Self::MonoidOwned, rhs: &Self) -> Self::MonoidOwned {
183		lhs + rhs
184	}
185
186	#[inline]
187	fn combine_right_borrowed_assign(lhs: &mut Self::MonoidOwned, rhs: &Self) {
188		lhs.push_str(rhs);
189	}
190
191	#[inline]
192	fn combine_iter_borrowed<'a, I: Iterator<Item = &'a Self>>(iter: I) -> Self::MonoidOwned {
193		iter.collect()
194	}
195
196	#[inline]
197	fn combine_iter_cow<'a, I: Iterator<Item = Cow<'a, Self>>>(iter: I) -> Self::MonoidOwned {
198		iter.collect()
199	}
200}
201
202impl PreMonoidBorrowed for OsStr {
203	type MonoidOwned = OsString;
204}
205
206impl MonoidBorrowed for OsStr {
207	#[inline]
208	fn combine_borrowed(&self, rhs: &Self) -> Self::MonoidOwned {
209		Self::combine_right_borrowed(self.to_os_string(), rhs)
210	}
211
212	#[inline]
213	fn combine_right_borrowed(mut lhs: Self::MonoidOwned, rhs: &Self) -> Self::MonoidOwned {
214		lhs.push(rhs);
215		lhs
216	}
217
218	#[inline]
219	fn combine_right_borrowed_assign(lhs: &mut Self::MonoidOwned, rhs: &Self) {
220		lhs.push(rhs);
221	}
222
223	#[inline]
224	fn combine_iter_borrowed<'a, I: Iterator<Item = &'a Self>>(iter: I) -> Self::MonoidOwned {
225		iter.collect()
226	}
227
228	#[inline]
229	fn combine_iter_cow<'a, I: Iterator<Item = Cow<'a, Self>>>(iter: I) -> Self::MonoidOwned {
230		iter.collect()
231	}
232}