someguynamedjosh / ouroboros

Easy self-referential struct generation for Rust.
Apache License 2.0
526 stars 33 forks source link

Can't refer to 'this in generic bounds? #50

Open tornewuff opened 2 years ago

tornewuff commented 2 years ago
use std::io::Read;
struct Foo<R: Read>(R);
struct Bar<'a, R: Read + 'a>(&'a Foo<R>);

#[ouroboros::self_referencing]
struct Test<R: Read + 'this> {
    foo: Foo<R>,
    #[borrows(foo)]
    #[covariant]
    bar: Bar<'this, R>,
}

I'm trying to define a selfreferencing structure where the referencing type needs a lifetime on its generic parameter, but adding 'this doesn't work - it reports it as an undeclared lifetime.

Am I going about this wrong? Is this possible to support?

someguynamedjosh commented 2 years ago

Unfortunately, ouroboros does not support this use case. The primary difficulty is that the generic parameter is used in places that aren't self-referencing, such as the Heads struct returned by .into_heads(). Theoretically, this might be supportable if ouroboros can detect which fields generic parameters are used in, but that is a level of complexity I am not willing to add at the moment.

On Sat, Nov 27, 2021 at 5:30 PM Torne Wuff @.***> wrote:

use std::io::Read;struct Foo(R);struct Bar<'a, R: Read + 'a>(&'a Foo);

[ouroboros::self_referencing]struct Test<R: Read + 'this> {

foo: Foo<R>,
#[borrows(foo)]
#[covariant]
bar: Bar<'this, R>,

}

I'm trying to define a selfreferencing structure where the referencing type needs a lifetime on its generic parameter, but adding 'this doesn't work - it reports it as an undeclared lifetime.

Am I going about this wrong? Is this possible to support?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/joshua-maros/ouroboros/issues/50, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOL2YRLTOLDWHKIKOZQ3ZJ3UOGA2FANCNFSM5I4WXJXA .

JohnScience commented 2 years ago

I needed that too to store an iterator. I've made a workaround with a specific type

pub(super) type EnumeratedDepsLinsIter<'a> = Filter<
    Map<Enumerate<Lines<'a>>, fn((usize, &str)) -> (usize, &str)>,
    fn(&(usize, &str)) -> bool
>;

and something like this

        // The closures are coerced to function pointers so that their types could be named.
        //
        // Quting the reference, "A closure expression produces a closure value with a unique,
        // anonymous type that cannot be written out.".
        //
        // Source: https://doc.rust-lang.org/reference/types/closure.html
        // 
        // The type of the whole iterator is needed so that ouroboros crate could handle the
        // field of the type of the iterator.
        let trim_lines: fn((usize, &str)) -> (usize, &str) = |(i, line)| (i, line.trim());
        let is_trimmed_dep_line: fn(&(usize, &str)) -> bool = |(_i, line)| line.starts_with(":dep");

but it's ugly.

JCBurnside commented 6 months ago

damn I was looking for this exactly. I needed to store a context and a codegen struct I am making for llvm. since if the context gets dropped it would create an issue for generated modules being invalidated. guess i'll have to look else where.

koutheir commented 3 months ago

For anyone interested, I switched to the self_cell crate in order to work around this issue.

fzyzcjy commented 3 months ago

Hi, is there any updates? Thanks!

fzyzcjy commented 3 months ago

The primary difficulty is that the generic parameter is used in places that aren't self-referencing, such as the Heads struct returned by .into_heads().

Then is it possible that, when using Bar<'this>, the Heads features are disabled? In my scenario (hoping to use this in https://github.com/fzyzcjy/flutter_rust_bridge), I only need to borrow the bar, and no need for functions like into_heads.

EDIT: I realize I do not need this in generics bounds. Thanks for the library and it works!