cow-tools/src/lib.rs

198 lines
5.5 KiB
Rust

pub enum TriCow<'a, 'b, T>
where
T: ToOwned + ?Sized,
{
Borrowed(&'a T),
Ephemeral(&'b T),
Owned(<T as ToOwned>::Owned),
}
impl<'a, 'b, T> TriCow<'a, 'b, T>
where
T: ToOwned + ?Sized,
{
pub fn into_owned(self) -> T::Owned {
match self {
Self::Borrowed(t) => t.to_owned(),
Self::Ephemeral(t) => t.to_owned(),
Self::Owned(t) => t,
}
}
pub fn into_std(self) -> std::borrow::Cow<'a, T> {
match self {
Self::Borrowed(t) => std::borrow::Cow::Borrowed(t),
Self::Ephemeral(t) => std::borrow::Cow::Owned(t.to_owned()),
Self::Owned(t) => std::borrow::Cow::Owned(t),
}
}
pub fn to_mut(&mut self) -> &mut <T as ToOwned>::Owned {
match *self {
Self::Borrowed(t) => {
*self = Self::Owned(t.to_owned());
match self {
Self::Owned(ref mut t) => t,
_ => unreachable!(),
}
}
Self::Ephemeral(t) => {
*self = Self::Owned(t.to_owned());
match self {
Self::Owned(ref mut t) => t,
_ => unreachable!(),
}
}
Self::Owned(ref mut t) => t,
}
}
}
impl<'a, 'b, T> AsRef<T> for TriCow<'a, 'b, T>
where
T: ToOwned + ?Sized,
T::Owned: std::borrow::Borrow<T>,
{
fn as_ref(&self) -> &T {
match self {
Self::Borrowed(t) => t,
Self::Ephemeral(t) => t,
Self::Owned(ref t) => std::borrow::Borrow::borrow(t),
}
}
}
#[cfg(test)]
mod tests {
use super::TriCow;
#[test]
fn a() {
let bytes = &[1, 2, 3, 4, 5, 6][..];
A::with_cow(TriCow::Borrowed(bytes));
A::with_cow(TriCow::Ephemeral(bytes));
A::with_cow(TriCow::Owned(Vec::from(bytes)));
}
#[test]
fn b() {
let bytes = &[1, 2, 3, 4, 5, 6][..];
B::with_cow(TriCow::Borrowed(bytes));
B::with_cow(TriCow::Ephemeral(bytes));
B::with_cow(TriCow::Owned(Vec::from(bytes)));
}
#[test]
fn c() {
let bytes = &[1, 2, 3, 4, 5, 6][..];
C::with_cow(TriCow::Borrowed(bytes));
C::with_cow(TriCow::Ephemeral(bytes));
C::with_cow(TriCow::Owned(Vec::from(bytes)));
}
#[test]
fn d() {
let bytes = &[1, 2, 3, 4, 5, 6][..];
D::with_cow(TriCow::Borrowed(bytes));
D::with_cow(TriCow::Ephemeral(bytes));
D::with_cow(TriCow::Owned(Vec::from(bytes)));
}
#[test]
fn e() {
let bytes = &[1, 2, 3, 4, 5, 6][..];
E::with_cow(TriCow::Borrowed(bytes));
E::with_cow(TriCow::Ephemeral(bytes));
E::with_cow(TriCow::Owned(Vec::from(bytes)));
}
trait WithCow<'a> {
fn with_cow<'b>(cow: TriCow<'a, 'b, [u8]>) -> Self;
}
struct A<'a>(std::borrow::Cow<'a, [u8]>);
struct B<'a>(A<'a>);
struct C<'a>(B<'a>, std::borrow::Cow<'a, [u8]>);
struct D<'a>(C<'a>);
struct E<'a>(D<'a>, std::borrow::Cow<'a, [u8]>);
impl<'a> WithCow<'a> for A<'a> {
fn with_cow<'b>(cow: TriCow<'a, 'b, [u8]>) -> Self {
Self(cow.into_std())
}
}
impl<'a> WithCow<'a> for B<'a> {
fn with_cow<'b>(cow: TriCow<'a, 'b, [u8]>) -> Self {
Self(A::with_cow(cow))
}
}
impl<'a> WithCow<'a> for C<'a> {
fn with_cow<'b>(cow: TriCow<'a, 'b, [u8]>) -> Self {
match cow {
TriCow::Borrowed(bytes) => {
let (first, second) = bytes.split_at(2);
Self(
B::with_cow(TriCow::Borrowed(first)),
std::borrow::Cow::Borrowed(second),
)
}
TriCow::Ephemeral(bytes) => {
let (first, second) = bytes.split_at(2);
Self(
B::with_cow(TriCow::Ephemeral(first)),
std::borrow::Cow::Owned(Vec::from(second)),
)
}
TriCow::Owned(bytes) => {
let (first, second) = bytes.split_at(2);
Self(
B::with_cow(TriCow::Ephemeral(first)),
std::borrow::Cow::Owned(Vec::from(second)),
)
}
}
}
}
impl<'a> WithCow<'a> for D<'a> {
fn with_cow<'b>(cow: TriCow<'a, 'b, [u8]>) -> Self {
Self(C::with_cow(cow))
}
}
impl<'a> WithCow<'a> for E<'a> {
fn with_cow<'b>(cow: TriCow<'a, 'b, [u8]>) -> Self {
match cow {
TriCow::Borrowed(bytes) => {
let (first, second) = bytes.split_at(2);
Self(
D::with_cow(TriCow::Borrowed(first)),
std::borrow::Cow::Borrowed(second),
)
}
TriCow::Ephemeral(bytes) => {
let (first, second) = bytes.split_at(2);
Self(
D::with_cow(TriCow::Ephemeral(first)),
std::borrow::Cow::Owned(Vec::from(second)),
)
}
TriCow::Owned(bytes) => {
let (first, second) = bytes.split_at(2);
Self(
D::with_cow(TriCow::Ephemeral(first)),
std::borrow::Cow::Owned(Vec::from(second)),
)
}
}
}
}
}