into_owned_trait/lib.rs
1//! This crate provides the [`IntoOwned`] trait, which converts a
2//! *borrowed form* of a type into its *owned form*.
3//!
4//! # Motivation
5//!
6//! A common pattern in performance-sensitive code is to maintain two parallel
7//! representations of a type: a *borrowed* form that holds references into
8//! existing data (cheap to create and copy), and an *owned* form that carries
9//! its own heap-allocated data (can outlive the source).
10//!
11//! ```rust
12//! # use into_owned_trait::IntoOwned;
13//! // Cheap to push onto a stack during processing — no allocation.
14//! #[derive(Clone, Copy)]
15//! enum EventRef<'a> {
16//! Started(&'a str),
17//! Finished(&'a str, u64),
18//! }
19//!
20//! // Stored in the final result — heap-allocated, lifetime-free.
21//! enum Event {
22//! Started(String),
23//! Finished(String, u64),
24//! }
25//!
26//! impl<'a> IntoOwned for EventRef<'a> {
27//! type Owned = Event;
28//!
29//! fn into_owned(self) -> Event {
30//! match self {
31//! EventRef::Started(name) => Event::Started(name.to_owned()),
32//! EventRef::Finished(name, ts) => Event::Finished(name.to_owned(), ts),
33//! }
34//! }
35//! }
36//!
37//! let frame = EventRef::Finished("build", 42);
38//! let owned = frame.into_owned();
39//! ```
40//!
41//! [`IntoOwned`] gives generic code a single, uniform interface for this
42//! conversion, regardless of how complex the borrowed type's internal
43//! structure is.
44//!
45//! # Built-in implementations
46//!
47//! Two implementations are provided out of the box as convenience building
48//! blocks when implementing the trait for your own types:
49//!
50//! - `&T` where `T: `[`ToOwned`] (delegates to [`ToOwned::to_owned`])
51//! - [`Cow<'a, T>`][std::borrow::Cow] where `T: `[`ToOwned`] (delegates to
52//! [`Cow::into_owned`])
53
54use std::borrow::Cow;
55use std::iter::FusedIterator;
56
57/// Conversion of a borrowed type into its fully owned counterpart.
58///
59/// Implement this trait for a *borrowed form* of a type—one that holds
60/// references into existing data—to produce the corresponding *owned form*
61/// that carries its own data and has no lifetime parameters.
62///
63/// The owned form is often a structurally identical type with references
64/// replaced by their owned equivalents (e.g. `&'a str` → `String`,
65/// `&'a T` → `T::Owned`).
66///
67/// # Example
68///
69/// ```rust
70/// use into_owned_trait::IntoOwned;
71///
72/// struct PersonRef<'a> {
73/// name: &'a str,
74/// age: u32,
75/// }
76///
77/// struct Person {
78/// name: String,
79/// age: u32,
80/// }
81///
82/// impl<'a> IntoOwned for PersonRef<'a> {
83/// type Owned = Person;
84///
85/// fn into_owned(self) -> Person {
86/// Person {
87/// name: self.name.to_owned(),
88/// age: self.age,
89/// }
90/// }
91/// }
92///
93/// let p = PersonRef { name: "Alice", age: 30 };
94/// let owned = p.into_owned();
95/// assert_eq!(owned.name, "Alice");
96/// assert_eq!(owned.age, 30);
97/// ```
98pub trait IntoOwned {
99 /// The fully owned type produced by [`into_owned`](Self::into_owned).
100 type Owned;
101
102 /// Converts `self` into a fully owned value, consuming it.
103 ///
104 /// Implementations walk each field and convert references to owned data
105 /// (e.g. calling [`ToOwned::to_owned`] or [`Clone::clone`] as
106 /// appropriate). Fields that already hold owned data should be moved
107 /// without cloning.
108 fn into_owned(self) -> Self::Owned;
109}
110
111impl<T: ToOwned + ?Sized> IntoOwned for &T {
112 type Owned = T::Owned;
113
114 fn into_owned(self) -> Self::Owned {
115 self.to_owned()
116 }
117}
118
119macro_rules! impl_into_owned_for_tuple {
120 ($($T:ident),+) => {
121 impl<$($T: IntoOwned),+> IntoOwned for ($($T,)+) {
122 type Owned = ($($T::Owned,)+);
123
124 fn into_owned(self) -> Self::Owned {
125 #[allow(non_snake_case)]
126 let ($($T,)+) = self;
127 ($($T.into_owned(),)+)
128 }
129 }
130 };
131}
132
133impl_into_owned_for_tuple!(A);
134impl_into_owned_for_tuple!(A, B);
135impl_into_owned_for_tuple!(A, B, C);
136impl_into_owned_for_tuple!(A, B, C, D);
137impl_into_owned_for_tuple!(A, B, C, D, E);
138impl_into_owned_for_tuple!(A, B, C, D, E, F);
139impl_into_owned_for_tuple!(A, B, C, D, E, F, G);
140impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H);
141impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H, I);
142impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H, I, J);
143impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H, I, J, K);
144impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
145
146impl<'a, T: ToOwned + ?Sized> IntoOwned for Cow<'a, T> {
147 type Owned = T::Owned;
148
149 fn into_owned(self) -> T::Owned {
150 Cow::into_owned(self)
151 }
152}
153
154/// An iterator adapter that converts each item from its borrowed form to its
155/// owned form using [`IntoOwned::into_owned`].
156///
157/// Created by wrapping an iterator whose items implement [`IntoOwned`].
158///
159/// # Example
160///
161/// ```rust
162/// use into_owned_trait::{IntoOwned, MapIntoOwned};
163///
164/// let strings: Vec<String> = MapIntoOwned(["hello", "world"].iter().copied()).collect();
165/// assert_eq!(strings, ["hello", "world"]);
166/// ```
167#[derive(Debug, Clone, Copy)]
168pub struct MapIntoOwned<I>(pub I);
169
170impl<I: Iterator> Iterator for MapIntoOwned<I>
171where
172 I::Item: IntoOwned,
173{
174 type Item = <I::Item as IntoOwned>::Owned;
175
176 fn next(&mut self) -> Option<Self::Item> {
177 self.0.next().map(IntoOwned::into_owned)
178 }
179
180 fn size_hint(&self) -> (usize, Option<usize>) {
181 self.0.size_hint()
182 }
183
184 fn count(self) -> usize {
185 self.0.count()
186 }
187
188 fn last(self) -> Option<Self::Item> {
189 self.0.last().map(IntoOwned::into_owned)
190 }
191
192 fn nth(&mut self, n: usize) -> Option<Self::Item> {
193 self.0.nth(n).map(IntoOwned::into_owned)
194 }
195}
196
197impl<I: DoubleEndedIterator> DoubleEndedIterator for MapIntoOwned<I>
198where
199 I::Item: IntoOwned,
200{
201 fn next_back(&mut self) -> Option<Self::Item> {
202 self.0.next_back().map(IntoOwned::into_owned)
203 }
204
205 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
206 self.0.nth_back(n).map(IntoOwned::into_owned)
207 }
208}
209
210impl<I: ExactSizeIterator> ExactSizeIterator for MapIntoOwned<I>
211where
212 I::Item: IntoOwned,
213{
214 fn len(&self) -> usize {
215 self.0.len()
216 }
217}
218
219impl<I: FusedIterator> FusedIterator for MapIntoOwned<I> where I::Item: IntoOwned {}
220
221/// An iterator adapter that converts the `Ok` variant of each [`Result`] item
222/// using [`IntoOwned::into_owned`], passing `Err` items through unchanged.
223///
224/// Created by wrapping an iterator whose items are `Result<T, E>` where
225/// `T: IntoOwned`.
226///
227/// # Example
228///
229/// ```rust
230/// use into_owned_trait::{IntoOwned, MapOkIntoOwned};
231///
232/// let results: Vec<Result<&str, ()>> = vec![Ok("hello"), Ok("world")];
233/// let owned: Vec<Result<String, ()>> = MapOkIntoOwned(results.into_iter()).collect();
234/// assert_eq!(owned, [Ok("hello".to_owned()), Ok("world".to_owned())]);
235/// ```
236#[derive(Debug, Clone, Copy)]
237pub struct MapOkIntoOwned<I>(pub I);
238
239impl<T: IntoOwned, E, I: Iterator<Item = Result<T, E>>> Iterator for MapOkIntoOwned<I> {
240 type Item = Result<T::Owned, E>;
241
242 fn next(&mut self) -> Option<Self::Item> {
243 self.0.next().map(|r| r.map(IntoOwned::into_owned))
244 }
245
246 fn size_hint(&self) -> (usize, Option<usize>) {
247 self.0.size_hint()
248 }
249
250 fn count(self) -> usize {
251 self.0.count()
252 }
253
254 fn last(self) -> Option<Self::Item> {
255 self.0.last().map(|r| r.map(IntoOwned::into_owned))
256 }
257
258 fn nth(&mut self, n: usize) -> Option<Self::Item> {
259 self.0.nth(n).map(|r| r.map(IntoOwned::into_owned))
260 }
261}
262
263impl<T: IntoOwned, E, I: DoubleEndedIterator<Item = Result<T, E>>> DoubleEndedIterator
264 for MapOkIntoOwned<I>
265{
266 fn next_back(&mut self) -> Option<Self::Item> {
267 self.0.next_back().map(|r| r.map(IntoOwned::into_owned))
268 }
269
270 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
271 self.0.nth_back(n).map(|r| r.map(IntoOwned::into_owned))
272 }
273}
274
275impl<T: IntoOwned, E, I: ExactSizeIterator<Item = Result<T, E>>> ExactSizeIterator
276 for MapOkIntoOwned<I>
277{
278 fn len(&self) -> usize {
279 self.0.len()
280 }
281}
282
283impl<T: IntoOwned, E, I: FusedIterator<Item = Result<T, E>>> FusedIterator for MapOkIntoOwned<I> {}