use std::{
borrow::{Borrow, Cow},
fmt::{Display, Formatter},
ops::Deref,
};
use crate::{MakeOwned, ShallowClone};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
pub enum CoCow<'a, T> {
Owned(T),
#[cfg_attr(feature = "serde", serde(skip_deserializing))]
Borrowed(&'a T),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
pub enum CoCowSlice<'a, T> {
Owned(Vec<T>),
#[cfg_attr(feature = "serde", serde(skip_deserializing))]
Borrowed(&'a [T]),
}
impl<'a, T: Clone> CoCow<'a, T> {
pub fn into_owned(self) -> T {
match self {
CoCow::Owned(owned) => owned,
CoCow::Borrowed(borrowed) => borrowed.clone(),
}
}
pub fn to_mut(&mut self) -> &mut T {
match self {
CoCow::Owned(owned) => owned,
CoCow::Borrowed(borrowed) => {
*self = CoCow::Owned(borrowed.clone());
match self {
CoCow::Owned(owned) => owned,
_ => unreachable!(),
}
}
}
}
}
impl<'a, T> CoCow<'a, T> {
pub fn is_borrowed(&self) -> bool {
matches!(self, CoCow::Borrowed(_))
}
pub fn is_owned(&self) -> bool {
matches!(self, CoCow::Owned(_))
}
}
impl<'a, T: Clone> CoCowSlice<'a, T> {
pub fn into_owned(self) -> Vec<T> {
match self {
CoCowSlice::Owned(owned) => owned,
CoCowSlice::Borrowed(borrowed) => borrowed.to_owned(),
}
}
pub fn to_mut(&mut self) -> &mut Vec<T> {
match self {
CoCowSlice::Owned(owned) => owned,
CoCowSlice::Borrowed(borrowed) => {
*self = CoCowSlice::Owned(borrowed.to_owned());
match self {
CoCowSlice::Owned(owned) => owned,
_ => unreachable!(),
}
}
}
}
}
impl<'a, T> CoCowSlice<'a, T> {
pub fn is_borrowed(&self) -> bool {
matches!(self, CoCowSlice::Borrowed(_))
}
pub fn is_owned(&self) -> bool {
matches!(self, CoCowSlice::Owned(_))
}
}
impl<'a, T> ShallowClone<'a> for CoCow<'a, T> {
type Target = CoCow<'a, T>;
fn shallow_clone(&'a self) -> Self::Target {
match self {
CoCow::Owned(owned) => CoCow::Borrowed(&owned),
CoCow::Borrowed(borrowed) => CoCow::Borrowed(borrowed),
}
}
}
impl<'a, T> ShallowClone<'a> for CoCowSlice<'a, T> {
type Target = CoCowSlice<'a, T>;
fn shallow_clone(&'a self) -> Self::Target {
match self {
CoCowSlice::Owned(owned) => CoCowSlice::Borrowed(&owned),
CoCowSlice::Borrowed(borrowed) => CoCowSlice::Borrowed(borrowed),
}
}
}
impl<'a, T: MakeOwned> MakeOwned for CoCow<'a, T>
where
<T as MakeOwned>::Owned: Clone,
{
type Owned = CoCow<'static, <T as MakeOwned>::Owned>;
fn make_owned(self) -> <Self as MakeOwned>::Owned {
CoCow::Owned(self.into_owned().make_owned())
}
}
impl<'a, T: MakeOwned> MakeOwned for CoCowSlice<'a, T>
where
<T as MakeOwned>::Owned: Clone,
{
type Owned = CoCowSlice<'static, <T as MakeOwned>::Owned>;
fn make_owned(self) -> <Self as MakeOwned>::Owned {
CoCowSlice::Owned(self.into_owned().make_owned())
}
}
impl<'a, T> Deref for CoCow<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
CoCow::Owned(owned) => owned,
CoCow::Borrowed(borrowed) => borrowed,
}
}
}
impl<'a, T> Deref for CoCowSlice<'a, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
match self {
CoCowSlice::Owned(owned) => owned,
CoCowSlice::Borrowed(borrowed) => borrowed,
}
}
}
impl<'a, T> AsRef<T> for CoCow<'a, T> {
fn as_ref(&self) -> &T {
self
}
}
impl<'a, T> AsRef<[T]> for CoCowSlice<'a, T> {
fn as_ref(&self) -> &[T] {
self
}
}
impl<'a, T> Borrow<T> for CoCow<'a, T> {
fn borrow(&self) -> &T {
self
}
}
impl<'a, T> Borrow<[T]> for CoCowSlice<'a, T> {
fn borrow(&self) -> &[T] {
self
}
}
impl<'a, T: Default> Default for CoCow<'a, T> {
fn default() -> Self {
CoCow::Owned(Default::default())
}
}
impl<'a, T> Default for CoCowSlice<'a, T> {
fn default() -> Self {
CoCowSlice::Owned(Default::default())
}
}
impl<'a, T: Display> Display for CoCow<'a, T> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
Display::fmt(&**self, f)
}
}
impl<'a, T> From<T> for CoCow<'a, T> {
fn from(value: T) -> Self {
CoCow::Owned(value)
}
}
impl<'a, T> From<Vec<T>> for CoCowSlice<'a, T> {
fn from(value: Vec<T>) -> Self {
CoCowSlice::Owned(value)
}
}
impl<'a, T> From<&'a T> for CoCow<'a, T> {
fn from(value: &'a T) -> Self {
CoCow::Borrowed(value)
}
}
impl<'a, T> From<&'a [T]> for CoCowSlice<'a, T> {
fn from(value: &'a [T]) -> Self {
CoCowSlice::Borrowed(value)
}
}
impl<'a, T> From<&'a Vec<T>> for CoCowSlice<'a, T> {
fn from(value: &'a Vec<T>) -> Self {
CoCowSlice::Borrowed(value)
}
}
impl<'a, const N: usize, T> From<&'a [T; N]> for CoCowSlice<'a, T> {
fn from(value: &'a [T; N]) -> Self {
CoCowSlice::Borrowed(value)
}
}
impl<'a, T: Clone> From<Cow<'a, T>> for CoCow<'a, T> {
fn from(value: Cow<'a, T>) -> Self {
match value {
Cow::Borrowed(borrowed) => Self::Borrowed(borrowed),
Cow::Owned(owned) => Self::Owned(owned),
}
}
}
impl<'a, T: Clone> From<Cow<'a, [T]>> for CoCowSlice<'a, T> {
fn from(value: Cow<'a, [T]>) -> Self {
match value {
Cow::Borrowed(borrowed) => Self::Borrowed(borrowed),
Cow::Owned(owned) => Self::Owned(owned),
}
}
}
impl<'a, T> IntoIterator for &'a CoCow<'a, T>
where
&'a T: IntoIterator,
{
type Item = <&'a T as IntoIterator>::Item;
type IntoIter = <&'a T as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
match self {
CoCow::Owned(owned) => owned.into_iter(),
CoCow::Borrowed(borrowed) => borrowed.into_iter(),
}
}
}
impl<'a, T> IntoIterator for &'a CoCowSlice<'a, T>
where
&'a [T]: IntoIterator,
{
type Item = <&'a [T] as IntoIterator>::Item;
type IntoIter = <&'a [T] as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
match self {
CoCowSlice::Owned(owned) => (&owned[..]).into_iter(),
CoCowSlice::Borrowed(borrowed) => borrowed.into_iter(),
}
}
}
#[cfg(test)]
mod tests {
use super::{CoCow, CoCowSlice};
use crate::ShallowClone;
#[test]
fn test_covariance() {
#[derive(ShallowClone, Clone)]
struct MyStruct<'a>(#[allow(dead_code)] &'a ());
let u = ();
let x = MyStruct(&u);
let cocow: CoCow<MyStruct> = CoCow::from(x);
fn test<'a>(_: CoCow<'a, MyStruct<'a>>) {}
test(cocow.shallow_clone());
let y = [(); 100].map(|_| MyStruct(&u));
let cocow_slice: CoCowSlice<MyStruct> = CoCowSlice::from(&y[..]);
fn test_slice<'a>(_: CoCowSlice<'a, MyStruct<'a>>) {}
test_slice(cocow_slice.shallow_clone());
}
}