Can't wrap 2 structs in Ouroboros

Struct FgbReader takes mutable reference to opened file [definition of the struct], so after I open an FgbReader, I must keep both vars within one scope (may pass FgbReader down the stack, but not the File).

	let mut myfile = File::open("local.fgb")?;
	let myreader: FgbReader<'a, File, FeaturesSelectedSeek> =
            FgbReader::open(&mut myfile)?.select_all()?;
    while let Ok(...) = myreader.next() { ... }

I'm trying to pack both myfile and myreader into a self-ref struct (like what's been discussed in this thread) with Ouroboros. After looking at examples, here's what I came up with:

#[self_referencing]
struct FgbDriver<'a> {
	fp: File,
	#[borrows(mut fp)]
	features_selected: FgbReader<'a, File, FeaturesSelectedSeek>,
	_p: PhantomData<&'a bool>

}

fn make_fgb<'a>(path: &str) -> Result<FgbDriver<'a>, Box<dyn Error>> {
	let mut fp = File::open(path)?;
	Ok(FgbDriverBuilder {
		fp,
		features_selected_builder: |fp| FgbReader::open(fp).unwrap().select_all().unwrap()
	}.build())
}

Compiler tells me that 'this is unused, and I should put it in PhantomData:

5 | #[self_referencing]
  | ^^^^^^^^^^^^^^^^^^^ unused parameter
  |
  = help: consider removing `'this`, referring to it in a field, or using a marker such as `std::marker::PhantomData`

Switching _p to 'this results in lifetime errors:

_p: PhantomData<&'this bool>

Errors:

10 |     _p: PhantomData<&'this bool>
   |         ^^^^^^^^^^^^^^^^^^^^^^^^

error[E0261]: use of undeclared lifetime name `'this`
  --> src/main.rs:10:19
   |
5  | #[self_referencing]
   | ------------------- lifetime `'this` is missing in item created through this procedural macro
...
10 |     _p: PhantomData<&'this bool>
   |                      ^^^^^ undeclared lifetime

error: lifetime may not live long enough
  --> src/main.rs:10:2
   |
6  | struct FgbDriver<'a> {
   |                  -- lifetime `'a` defined here
...
10 |     _p: PhantomData<&'this bool>
   |     ^^ assignment requires that `'a` must outlive `'static`

So, if I put 'this somewhere in the struct, compiler says it's undeclared. If I put it into struct definition, like FgbDriver<'a, 'this>, compiler tells me it shadows 'this in macro.

What should I do?

The ouroboros macro is defined such that 'this is only usable in fields marked as #[borrows(…)] which is why putting 'this into the phantom data field failed. You don’t want either of the <'a> nor the marker field though. Simply

#[self_referencing]
struct FgbDriver {
    fp: File,
    #[borrows(mut fp)]
    #[covariant]
    features_selected: FgbReader<'this, File, FeaturesSelectedSeek>,
}

The compilation error about 'this being unused didn’t talk of the FgbDriver struct, but one of the helper struct generated by the self_referencing macro, so the compiler suggestions of adding a PhantomData do not apply, since you wouldn’t be directly modifying the struct in question; due to how the macro is implemented, only using 'this in one of the marked-#[borrows(…)] struct can fix that issue.

2 Likes

Great, this worked!

Ouroboros that you suggested in that thread was the only solution to my struggles with FlatGeobuf crate.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.