1

I have a RwLock protected global WORLD, and I want to write a function that read locks it and returns an iterator (of type Neighbors) that iterates over edges in a petgraph::stable_graph::StableGraph that is stored inside the global. I'm using OwningRef to deal with keeping the read lock guard alive after the function exits, which has worked for me in the past when just returning a field of World directly. I've included a compilable example and the error I'm getting below -- it seems there is some sort of type problem but I haven't been able to figure it out. I think it might have to do with OwningRef wanting to deal with a reference rather than an object containing a reference (Neighbors) but I'm not sure how to work around that.

Cargo.toml:

[package]
name = "problem_demo"
version = "0.1.0"
authors = ["Joseph Garvin <joseph.h.garvin@gmail.com>"]
edition = "2018"

[dependencies]
owning_ref="0.4.1"
once_cell="1.4.0"
petgraph={version="0.5.1", features=["serde-1"]}

main.rs:

use std::{sync::RwLock};
use once_cell::sync::OnceCell;
use owning_ref::RwLockReadGuardRef;
use petgraph::stable_graph::{StableGraph, Neighbors};

struct Bar {
    data: i32
}

struct World {
    graph: StableGraph<(), Bar, petgraph::Directed, u32>
}

pub static WORLD: OnceCell<RwLock<World>> = OnceCell::new();

fn neighbors(id: u32) -> Result<RwLockReadGuardRef<'static, World, Neighbors<'static, Bar, u32>>, Box<dyn std::error::Error>> {
    RwLockReadGuardRef::new(WORLD.get().unwrap().read().unwrap())
        .try_map(
            |world: &World| -> std::result::Result<Neighbors<'static, Bar, u32>, Box<dyn std::error::Error>>
            {
                let neighbors = world.graph.neighbors_directed(
                    petgraph::graph::NodeIndex::new(id as usize),
                    petgraph::Direction::Outgoing
                );

                Ok(neighbors)
            }
        )
}

Errors:

error[E0271]: type mismatch resolving `for<'r> <[closure@src/main.rs:21:13: 29:14 id:_] as std::ops::FnOnce<(&'r World,)>>::Output == std::result::Result<&'r _, _>`
  --> src/main.rs:20:10
   |
20 |         .try_map(
   |          ^^^^^^^ expected struct `petgraph::stable_graph::Neighbors`, found reference
   |
   = note: expected enum `std::result::Result<petgraph::stable_graph::Neighbors<'static, Bar>, std::boxed::Box<dyn std::error::Error>>`
              found enum `std::result::Result<&_, _>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0271`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.
Joseph Garvin
  • 20,727
  • 18
  • 94
  • 165
  • Your function is defined as returning a non-ref Neighbors (embedded inside a lock gusrd embedded inside a Result) isn't it? – harmic Aug 22 '20 at 08:34
  • @harmic it is, but Neighbors contains a ref that depends on world, so I'm not sure how to correct it – Joseph Garvin Aug 22 '20 at 13:31
  • Somewhat off-topic, why are you using `try_map` and returning a `Result`? – Coder-256 Aug 23 '20 at 00:01
  • Also to answer your question, it seems that this is currently a [missing feature](https://github.com/Kimundi/owning-ref-rs/issues/59), and it seems to me that `owning_ref` is likely not actively maintained. – Coder-256 Aug 23 '20 at 00:19
  • 1
    Also note: https://github.com/Kimundi/owning-ref-rs/blob/677c5bbe33210e65ababfd46eeb2b7aaab41f94d/src/lib.rs#L1161-L1163 – Coder-256 Aug 23 '20 at 00:20
  • @Coder-256 using result is a artifact of trimming down from the larger real code base situation this is taken from :) In the real situation the code inside the closure can fail. – Joseph Garvin Aug 23 '20 at 15:51
  • @Coder-256: I'm lost enough in the types I'm not sure what that feature does or how it helps. Could you expand a little bit? Maybe I can figure out how to jigger it if I understand. – Joseph Garvin Aug 23 '20 at 15:56
  • I hate to break it to you, but AFAIK there's just no way to do this safely as of today. The problem is that `OwningRef` only works with references. `OwningHandle` is meant to work with smart pointers, but it currently only supports `RefCell`. It looks like `RwLock` support was planned, but it's hard to tell if that's still the case, or even if the crate is still well-maintained. – Coder-256 Aug 23 '20 at 19:05
  • And I am unaware of any alternative crates. One solution could be to implement this yourself ([ex. `RefCell`](https://github.com/Kimundi/owning-ref-rs/blob/677c5bbe33210e65ababfd46eeb2b7aaab41f94d/src/lib.rs#L1151-L1159)) but I'm not 100% sure if that's safe or even the right solution in your case. – Coder-256 Aug 23 '20 at 19:08
  • [`rental`](https://crates.io/crates/rental) would solve your problem, but it is [no longer supported](https://github.com/jpernst/rental). Personally I'm not sure what the best solution is here. – Coder-256 Aug 23 '20 at 19:11

0 Answers0