use std::borrow::Cow;
use std::ops::Deref;
fn flatten_cow<'a, 'b, T>(this: Cow<'a, Cow<'b, T>>) -> Cow<'a, T>
where
'b: 'a,
T: ToOwned + ?Sized + 'b,
{
match this {
Cow::Owned(this) => this,
Cow::Borrowed(this) => Cow::Borrowed(this.deref()),
}
}
pub trait FlattenCow<'a, T: ToOwned + ?Sized + 'a> {
fn flatten(self) -> Cow<'a, T>;
}
impl<'a, 'b: 'a, T: ToOwned + ?Sized + 'a> FlattenCow<'a, T> for Cow<'b, Cow<'a, T>> {
fn flatten(self) -> Cow<'a, T> {
flatten_cow(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn is_owned<T: ToOwned>(input: Cow<T>) -> bool {
matches!(input, Cow::Owned(_))
}
#[test]
fn owned_owned() {
let input: Cow<Cow<usize>> = Cow::Owned(Cow::Owned(42));
let tmp = input.flatten();
assert_eq!(tmp, Cow::Owned(42));
assert!(is_owned(tmp));
}
#[test]
fn owned_borrowed() {
let input: Cow<Cow<usize>> = Cow::Owned(Cow::Borrowed(&42));
let tmp = input.flatten();
assert_eq!(tmp, Cow::Owned(42));
assert!(!is_owned(tmp));
}
#[test]
fn borrowed_owned() {
let input: Cow<Cow<usize>> = Cow::Borrowed(&Cow::Owned(42));
let tmp = input.flatten();
assert_eq!(tmp, Cow::Owned(42));
assert!(!is_owned(tmp));
}
#[test]
fn borrowed_borrowed() {
let input: Cow<Cow<usize>> = Cow::Borrowed(&Cow::Borrowed(&42));
let tmp = input.flatten();
assert_eq!(tmp, Cow::Owned(42));
assert!(!is_owned(tmp));
}
}