into-owned-trait 1.2.0

`IntoOwned` trait for converting borrowed types into their owned counterparts
Documentation
//! This crate provides the [`IntoOwned`] trait, which converts a
//! *borrowed form* of a type into its *owned form*.
//!
//! # Motivation
//!
//! A common pattern in performance-sensitive code is to maintain two parallel
//! representations of a type: a *borrowed* form that holds references into
//! existing data (cheap to create and copy), and an *owned* form that carries
//! its own heap-allocated data (can outlive the source).
//!
//! ```rust
//! # use into_owned_trait::IntoOwned;
//! // Cheap to push onto a stack during processing — no allocation.
//! #[derive(Clone, Copy)]
//! enum EventRef<'a> {
//!     Started(&'a str),
//!     Finished(&'a str, u64),
//! }
//!
//! // Stored in the final result — heap-allocated, lifetime-free.
//! enum Event {
//!     Started(String),
//!     Finished(String, u64),
//! }
//!
//! impl<'a> IntoOwned for EventRef<'a> {
//!     type Owned = Event;
//!
//!     fn into_owned(self) -> Event {
//!         match self {
//!             EventRef::Started(name) => Event::Started(name.to_owned()),
//!             EventRef::Finished(name, ts) => Event::Finished(name.to_owned(), ts),
//!         }
//!     }
//! }
//!
//! let frame = EventRef::Finished("build", 42);
//! let owned = frame.into_owned();
//! ```
//!
//! [`IntoOwned`] gives generic code a single, uniform interface for this
//! conversion, regardless of how complex the borrowed type's internal
//! structure is.
//!
//! # Built-in implementations
//!
//! Two implementations are provided out of the box as convenience building
//! blocks when implementing the trait for your own types:
//!
//! - `&T` where `T: `[`ToOwned`] (delegates to [`ToOwned::to_owned`])
//! - [`Cow<'a, T>`][std::borrow::Cow] where `T: `[`ToOwned`] (delegates to
//!   [`Cow::into_owned`])

use std::borrow::Cow;
use std::iter::FusedIterator;

/// Conversion of a borrowed type into its fully owned counterpart.
///
/// Implement this trait for a *borrowed form* of a type—one that holds
/// references into existing data—to produce the corresponding *owned form*
/// that carries its own data and has no lifetime parameters.
///
/// The owned form is often a structurally identical type with references
/// replaced by their owned equivalents (e.g. `&'a str` → `String`,
/// `&'a T` → `T::Owned`).
///
/// # Example
///
/// ```rust
/// use into_owned_trait::IntoOwned;
///
/// struct PersonRef<'a> {
///     name: &'a str,
///     age: u32,
/// }
///
/// struct Person {
///     name: String,
///     age: u32,
/// }
///
/// impl<'a> IntoOwned for PersonRef<'a> {
///     type Owned = Person;
///
///     fn into_owned(self) -> Person {
///         Person {
///             name: self.name.to_owned(),
///             age: self.age,
///         }
///     }
/// }
///
/// let p = PersonRef { name: "Alice", age: 30 };
/// let owned = p.into_owned();
/// assert_eq!(owned.name, "Alice");
/// assert_eq!(owned.age, 30);
/// ```
pub trait IntoOwned {
	/// The fully owned type produced by [`into_owned`](Self::into_owned).
	type Owned;

	/// Converts `self` into a fully owned value, consuming it.
	///
	/// Implementations walk each field and convert references to owned data
	/// (e.g. calling [`ToOwned::to_owned`] or [`Clone::clone`] as
	/// appropriate). Fields that already hold owned data should be moved
	/// without cloning.
	fn into_owned(self) -> Self::Owned;
}

impl<T: ToOwned + ?Sized> IntoOwned for &T {
	type Owned = T::Owned;

	fn into_owned(self) -> Self::Owned {
		self.to_owned()
	}
}

macro_rules! impl_into_owned_for_tuple {
	($($T:ident),+) => {
		impl<$($T: IntoOwned),+> IntoOwned for ($($T,)+) {
			type Owned = ($($T::Owned,)+);

			fn into_owned(self) -> Self::Owned {
				#[allow(non_snake_case)]
				let ($($T,)+) = self;
				($($T.into_owned(),)+)
			}
		}
	};
}

impl_into_owned_for_tuple!(A);
impl_into_owned_for_tuple!(A, B);
impl_into_owned_for_tuple!(A, B, C);
impl_into_owned_for_tuple!(A, B, C, D);
impl_into_owned_for_tuple!(A, B, C, D, E);
impl_into_owned_for_tuple!(A, B, C, D, E, F);
impl_into_owned_for_tuple!(A, B, C, D, E, F, G);
impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H);
impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H, I);
impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H, I, J);
impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H, I, J, K);
impl_into_owned_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);

