use std::{
borrow::{Borrow, BorrowMut},
fmt::Display,
ops::{Deref, DerefMut},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum CloneOnExtract<'a, T: Borrow<U>, U: ?Sized + ToOwned<Owned = T>> {
Owned(T),
Borrowed(&'a U),
}
impl<'a, T: Borrow<U>, U: ?Sized + ToOwned<Owned = T>> CloneOnExtract<'a, T, U> {
pub fn into_owned(self) -> Self {
match self {
Self::Owned(t) => CloneOnExtract::Owned(t),
Self::Borrowed(t) => CloneOnExtract::Owned(t.to_owned()),
}
}
pub fn as_borrowed(&'a self) -> Self {
match self {
Self::Owned(t) => CloneOnExtract::Borrowed(t.borrow()),
Self::Borrowed(t) => CloneOnExtract::Borrowed(t),
}
}
pub fn extract(self) -> T {
match self {
CloneOnExtract::Owned(t) => t,
CloneOnExtract::Borrowed(t) => t.to_owned(),
}
}
pub fn is_owned(&self) -> bool {
matches!(self, CloneOnExtract::Owned(_))
}
pub fn is_borrowed(&self) -> bool {
matches!(self, CloneOnExtract::Borrowed(_))
}
}
impl<'a, T: Deref + Borrow<T::Target>> CloneOnExtract<'a, T, T::Target>
where
T::Target: ToOwned<Owned = T>,
{
pub fn from_deref_owned(owned: T) -> Self {
CloneOnExtract::Owned(owned)
}
}
impl<'a, U: ?Sized + ToOwned> CloneOnExtract<'a, U::Owned, U> {
pub fn from_ref(borrowed: &'a U) -> Self {
CloneOnExtract::Borrowed(borrowed)
}
}
impl<'a, T: Clone> CloneOnExtract<'a, T, T> {
pub fn from_owned(owned: T) -> Self {
CloneOnExtract::Owned(owned)
}
}
impl<T: Borrow<U>, U: ?Sized + ToOwned<Owned = T>> Deref for CloneOnExtract<'_, T, U> {
type Target = U;
fn deref(&self) -> &Self::Target {
match self {
Self::Owned(t) => t.borrow(),
Self::Borrowed(t) => t,
}
}
}
impl<T: BorrowMut<U>, U: ?Sized + ToOwned<Owned = T>> DerefMut for CloneOnExtract<'_, T, U> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Owned(t) => t.borrow_mut(),
Self::Borrowed(t) => {
*self = Self::Owned(t.to_owned());
self.deref_mut()
}
}
}
}
impl<T: Borrow<U>, U: ?Sized + ToOwned<Owned = T>> Borrow<U> for CloneOnExtract<'_, T, U> {
fn borrow(&self) -> &U {
self
}
}
impl<T: BorrowMut<U>, U: ?Sized + ToOwned<Owned = T>> BorrowMut<U> for CloneOnExtract<'_, T, U> {
fn borrow_mut(&mut self) -> &mut U {
self
}
}
impl<T: Borrow<U>, U: ?Sized + ToOwned<Owned = T>> AsRef<U> for CloneOnExtract<'_, T, U> {
fn as_ref(&self) -> &U {
self
}
}
impl<T: BorrowMut<U>, U: ?Sized + ToOwned<Owned = T>> AsMut<U> for CloneOnExtract<'_, T, U> {
fn as_mut(&mut self) -> &mut U {
self
}
}
impl<T: Borrow<U> + Default, U: ?Sized + ToOwned<Owned = T>> Default for CloneOnExtract<'_, T, U> {
fn default() -> Self {
Self::Owned(T::default())
}
}
impl<T: Borrow<U>, U: ?Sized + ToOwned<Owned = T> + Display> Display for CloneOnExtract<'_, T, U> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Owned(t) => t.borrow().fmt(f),
Self::Borrowed(t) => t.fmt(f),
}
}
}