use super::*;
use core::{cmp, fmt, hash, ops::Deref};
use std_alloc::borrow::Borrow;
pub trait TryToOwned {
type Owned: Borrow<Self>;
fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory>;
}
impl TryToOwned for str {
type Owned = TryString;
fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory> {
let mut s = TryString::new();
s.push_str(self)?;
Ok(s)
}
}
impl<T> TryToOwned for [T]
where
T: TryClone,
{
type Owned = TryVec<T>;
fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory> {
let mut v = TryVec::with_capacity(self.len())?;
for x in self {
v.push(x.try_clone()?)?;
}
Ok(v)
}
}
impl<T> TryToOwned for T
where
T: TryClone,
{
type Owned = Self;
fn try_to_owned(&self) -> Result<Self::Owned, OutOfMemory> {
self.try_clone()
}
}
pub enum TryCow<'a, B>
where
B: 'a + TryToOwned + ?Sized,
{
Borrowed(&'a B),
Owned(<B as TryToOwned>::Owned),
}
impl<'a, B> From<&'a B> for TryCow<'a, B>
where
B: 'a + ?Sized + TryToOwned,
{
fn from(b: &'a B) -> Self {
Self::Borrowed(b)
}
}
impl<B> Default for TryCow<'_, B>
where
B: ?Sized + TryToOwned<Owned: Default>,
{
fn default() -> Self {
Self::Owned(<B as TryToOwned>::Owned::default())
}
}
impl<B> fmt::Debug for TryCow<'_, B>
where
B: ?Sized + fmt::Debug + TryToOwned<Owned: fmt::Debug>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Borrowed(b) => fmt::Debug::fmt(b, f),
Self::Owned(o) => fmt::Debug::fmt(o, f),
}
}
}
impl<B> TryClone for TryCow<'_, B>
where
B: ?Sized + TryToOwned,
{
fn try_clone(&self) -> Result<Self, OutOfMemory> {
match self {
Self::Borrowed(b) => Ok(Self::Borrowed(b)),
Self::Owned(o) => {
let b: &B = o.borrow();
Ok(Self::Owned(b.try_to_owned()?))
}
}
}
}
impl<B> Deref for TryCow<'_, B>
where
B: ?Sized + TryToOwned,
{
type Target = B;
fn deref(&self) -> &B {
match self {
Self::Borrowed(b) => b,
Self::Owned(o) => o.borrow(),
}
}
}
impl<B> AsRef<B> for TryCow<'_, B>
where
B: ?Sized + TryToOwned,
{
fn as_ref(&self) -> &B {
self
}
}
impl<'a, B> Borrow<B> for TryCow<'a, B>
where
B: ?Sized + TryToOwned,
{
fn borrow(&self) -> &B {
&**self
}
}
impl<B> hash::Hash for TryCow<'_, B>
where
B: ?Sized + hash::Hash + TryToOwned,
{
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
hash::Hash::hash(&**self, state)
}
}
impl<B> PartialEq for TryCow<'_, B>
where
B: ?Sized + PartialEq + TryToOwned,
{
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(&**self, &**other)
}
}
impl<B> Eq for TryCow<'_, B> where B: ?Sized + Eq + TryToOwned {}
impl<B> PartialOrd for TryCow<'_, B>
where
B: ?Sized + PartialOrd + TryToOwned,
{
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
}
impl<B> Ord for TryCow<'_, B>
where
B: ?Sized + Ord + TryToOwned,
{
fn cmp(&self, other: &Self) -> cmp::Ordering {
Ord::cmp(&**self, &**other)
}
}
impl<'a, B> TryCow<'a, B>
where
B: TryToOwned + ?Sized,
{
pub fn to_mut(&mut self) -> Result<&mut <B as TryToOwned>::Owned, OutOfMemory> {
if let Self::Borrowed(b) = self {
*self = Self::Owned(b.try_to_owned()?);
}
match self {
TryCow::Owned(x) => Ok(x),
TryCow::Borrowed(_) => unreachable!(),
}
}
pub fn into_owned(self) -> Result<<B as TryToOwned>::Owned, OutOfMemory> {
match self {
TryCow::Borrowed(b) => b.try_to_owned(),
TryCow::Owned(x) => Ok(x),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::Result;
#[test]
fn to_mut() -> Result<()> {
let mut s = TryCow::Borrowed("hello");
s.to_mut()?.push_str(", world!")?;
assert!(matches!(s, TryCow::Owned(_)));
assert_eq!(&*s, "hello, world!");
Ok(())
}
#[test]
fn into_owned() -> Result<()> {
let v = TryCow::Borrowed(&[42u8, 36][..]);
let v: TryVec<u8> = v.into_owned()?;
assert_eq!(&*v, &[42, 36]);
Ok(())
}
}