A Rust library providing traits for working with copy-on-write values efficiently.
ShallowClone trait
This is basically the same as the standard Clone,
except that it's optimized for copy-on-write values so that they're not cloned. Shallow cloning a
Cow will always produce a Borrowed variant, either referencing the original
value if it was Owned, or just copying the reference if it already was Borrowed.
| original | after ShallowClone::shallow_clone(&'a T) |
|---|---|
Cow::Owned(T) |
Cow::Borrowed(&'a T) |
Cow::Borrowed(&'b T) |
Cow::Borrowed(&'a T) |
MakeOwned trait
This is kind of a side effect of ShallowClone. It allows to convert any value that implements it
to an equivalent type which is 'static - no references, completely self-sufficient. It does that by replacing
all inner Cows with their owned variants, which allows to set the associated lifetimes to 'static.
Obviously you can't use this if your type contains straight up references not in an enum like Cow.
You might notice, that if you have some deeply nested structures with Cows, where your inner value contains
references too, for example:
struct Foo<'a> {
inner: Cow<'a, [Bar<'a>]>,
}
struct Bar<'a> {
id: &'a str,
data: [u8; 1024],
}Here we have a Cow of a slice of Bars, and Bar also has a lifetime. If you try to shallow clone
Foo, it will not compile, because the shallow cloning will try to shorten the lifetime of the Cow, but not the
lifetime of Bar (shallow cloning only goes as deep as the first Cow, upon which it just replaces it with
a Borrowed variant). So you will end up with Cow<'a, [Bar<'b>]> and even though 'b is clearly a subtype of 'a
and you could expect the compiler to accept it, actually Cow<'_, T> is invariant1 over T so it won't compile.
One solution to this would be to have two lifetimes instead, like Foo<'a, 'b> but that quickly bubbles up in your
structures and makes everything much more complicated.
To solve this issue, this crate also introduces two covariant replacements for the standard Cow:
CoCow<'a, T>which is a general replacement for the standardCow,CoCowSlice<'a, T>which is a replacement forCow<'a, [T]>.
These types don't rely on the ToOwned trait and have simpler, but less powerful definition (hence the need for
a an additional CoCowSlice). They are covariant over T, which allows ShallowClone to be used with nested
structures like described.
You can also easily make your own specialised Cow types and implement ShallowClone for them, if these two types
are not sufficient for your needs.
Note that for simple cases like Cow<'a, str> or Cow<'a, [u8]> there is no need for them and you can just use
the normal std::borrow::Cow.
Footnotes
-
This is because
Cow<T>requires thatT: ToOwned, therefore if you subtypedTit could have a differentToOwnedimplementation (or even none) and it would invalidate the type. TheCoCowtypes in this crate do not rely on any traits and avoid this limitation. ↩