How to make OwningRef work with iterators? - rust

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.

Related

Passing a BufWriter to a function in Rust

In this example I'm trying to pass a BufWriter to some functions but don't understand generic type syntax enough to figure out whats missing.
Instead of passing the file, I want to pass the buffered writer and could not find any examples of this which would get me out of the weeds.
use std::fs::OpenOptions;
use std::io::BufWriter;
fn main() {
println!("Opening dummy read file");
let write = OpenOptions::new()
.write(true)
.create(true)
.open("DummyWriteFile");
let mut writer = BufWriter::new(write.unwrap());
// do some writes with FunctionA
write_something(&mut writer);
// write something else here with bufwriter
}
fn write_something(outBuf: BufWriter<W>) {}
The error I get is the following:
Compiling playground v0.0.1 (/playground)
error[E0412]: cannot find type `W` in this scope
--> src/main.rs:13:40
|
13 | fn write_something( outBuf: BufWriter <W> ){
| - ^ not found in this scope
| |
| help: you might be missing a type parameter: `<W>`
For more information about this error, try `rustc --explain E0412`.
error: could not compile `playground` due to previous error
You have a couple options.
To make that version of your code work, you need to add W as a generic parameter on the function with a Write bound. And you need to change it to take a mutable reference:
use std::io::Write;
fn write_something<W: Write>(out_buf: &mut BufWriter<W>) {
}
But what you probably want is to use the Write trait bound (since BufWriter impls it) instead of specifying BufWriter directly:
fn write_something(mut out_buf: impl Write) {
// OR: fn write_something<W: Write>(mut out_buf: W) {
}

Mutable optional OutputPin

I'm stuck with ownership; I but can't make the Option<OutputPin> in my function usable. How should it be?
struct Chip {
wake_pin: Option<OutputPin>,
}
impl Chip {
pub fn new(wake_pin: Option<Pin>) -> Chip {
Chip {
wake_pin: wake_pin.map(|pin| pin.into_output()),
}
}
pub fn awake(&self) {
// Fails
if let Some(pin) = self.wake_pin {
pin.set_low();
}
}
}
fn main() {
let wake_pin = Gpio::new()
.expect("Can not init gpio")
.get(255)
.expect("Could not attach to wake pin");
let chip = Chip::new(Some(wake_pin));
}
I am using the rppal crate and the compiler fails in the if let Some area. I tried to borrow wake_pin, get the Option as a reference and some other things but I don't understand the ownership rules completely.
I believe I've duplicated your set up. If something isn't right, please edit your question with the relevant details.
src/main.rs:
use rppal::gpio::{Gpio, OutputPin, Pin};
struct Chip {
wake_pin: Option<OutputPin>,
}
impl Chip {
pub fn new(wake_pin: Option<Pin>) -> Chip {
Chip {
wake_pin: wake_pin.map(|pin| pin.into_output()),
}
}
pub fn awake(&self) {
// Fails
if let Some(pin) = self.wake_pin {
pin.set_low();
}
}
}
fn main() {
let wake_pin = Gpio::new()
.expect("Can not init gpio")
.get(255)
.expect("Could not attach to wake pin");
let chip = Chip::new(Some(wake_pin));
}
Cargo.toml:
[package]
name = "tmp"
version = "0.0.1"
edition = "2018"
[dependencies]
rppal = "0.11.3"
Attempting to compile this (with cargo check or similar), we get a warning and two errors.
warning: unused variable: `chip`
--> src/main.rs:28:9
|
28 | let chip = Chip::new(Some(wake_pin));
| ^^^^ help: consider prefixing with an underscore: `_chip`
|
= note: `#[warn(unused_variables)]` on by default
error[E0507]: cannot move out of `self.wake_pin.0` which is behind a shared reference
--> src/main.rs:16:28
|
16 | if let Some(pin) = self.wake_pin {
| --- ^^^^^^^^^^^^^ help: consider borrowing here: `&self.wake_pin`
| |
| data moved here
| move occurs because `pin` has type `rppal::gpio::pin::OutputPin`, which does not implement the `Copy` trait
error[E0596]: cannot borrow `pin` as mutable, as it is not declared as mutable
--> src/main.rs:17:13
|
16 | if let Some(pin) = self.wake_pin {
| --- help: consider changing this to be mutable: `mut pin`
17 | pin.set_low();
| ^^^ cannot borrow as mutable
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0507, E0596.
For more information about an error, try `rustc --explain E0507`.
error: Could not compile `tmp`.
To learn more, run the command again with --verbose.
Since you're presumably going to use chip later, we can silence the warning by temporarily renaming it to _chip.
let _chip = Chip::new(Some(wake_pin));
The first error tells us that we can't move the pin out of self since we're only borrowing self. It would be rather rude to invalidate the data behind self if we're only borrowing it. However, the compiler is telling us a solution. help: consider borrowing here: `&self.wake_pin`
It ends up not quite being right, but it's the right direction.
if let Some(pin) = &self.wake_pin {
pin.set_low();
}
Now instead of pin having type OutputPin (an owned value), it has type &OutputPin (a borrowed value).
We still get the second error though (with a slightly different phrasing). The point is that pin.set_low() requires pin to be a mutable reference. Right now, we're taking self as an immutable reference (pub fn awake(&self)). If we're going to mutate self or any of its fields, we need to take it mutably. This also means we need to make sure pin is borrowed mutably.
pub fn awake(&mut self) {
if let Some(pin) = &mut self.wake_pin {
pin.set_low();
}
}

Creating a cyclic Tokio stream connected to a shared state

I am running into a problem that I do not really understand and hoped
that somebody might be able to see what I have misunderstood.
The problem is quite straightforward: I have a global state (shared
between several tasks) and want to have an infinite cycle over a
vector in the global state. I will then zip that with an interval
stream and hence get a regular emission of the next value in the
stream.
If the vector in the state changes, the inifinite stream should just
reload the vector and start reading from the new one instead, and
discard the old array.
Here is the code that I've gotten this far, and the questions are at
the end of the post.
use futures::stream::Stream;
use futures::{Async, Poll};
use std::iter::Cycle;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use tokio::timer::Interval;
We define a global state that hold an array that can be
updated. Whenever the array is updated, we will step the version and
set the array.
struct State<T> {
version: u32,
array: Vec<T>,
}
impl<T> State<T> {
fn new(array: Vec<T>) -> Self {
Self {
version: 0,
array: Vec::new(),
}
}
fn update(&mut self, array: Vec<T>) {
self.version += 1;
self.array = array;
}
}
Now, we create an stream over the state. When initialized, it will
read the array and version from the state and store it and then keep
an instance of std::iter::Cycle internally that will cycle over the
array.
struct StateStream<I> {
state: Arc<Mutex<State<I::Item>>>,
version: u32,
iter: Cycle<I>,
}
impl<I> StateStream<I>
where
I: Iterator,
{
fn new(state: Arc<Mutex<State<I::Item>>>) -> Self {
let (version, array) = {
let locked_state = state.lock().unwrap();
(locked_state.version, locked_state.array)
};
Self {
state: state,
version: version,
iter: array.iter().cycle(),
}
}
}
We now implement the stream for the StateStream. With each poll, it
will check if the version of the state changed, and if it did, reload
the array and version.
We will then take the next item from the iterator and return that.
impl<I> Stream for StateStream<I>
where
I: Iterator + Clone,
{
type Item = I::Item;
type Error = ();
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let locked_state = self.state.lock().unwrap();
if locked_state.version > self.version {
self.iter = locked_state.array.clone().iter().cycle();
self.version = locked_state.version;
}
Ok(Async::Ready(self.iter.next()))
}
}
The main program looks like this. I do not update the vector here, but
that is not important for the case at hand.
fn main() {
let state = Arc::new(Mutex::new(State::new(vec![2, 3, 5, 7, 11, 13])));
let primes = StateStream::new(state)
.take(20)
.zip(
Interval::new(Instant::now(), Duration::from_millis(500))
.map_err(|err| println!("Error: {}", err)),
)
.for_each(|(number, instant)| {
println!("fire; number={}, instant={:?}", number, instant);
Ok(())
});
tokio::run(primes);
}
When compiling this, I get the following errors:
cargo run --example cycle_stream_shared
Compiling tokio-testing v0.1.0 (/home/mats/crates/tokio-examples)
error[E0308]: mismatched types
--> examples/cycle_stream_shared.rs:66:19
|
66 | iter: array.iter().cycle(),
| ^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter`
|
= note: expected type `std::iter::Cycle<I>`
found type `std::iter::Cycle<std::slice::Iter<'_, <I as std::iter::Iterator>::Item>>`
error[E0308]: mismatched types
--> examples/cycle_stream_shared.rs:81:25
|
81 | self.iter = locked_state.array.clone().iter().cycle();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter`
|
= note: expected type `std::iter::Cycle<I>`
found type `std::iter::Cycle<std::slice::Iter<'_, <I as std::iter::Iterator>::Item>>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
error: Could not compile `tokio-testing`.
To learn more, run the command again with --verbose.
Now, the error and the explanation says that the concrete type is not
possible to derive, but in this case, I am using the generic struct
Cycle<I> and expect I to be instantiated to std::slice::Iter<'_,
I::Item>. Since std::slice::Iter has implemented Iterator and, the type have implemented all necessary traits to match.
Some answers to similar questions exist, but nothing that seems to
match this case:
“Expected type parameter” error in the constructor of a generic
struct is showing that the types do not match (same
as the explanation gives) because the generic struct definition allow any type, but the construction require a specific type.
In this case, we are using a generic type Cycle<I>, where I should implement the Iterator trait, and try to use a type std::slice::Iter<..> that does implement Iterator.
How do I return an instance of a trait from a
method? talk about how to return an arbitrary type
matching a trait, which is not the case here.
The other questions are mostly referring to these two, or variations
of these.
Update: Changed it to be a generic type to demonstrate that it still does not work.

How to write a proper generic function signature when borrowing data across multiple traits

While developing on a private project I ran into a lifetime problem related to borrowing the same object over multiple structs and traits. This is a bunch of stripped-down definitions I used:
trait WorkspaceLog {
fn get(&self) -> usize;
}
struct TheLog<'a>(&'a FilesystemOverlay);
impl<'a> WorkspaceLog for TheLog<'a> {
fn get(&self) -> usize {
(self.0).0
}
}
trait WorkspaceController<'a> {
type Log: WorkspaceLog;
fn get_log(&'a self) -> Self::Log;
}
struct FilesystemOverlay(usize);
struct FSWorkspaceController<'a>(&'a mut FilesystemOverlay);
impl<'a> WorkspaceController<'a> for FSWorkspaceController<'a> {
type Log = TheLog<'a>;
fn get_log(&'a self) -> Self::Log {
TheLog(&*self.0)
}
}
trait AsWorkspaceController<'a> {
type Controller: WorkspaceController<'a>;
fn get_controller(self) -> Self::Controller;
}
impl<'a> AsWorkspaceController<'a> for &'a mut FilesystemOverlay {
type Controller = FSWorkspaceController<'a>;
fn get_controller(self) -> FSWorkspaceController<'a> {
FSWorkspaceController(self)
}
}
So far, so good. This basically enables me to borrow a mut ref of FilesystemOverlay as some other interface, providing additional functionality. This interface, in turn, allows me to borrow essentially the same thing as yet another thing that provides the final data. This works as long a I directly use FilesystemOverlay:
fn init1(control_dir: &mut FilesystemOverlay) -> usize {
let controller = control_dir.get_controller();
let log = controller.get_log();
log.get()
}
However, if I replace the concrete reference with a type parameter, the compilation fails, telling me that controller doesn't live long enough since it, for reasons I don't understand, thinks that get_log borrows controller beyond the end of the function and thus way longer than the program logic
requires:
fn init2<'a: 'b, 'b, O>(control_dir: O) -> usize
where O: AsWorkspaceController<'b>+'a {
let controller = control_dir.get_controller();
let log = controller.get_log();
log.get()
}
fn main() {
let mut control_dir = FilesystemOverlay(5);
dbg!(init1(&mut control_dir));
dbg!(init2(&mut control_dir));
}
I tried several approaches but I so far were unable to figure out the proper signature of init2. This is the error I get:
error[E0597]: `controller` does not live long enough
--> test.rs:53:15
|
53 | let log = controller.get_log();
| ^^^^^^^^^^ borrowed value does not live long enough
54 | log.get()
55 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'b as defined on the function body at 50:18...
--> test.rs:50:18
|
50 | fn init2<'a: 'b, 'b, O>(control_dir: O) -> usize
| ^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.
This is the full code on the rust playground.
So, how do I need to change the signature of init2 so that the compiler understands that controller may be dropped after the call to log.get()? Do I need other changes in the above types as well?
Edit: I've made some additional experiments and this is the closest I could manage to create. This one has two lifetimes and a signature that late-binds, but it still gives a warning about UB. Does anyone understand why?
With the help of a nice and knowing person on GitHub I was able to create a working version of the code, see https://github.com/rust-lang/rust/issues/58868. The key was to use a free lifetime bound on the type declaration of Controller inside AsWorkspaceController:
trait AsWorkspaceController<'a> {
type Controller: for<'b> WorkspaceController<'b>+'a;
fn get_controller(&'a mut self) -> Self::Controller;
}
See the full code on the playground.