impl<'a, T: ToOwned + ?Sized> IntoOwned for Cow<'a, T> {
	type Owned = T::Owned;

	fn into_owned(self) -> T::Owned {
		Cow::into_owned(self)
	}
}

/// An iterator adapter that converts each item from its borrowed form to its
/// owned form using [`IntoOwned::into_owned`].
///
/// Created by wrapping an iterator whose items implement [`IntoOwned`].
///
/// # Example
///
/// ```rust
/// use into_owned_trait::{IntoOwned, MapIntoOwned};
///
/// let strings: Vec<String> = MapIntoOwned(["hello", "world"].iter().copied()).collect();
/// assert_eq!(strings, ["hello", "world"]);
/// ```
#[derive(Debug, Clone, Copy)]
pub struct MapIntoOwned<I>(pub I);

impl<I: Iterator> Iterator for MapIntoOwned<I>
where
	I::Item: IntoOwned,
{
	type Item = <I::Item as IntoOwned>::Owned;

	fn next(&mut self) -> Option<Self::Item> {
		self.0.next().map(IntoOwned::into_owned)
	}

	fn size_hint(&self) -> (usize, Option<usize>) {
		self.0.size_hint()
	}

	fn count(self) -> usize {
		self.0.count()
	}

	fn last(self) -> Option<Self::Item> {
		self.0.last().map(IntoOwned::into_owned)
	}

	fn nth(&mut self, n: usize) -> Option<Self::Item> {
		self.0.nth(n).map(IntoOwned::into_owned)
	}
}

impl<I: DoubleEndedIterator> DoubleEndedIterator for MapIntoOwned<I>
where
	I::Item: IntoOwned,
{
	fn next_back(&mut self) -> Option<Self::Item> {
		self.0.next_back().map(IntoOwned::into_owned)
	}

	fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
		self.0.nth_back(n).map(IntoOwned::into_owned)
	}
}

impl<I: ExactSizeIterator> ExactSizeIterator for MapIntoOwned<I>
where
	I::Item: IntoOwned,
{
	fn len(&self) -> usize {
		self.0.len()
	}
}

impl<I: FusedIterator> FusedIterator for MapIntoOwned<I> where I::Item: IntoOwned {}

/// An iterator adapter that converts the `Ok` variant of each [`Result`] item
/// using [`IntoOwned::into_owned`], passing `Err` items through unchanged.
///
/// Created by wrapping an iterator whose items are `Result<T, E>` where
/// `T: IntoOwned`.
///
/// # Example
///
/// ```rust
/// use into_owned_trait::{IntoOwned, MapOkIntoOwned};
///
/// let results: Vec<Result<&str, ()>> = vec![Ok("hello"), Ok("world")];
/// let owned: Vec<Result<String, ()>> = MapOkIntoOwned(results.into_iter()).collect();
/// assert_eq!(owned, [Ok("hello".to_owned()), Ok("world".to_owned())]);
/// ```
#[derive(Debug, Clone, Copy)]
pub struct MapOkIntoOwned<I>(pub I);

impl<T: IntoOwned, E, I: Iterator<Item = Result<T, E>>> Iterator for MapOkIntoOwned<I> {
	type Item = Result<T::Owned, E>;

	fn next(&mut self) -> Option<Self::Item> {
		self.0.next().map(|r| r.map(IntoOwned::into_owned))
	}

	fn size_hint(&self) -> (usize, Option<usize>) {
		self.0.size_hint()
	}

	fn count(self) -> usize {
		self.0.count()
	}

	fn last(self) -> Option<Self::Item> {
		self.0.last().map(|r| r.map(IntoOwned::into_owned))
	}

	fn nth(&mut self, n: usize) -> Option<Self::Item> {
		self.0.nth(n).map(|r| r.map(IntoOwned::into_owned))
	}
}

impl<T: IntoOwned, E, I: DoubleEndedIterator<Item = Result<T, E>>> DoubleEndedIterator
	for MapOkIntoOwned<I>
{
	fn next_back(&mut self) -> Option<Self::Item> {
		self.0.next_back().map(|r| r.map(IntoOwned::into_owned))
	}

	fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
		self.0.nth_back(n).map(|r| r.map(IntoOwned::into_owned))
	}
}

impl<T: IntoOwned, E, I: ExactSizeIterator<Item = Result<T, E>>> ExactSizeIterator
	for MapOkIntoOwned<I>
{
	fn len(&self) -> usize {
		self.0.len()
	}
}

impl<T: IntoOwned, E, I: FusedIterator<Item = Result<T, E>>> FusedIterator for MapOkIntoOwned<I> {}