use core::{
borrow::Borrow,
fmt::{self, Debug, Display},
ops::Deref,
};
use const_default::ConstDefault;
use crate::alloc::{AllocateIn, Allocator};
use crate::error::StorageError;
pub type Owned<B, A> = <B as ToOwnedIn<A>>::Owned;
pub trait ToOwnedIn<A: Allocator> {
type Owned: Borrow<Self>;
fn to_owned_in<I>(&self, alloc_in: I) -> Self::Owned
where
I: AllocateIn<Alloc = A>,
{
match self.try_to_owned_in(alloc_in) {
Ok(inst) => inst,
Err(err) => err.panic(),
}
}
fn try_to_owned_in<I>(&self, alloc_in: I) -> Result<Self::Owned, StorageError>
where
I: AllocateIn<Alloc = A>;
}
impl<T: Clone + 'static, A: Allocator> ToOwnedIn<A> for T {
type Owned = T;
fn try_to_owned_in<I>(&self, _alloc_in: I) -> Result<Self::Owned, StorageError>
where
I: AllocateIn<Alloc = A>,
{
Ok(self.clone())
}
}
pub enum Cow<'b, T: ToOwnedIn<A> + ?Sized, A: Allocator> {
Borrowed(&'b T),
Owned(Owned<T, A>),
}
impl<'b, T: ToOwnedIn<A> + ?Sized, A: Allocator> Cow<'b, T, A> {
#[inline]
pub fn is_borrowed(&self) -> bool {
matches!(self, Self::Borrowed(_))
}
#[inline]
pub fn is_owned(&self) -> bool {
matches!(self, Self::Owned(_))
}
#[inline]
pub fn to_mut(&mut self) -> &mut Owned<T, A>
where
A: Default + Allocator,
{
self.to_mut_in(A::default())
}
pub fn to_mut_in<I>(&mut self, alloc_in: I) -> &mut Owned<T, A>
where
I: AllocateIn<Alloc = A>,
{
match *self {
Self::Borrowed(borrowed) => {
*self = Self::Owned(borrowed.to_owned_in(alloc_in));
let Self::Owned(owned) = self else {
unreachable!()
};
owned
}
Self::Owned(ref mut owned) => owned,
}
}
pub fn into_owned(self) -> Owned<T, A>
where
A: Default + Allocator,
{
match self {
Self::Borrowed(borrowed) => borrowed.to_owned_in(A::default()),
Self::Owned(owned) => owned,
}
}
pub fn into_owned_in<I>(self, alloc_in: I) -> Owned<T, A>
where
I: AllocateIn<Alloc = A>,
{
match self {
Self::Borrowed(borrowed) => borrowed.to_owned_in(alloc_in),
Self::Owned(owned) => owned,
}
}
pub fn try_into_owned(self) -> Result<Owned<T, A>, StorageError>
where
A: Default + Allocator,
{
match self {
Self::Borrowed(borrowed) => borrowed.try_to_owned_in(A::default()),
Self::Owned(owned) => Ok(owned),
}
}
pub fn try_into_owned_in<I>(self, storage: I) -> Result<Owned<T, A>, StorageError>
where
I: AllocateIn<Alloc = A>,
{
match self {
Self::Borrowed(borrowed) => borrowed.try_to_owned_in(storage),
Self::Owned(owned) => Ok(owned),
}
}
}
impl<T: ToOwnedIn<A> + ?Sized, A: Allocator> AsRef<T> for Cow<'_, T, A> {
fn as_ref(&self) -> &T {
self
}
}
impl<T: ToOwnedIn<A> + ?Sized, A: Allocator> Borrow<T> for Cow<'_, T, A> {
fn borrow(&self) -> &T {
self
}
}
impl<T: ToOwnedIn<A> + ?Sized, A: Allocator> Clone for Cow<'_, T, A>
where
Owned<T, A>: Clone,
{
fn clone(&self) -> Self {
match self {
Self::Borrowed(b) => Self::Borrowed(*b),
Self::Owned(o) => Self::Owned(o.clone()),
}
}
fn clone_from(&mut self, source: &Self) {
match (self, source) {
(&mut Self::Owned(ref mut dest), Self::Owned(ref o)) => dest.clone_from(o),
(t, s) => *t = s.clone(),
}
}
}
impl<T, A: Allocator> ConstDefault for Cow<'_, T, A>
where
T: ToOwnedIn<A> + ?Sized,
T::Owned: ConstDefault,
{
const DEFAULT: Self = Self::Owned(T::Owned::DEFAULT);
}
impl<T, A: Allocator> Debug for Cow<'_, T, A>
where
T: ToOwnedIn<A> + Debug + ?Sized,
Owned<T, A>: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Borrowed(b) => Debug::fmt(b, f),
Self::Owned(ref o) => Debug::fmt(o, f),
}
}
}
impl<T, A: Allocator> Display for Cow<'_, T, A>
where
T: ToOwnedIn<A> + Display + ?Sized,
Owned<T, A>: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Borrowed(ref b) => Display::fmt(b, f),
Self::Owned(ref o) => Display::fmt(o, f),
}
}
}
impl<T: ToOwnedIn<A> + ?Sized, A: Allocator> Deref for Cow<'_, T, A> {
type Target = T;
fn deref(&self) -> &T {
match *self {
Self::Borrowed(borrowed) => borrowed,
Self::Owned(ref owned) => owned.borrow(),
}
}
}
impl<T: ToOwnedIn<A> + ?Sized, A: Allocator> Default for Cow<'_, T, A>
where
Owned<T, A>: Default,
{
#[inline]
fn default() -> Self {
Self::Owned(Default::default())
}
}
impl<'b, T: ToOwnedIn<A> + ?Sized, A: Allocator> From<&'b T> for Cow<'b, T, A> {
#[inline]
fn from(borrow: &'b T) -> Self {
Self::Borrowed(borrow)
}
}
impl<'b, T: ToOwnedIn<A> + ?Sized, A: Allocator> From<&'b mut T> for Cow<'b, T, A> {
#[inline]
fn from(borrow: &'b mut T) -> Self {
Self::Borrowed(borrow)
}
}
impl<'a, 'b, T: ToOwnedIn<A> + ?Sized, A: Allocator, U: ToOwnedIn<B> + ?Sized, B: Allocator>
PartialEq<Cow<'b, U, B>> for Cow<'a, T, A>
where
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &Cow<'b, U, B>) -> bool {
self.deref().eq(other.deref())
}
}
impl<'a, T: ToOwnedIn<A> + Eq + ?Sized, A: Allocator> Eq for Cow<'a, T, A> {}