A type such as
Box<dyn Capture + '_> also has a lifetime parameter. The only advantage it has over other types with lifetime parameters is that it can utilize some special elision rules that allow you to write
Box<dyn Capture> as a shorthand for
Box<dyn Capture + 'static>.
As for the code you’re asking about w.r.t. soundness, it looks relatively sound to me, given that user-code will not be allowed to construct arbitrary
T values. I can’t think of a way to implement something like
release soundly without
unsafe, if the requirement is that a
Box is involved and re-allocation should be avoided, as there’s no existing API for re-using an allocation of a
Box while changing the contained type, even if a completely new value is to be assigned and the type change only changes a lifetime.
However, if avoiding the
Box is the goal anyways, then you could just have such API construct a new value and that should not be a problem in safe code. Of course I don’t know your concrete “practical” use-case, so I cannot say for sure how straightforward this would or wouldn’t be.
As for how to solve the problem of using the same type sometimes with and sometimes “without” a lifetime, as hinted at in my first paragraph, all your current solution does is make writing “
'static” a bit simpler, and if you can live without that simplification, the straightforward solution is yet to just use something like
Cow<'static, T> for the owned lifetime-“free” version. (Though if you want to, you can of course use your own
enum, it doesn’t have to be
Cow itself.) If writing the
'static becomes too tedious, a type alias can help. E.g.
type LifetimeFreeCow<T> = Cow<'static, T>; (good names to be determined).
Of course, this still is a difference at the type level. If you do have a single type
Foo<'a> and use
Foo<'static> for the owned version, then removing any contained references and converting back to
Foo<'static> at the same time will still involve converting e.g.
Foo<'static> which safe code can only do by re-constructing the struct, and thus if the value was also boxed / on the heap, safe code could do this while re-allocating.
This reminds me, I had previously in some answer in this forum also suggested unsafe code for a “comparable” conversion of making a lifetime
'static safely because all contained references where removed. The use-case was something like
Vec<&'a Foo> which was supposed to be re-used in a loop, and each iteration put new local references into the
Vec, uses it, and then no longer needs the values, but unsafe was necessary to convert the
Vec<&'a Foo> back into
Vec<&'static Foo> after
.clean()-ing the vec, so it could escape the loop body, and be re-used in the next iteration (then variance could convert it back into a shorter-lived
Vec<&'a Foo> again to hold short-lived references). I’d say there might be some general design-work that could be done eventually for coming up with as-general-as-possible safe APIs for re-using allocations (of
Box or other things) while (slightly) changing the type, and where the contained values are dropped / removed / cleared / … to make the type conversion sound. Edit: Found the posts about that in case you’re interested; of course it’s only somewhat relevant for this use-case. Also I mis-remembered, the solution didn’t even involve
unsafe code directly but instead relied on specialized implementations for iterators and
Vec. Here’s one comment about such a case and it also links another related discussion.