I am having trouble with some lifetime stuff. Let me first say what I'm trying to do, hopefully that will make it clearer what the intention is.
Essentially I have a kind of storage object from which views into the storage can be constructed. Views can be constructed from other views and so on. Most of these views are pretty straightforward to implement, but there's one in particular I'm having trouble with.
This view "negates" another predicate-based view (i.e., Not<V>
), but this only makes sense if V
itself has another internal view (i.e. WrapperView<V>
for some V
, so it could look like Not<WrapperView<V>>
). So I need to be able to access the sub-sub-view and thus I created a trait for doing so:
trait AsInnerRef<'a> {
type Inner: 'a;
fn as_inner(&'a self) -> Self::Inner;
}
(I return Self::Inner
instead of &Self::Inner
because I need to be able to return newly constructed objects that contain the references themselves in some cases).
There are certain operations that can be performed on views, for the purposes of this question I am having trouble implementing two in particular for Not
trait Contains {
fn contains(&self) -> bool;
}
trait Remove {
type Item;
fn remove(&mut self) -> Self::Item;
}
I will only focus on Contains
for now. I have my sub-views, these aren't really important other than to use them in the Not
view below to show the error:
struct FlatView<'a>(&'a u32);
impl Contains for &FlatView<'_> {
fn contains(&self) -> bool {
true
}
}
struct WrapperView<V>(V);
impl<'a, V: 'a> AsInnerRef<'a> for WrapperView<V> {
type Inner = &'a V;
fn as_inner(&'a self) -> Self::Inner {
&self.0
}
}
impl<V: Contains> Contains for WrapperView<V> {
fn contains(&self) -> bool {
self.0.contains()
}
}
Then I have my Not
view and its implementations which is where things break.
struct Not<V>(V);
impl<V> Contains for Not<V>
where
for<'a> V: AsInnerRef<'a>,
for<'a> <V as AsInnerRef<'a>>::Inner: Contains
{
fn contains(&self) -> bool {
self.0.as_inner().contains()
}
}
(I was originally naming the lifetime explicitly which caused immediate compilation failure, someone in the Discord chat helped me to this part)
If I actually try to use this like so, it fails:
fn main() {
let storage = 5;
let view = Not(WrapperView(FlatView(&storage)));
view.contains();
}
57 | let view = Not(WrapperView(FlatView(&storage)));
| ^^^^^^^^ borrowed value does not live long enough
58 | view.contains();
| --------------- argument requires that `storage` is borrowed for `'static`
59 | }
| - `storage` dropped here while still borrowed
The closest topic I've come across similar to this is Argument requires that ... is borrowed for `'static`, but I have been unable to adopt the solution there using the 'upper_bound
lifetime. I tried putting it on AsInnerRef
with a corresponding 'upper_bound: 'a
bound and passing an explicit 'upper_bound
to the Not
Contains
implementation, but to no avail.
The full code for the above is here Rust Playground.
I mentioned above I was also having trouble implementing the Remove
operation. The setup is identical except the trait I'm implementing: Rust Playground. Here I really don't know what lifetime I could choose for the associated type type Item = <<V as AsInnerMut<'a>>::Inner as Remove>::Item;
('a
is not a lifetime in scope).
I'd appreciate any help, thanks in advance!