I have a trait, Relation
(a relational algebra table) that is modeled a bit after how Iterator
works, in that its methods generally consume self
, and there are usually distinct implementations for T
and &T
.
Because the main operations are consuming, I need a way to let users run multiple queries against the same table. To do this, I'd like to provide access to the &T
implementation (if it exists) via a method that doesn't consume the original. When trying to implement this, I could only manage to make a lifetime-invariant trait, which basically limits its usefulness to 'static
types.
An alternative that I considered is to require both T
and &T
implementations, and then provide a blanket &&T
one, but I ran into a similar issue: I can't require for<'a> &'a T: ...
because it restricts T
to be static-- as far as I can tell, there's no way to restrict the HRTB to only those lifetimes that T
is valid for.
The goal here is to be able to call a function that returns impl Viewable<...>
, and be able to generate views that access the data in that viewable without cloning the whole thing. Can anyone else see a way to make this happen?
pub trait Relation {}
// Doesn't need to preserve old data
impl<R> Relation for Vec<R> {}
// Same results as above, but may need to make copies
impl<'view, R:'view> Relation for &'view [R] {}
// ================================
// Semantically, can support a view with lifetime exactly 'view
// Would prefer any lifetime contained in 'view, is that possible?
pub trait Viewable<'view>: Relation {
type View: Relation + 'view;
fn view<'s:'view>(&'s self)->Self::View;
}
// Vec can provide references to its records without destroying them
impl<'view, R:'view> Viewable<'view> for Vec<R> {
type View= &'view [R];
fn view<'s:'view>(&'s self)->Self::View { &self[..] }
}
// TODO: Implement Viewable for &[R] where Self::View=Self
// This works, but I'd prefer to return impl Viewable<'static> if possible
pub fn f_static()->impl for<'a> Viewable<'a> {
vec![42]
}
// This is a better proxy for my use case. It compiles, but can't be used.
pub fn f_ref<'x>(x:&'x usize)->impl Viewable<'x> {
vec![x]
}
pub fn f_view() {
{
let rel = f_static();
rel.view();
}
{
let x:usize = 42;
let rel = f_ref(&x);
rel.view(); // Commenting out this line clears the compile error
}
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0597]: `rel` does not live long enough
--> src/lib.rs:45:9
|
45 | rel.view(); // Commenting out this line clears the compile error
| ^^^ borrowed value does not live long enough
46 | }
| -
| |
| `rel` dropped here while still borrowed
| borrow might be used here, when `rel` is dropped and runs the destructor for type `impl Viewable<'_>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
Warnings
No main function was detected, so your code was compiled
but not run. If you’d like to execute your code, please
add a main function.