Hey,
I am trying to solve the following problem:
- Take some
Args
definition, such as a tuple(S, A)
. - Can I define a function that takes the original value or any combination of inner references, e.g.
(&S, A)
,(S, &A)
or(&S, &A)
, without multiple trait implementations.
Below I have appended a demo that gives you some idea of my thinking.
This, unfortunately, doesn't fit within the remit of Borrow
or AsRef
as the associated type needs to be parameterised by lifetimes. I suspect this is not something that can be implemented without GATs...
Does anyone have any suggestions?
Just a note on motivation:
- The
Function
trait here has an associated type which must be the same for all reference combinations mentioned above. - With references themselves being treated as unique types (a good thing I would add), this leads to some rather hideous type constraints.
- I would ideally have the constraint given as, say,
Function<(S, A)>
, and have this automatically support all of the aforementioned reference variants.
Many thanks,
Tom
pub trait Args<'a> {
type Borrowed: 'a;
}
impl<'s, S: 's> Args<'s> for (S,) {
type Borrowed = (&'s S,);
}
pub trait BorrowArgs<'a, A: Args<'a>> {
fn borrow_args(&self) -> A::Borrowed;
}
impl<'s, S: 's> BorrowArgs<'s, (S,)> for (S,) {
fn borrow_args(&self) -> (&'s S,) { (&self.0,) }
}
impl<'s, S: 's> BorrowArgs<'s, (S,)> for (&S,) {
fn borrow_args(&self) -> (&'s S,) { (&self.0,) }
}
pub trait Function<A: for<'a> Args<'a>> {
type Output;
fn test<B: for<'a> BorrowArgs<'a, A>>(&self, _: B) -> Self::Output;
}
pub struct Demo;
impl Function<(f64,)> for Demo {
type Output = bool;
fn test<B: for<'a> BorrowArgs<'a, (f64,)>>(&self, _: B) -> bool { true }
}
fn main() {
println!("{:?}", Demo.test((&1.0,)));
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:14:42
|
14 | fn borrow_args(&self) -> (&'s S,) { (&self.0,) }
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 14:5...
--> src/main.rs:14:5
|
14 | fn borrow_args(&self) -> (&'s S,) { (&self.0,) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:14:42
|
14 | fn borrow_args(&self) -> (&'s S,) { (&self.0,) }
| ^^^^^^^
note: but, the lifetime must be valid for the lifetime `'s` as defined on the impl at 13:6...
--> src/main.rs:13:6
|
13 | impl<'s, S: 's> BorrowArgs<'s, (S,)> for (S,) {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:14:42
|
14 | fn borrow_args(&self) -> (&'s S,) { (&self.0,) }
| ^^^^^^^
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/main.rs:18:42
|
18 | fn borrow_args(&self) -> (&'s S,) { (&self.0,) }
| ^^^^^^^
|
note: ...the reference is valid for the lifetime `'s` as defined on the impl at 17:6...
--> src/main.rs:17:6
|
17 | impl<'s, S: 's> BorrowArgs<'s, (S,)> for (&S,) {
| ^^
note: ...but the borrowed content is only valid for the lifetime `'_` as defined on the impl at 17:43
--> src/main.rs:17:43
|
17 | impl<'s, S: 's> BorrowArgs<'s, (S,)> for (&S,) {
| ^
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0312, E0495.
For more information about an error, try `rustc --explain E0312`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.