What does the Rust error code E0495 mean?

I'm using Rocket to make a web server and I'm trying to make a wrapper around the Responder trait so that my route methods can return any struct.
The code below does not compile because of an error about lifetimes that I don't fully understand. The error is not listed in the error index; it skips from E0492 to E0496.
Since this code uses Rocket, it requires the nightly compiler.
main.rs
#![feature(custom_attribute, proc_macro_hygiene, decl_macro)]
#[macro_use]
extern crate rocket;
extern crate rocket_contrib;
use rocket::{http::Status, response::Responder, Request};
use rocket_contrib::templates::Template;
fn main() {
rocket::Rocket::ignite().mount("/", routes![route]).launch();
}
#[get("/")]
fn route<'a>() -> DynamicResponder<'a> {
DynamicResponder::from(Template::render("template", ()))
}
struct DynamicResponder<'a> {
inner: Box<dyn Responder<'a> + 'a>,
}
impl<'r> DynamicResponder<'r> {
pub fn from<T: 'r>(responder: T) -> DynamicResponder<'r>
where
T: Responder<'r>,
{
DynamicResponder {
inner: Box::new(responder),
}
}
}
impl<'r> Responder<'r> for DynamicResponder<'r> {
fn respond_to<'b>(
self,
request: &'b Request,
) -> Result<rocket::response::Response<'r>, Status> {
self.inner.respond_to(request)
}
}
Cargo.toml
[package]
name = "rocketing_around"
version = "0.1.0"
[dependencies]
rocket = "0.4.0"
[dependencies.rocket_contrib]
version = "0.4.0"
default_features = false
features = [ "handlebars_templates" ]
Compiler message:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'r` due to conflicting requirements
--> src/main.rs:15:5
|
15 | DynamicResponder::from(Template::render("template", ()))
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 14:10...
--> src/main.rs:14:10
|
14 | fn route<'a>() -> DynamicResponder<'a> {
| ^^
= note: ...so that the expression is assignable:
expected DynamicResponder<'a>
found DynamicResponder<'_>
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the types are compatible:
expected rocket::response::Responder<'_>
found rocket::response::Responder<'static>
What does the Rust error code E0495 mean?
The error code E0495 seems to be a catch-all for a variety of different situations where lifetime requirements can't be reconciled. The message already says that, and there are huge number of ways that you could write code where lifetimes don't match up properly, which is perhaps why it isn't listed with examples in the error index.
Type parameters, including lifetimes, are always determined by the caller. Looking at your particular example, a function signature like this:
fn route<'a>() -> DynamicResponder<'a> { ... }
means that, for any lifetime 'a chosen by the caller, references inside the returned DynamicResponder<'a> must be valid. But what could the references inside DynamicResponder<'a> even be in this situation? They can't be references to variables in the function body because those only live as long as the function. There are no arguments, so the only things that could be referenced by the DynamicResponder<'a> are things that live outside the function, i.e. statics.
You can fix the error by removing the lifetime variable and setting the lifetime parameter to the only lifetime that makes sense:
fn route() -> DynamicResponder<'static> { ... }

Resources