Resolve<'a> {
fn resolve(ctx: &'a String) -> Self;
}
struct Foo<'a> {
inner: &'a String
}
impl<'a> Resolve<'a> for Foo<'a> {
fn resolve(ctx: &'a String) -> Self {
Foo {
inner: &ctx
}
}
}
struct Bar;
impl<'a> Resolve<'a> for Bar {
fn resolve(_ctx: &'a String) -> Self {
todo!()
}
}
trait System<'a, A> {
fn run(&self, ctx: &'a String);
}
impl<'a, A, T> System<'a, A> for T where T: Fn(A), A: Resolve<'a> {
fn run(&self, ctx: &'a String) {
let x = A::resolve(ctx);
(self)(x)
}
}
fn foo(_foo: Foo) {}
fn bar(_bar: Bar) {}
fn box_fn<A>(x: impl for<'a> System<'a, A> + 'static) -> Box<dyn Fn(&String)> {
Box::new(move |ctx| x.run(ctx))
}
fn main() {
// implementation of System is not general enough
box_fn(foo);
box_fn(bar);
}
#implementation of resolve is not generic enough
18 messages · Page 1 of 1 (latest)
Im currently trying to add lifetimes to my framework and I've come across this. I want to provide a mechanism to make parameters that are resolvable without owning their values to avoid cloning large amounts of data. This is the minimum example of what I am doing
Your code got cut off (particularly for what might be the important part)
Also, you didn't provide the actual error output
Cut off? No it didnt
error: implementation of `System` is not general enough
--> src/main.rs:46:5
|
46 | box_fn(foo);
| ^^^^^^^^^^^ implementation of `System` is not general enough
|
= note: `for<'a> fn(Foo<'a>) {foo}` must implement `System<'0, Foo<'_>>`, for any lifetime `'0`...
= note: ...but it actually implements `System<'1, Foo<'_>>`, for some specific lifetime `'1````
My bad then, but its only the word trait
A the function-parameter for the System implementation and 'a the unbounded lifetime are disjoint, and A is just as the error says, a particular lifetime
Think about box_fn<A>(...), that A can't satisfy for<'a> System<'a, A> unless A: 'static
I am aware of why this fsils
Fails
I dont have a good solution to represent this
I understand this does not represent a universal singular implementation but that is what I would like
You could do something like this I think....essentially make the Resolve trait allow a different type as output than Self.....this way it doesn't matter what lifetime it uses initially for Foo (deduced from the function passed in), it can still resolve it to the correct lifetime when resolved with a specific string of that lifetime. It does leave it upto the implementor though to make sure they produce the correct type as output
?play
trait Resolve<'a> {
type Output;
fn resolve(ctx: &'a String) -> Self::Output;
}
#[derive(Debug)]
struct Foo<'a> {
_inner: &'a String
}
impl<'a, 'b> Resolve<'b> for Foo<'a> {
type Output = Foo<'b>;
fn resolve(ctx: &'b String) -> Self::Output {
Foo {
_inner: &ctx
}
}
}
#[derive(Debug)]
struct Bar;
impl<'a> Resolve<'a> for Bar {
type Output = Self;
fn resolve(_ctx: &'a String) -> Self::Output {
Self
}
}
trait System<'a, A> {
fn run(&self, ctx: &'a String);
}
impl<'a, A, T> System<'a, A> for T where T: Fn(A) + Fn(A::Output), A: Resolve<'a> {
fn run(&self, ctx: &'a String) {
let x = A::resolve(ctx);
(self)(x)
}
}
fn foo(foo: Foo) {
println!("Calling foo with {foo:?}");
}
fn bar(bar: Bar) {
println!("Calling bar with {bar:?}");
}
fn box_fn<A>(x: impl for<'a> System<'a, A> + 'static) -> Box<dyn Fn(&String)> {
Box::new(move |ctx| x.run(ctx))
}
fn main() {
let foo_boxed = box_fn(foo);
let bar_boxed = box_fn(bar);
let string = String::from("Hello, World!");
foo_boxed(&string);
bar_boxed(&string);
}
Calling foo with Foo { _inner: "Hello, World!" }
Calling bar with Bar```