copy_on_write.rs

#
use std::{
    borrow::Borrow,
    fmt::{self, Debug},
};
#

A CopyOnWrite can be in either of two states:

pub enum CopyOnWrite<'a, B: 'a>
where
    B: ToOwned,
{
#

Borrowed, where it is a reference to the underlying data.

    Borrowed(&'a B),
#

Owned, where it uniquely owns the data.

    Owned(<B as ToOwned>::Owned),
}

use CopyOnWrite::*;
#

CopyOnWrite requires a manual implementation of Clone:

impl<B: ToOwned> Clone for CopyOnWrite<'_, B> {
    fn clone(&self) -> Self {
        match *self {
#

If the CoW is Borrowed, the clone returns the borrowed data.

            Borrowed(b) => Borrowed(b),
#

If the Cow is Owned, the clone returns a new copy of the data.

            Owned(ref owned) => Owned(owned.borrow().to_owned()),
        }
    }

    fn clone_from(&mut self, source: &Self) {
        match (self, source) {
            (&mut Owned(ref mut dest), Owned(ref owned)) => owned.borrow().clone_into(dest),
            (t, s) => *t = s.clone(),
        }
    }
}

impl<B: ToOwned> CopyOnWrite<'_, B> {
#

If we want a mutable version of the CoW

    pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
        match self {
#

If it is borrowed, we’ll clone it and return that.

            Borrowed(borrowed) => {
                *self = Owned(borrowed.to_owned());
                match self {
                    Borrowed(..) => unreachable!(),
                    Owned(ref mut owned) => owned,
                }
            }
#

Otherwise, we already own a mutable copy, so hand that out.

            Owned(ref mut owned) => owned,
        }
    }

    pub fn into_owned(self) -> <B as ToOwned>::Owned {
        match self {
            Borrowed(borrowed) => borrowed.to_owned(),
            Owned(owned) => owned,
        }
    }
}

impl<B> Debug for CopyOnWrite<'_, B>
where
    B: Debug + ToOwned<Owned: Debug>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Borrowed(ref b) => Debug::fmt(b, f),
            Owned(ref o) => Debug::fmt(o, f),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn check_clones() {
        let mut cow: CopyOnWrite<String> = CopyOnWrite::Owned("Hi".to_string());
        let mut cow1 = cow.clone();

        let mut mutable_cow = cow1.into_owned();
        mutable_cow.push_str(" world");
        assert_eq!(cow.clone().into_owned(), "Hi".to_string());
        assert_ne!(mutable_cow, cow.into_owned());
    }
}