How to call a `dyn Fn` which is a field? - rust

struct DummyRtspClient<'a> {
on_produce: &'a dyn Fn(EncodedPacket)
}
impl ... for DummyRtspClient {
fn set_on_produce(&self, f: &'a dyn Fn(EncodedPacket)){
self.on_produce = f;
}
}
Then how can I use on_produce?
I tried
let encoded_packet = EncodedPacket{
data: Vec::new(),
};
self.on_produce(encoded_packet);
but it says that on_produce is not a member function, but a field.
I tried self.on_produce.call(encoded_packet) but I also get errors.

Your error message should say something like this:
error[E0599]: no method named `on_produce` found for reference `&DummyRtspClient<'a>` in the current scope
--> src/lib.rs:14:18
|
14 | self.on_produce(encoded_packet);
| ^^^^^^^^^^ field, not a method
|
help: to call the function stored in `on_produce`, surround the field access with parentheses
|
14 | (self.on_produce)(encoded_packet);
| ^ ^
In particular, the second part tells exactly you how to solve this: wrap self.on_produce in a set of parentheses to disambiguate it from attempting to call a member function.

Related

Can you specify the lifetime of a moved self parameter?

I have a newtype struct:
pub struct Branch<'repo>(Git2Branch<'repo>);
And I am trying to wrap a method call:
impl <'repo> Branch<'_> {
pub fn into_reference(self) -> Git2Reference<'repo> {
self.0.into_reference()
}
}
(Git2Branch and Git2Reference here are aliases for types of the same name from the git2 crate.)
This fails to compile with
error: lifetime may not live long enough
--> git_wrapper/src/branch.rs:38:9
|
6 | impl <'repo> Branch<'_> {
| ----- lifetime `'repo` defined here
...
37 | pub fn into_reference(self) -> Git2Reference<'repo> {
| ---- has type `branch::Branch<'1>`
38 | self.0.into_reference()
| ^^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'repo` but it is returning data with lifetime `'1`
Lifetimes '1 and 'repo should be the same, but I can't figure out how (or if it's even possible) to specify the lifetime of self in this case.
impl <'repo> Branch<'_> {
Is the same as:
impl <'repo, 'anonymous> Branch<'anonymous> {
So the lifetimes 'repo and the anonymous lifetime of the field are unrelated - which causes an issue when you try to return the Git2Reference<'anonymous>.
You only need to talk about one lifetime here, so say that:
impl <'repo> Branch<'repo> {

Constraint associated type of a generic associated type

I have a type Builder with a Generic Associated Type (GAT) InstanceForBuilder<'a>.
I'd like to write a function (build_with_42_for_bool<Builder>) that constraints the Builder to only those cases where Builder::InstanceForBuilder<'a>::InstanceProperty == bool (for all 'a).
I've been playing around for a while to get the syntax around this for <'a> right, but haven't been able to make this work.
The lifetime can't be a template argument of the function itself, because the reference only lives inside it.
Is this possible at all yet, given that GAT is an unstable feature?
playground
#![feature(generic_associated_types)]
// Trait definitions.
trait Builder {
type InstanceForBuilder<'a>: Instance<'a>;
fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a>;
}
trait Instance<'a> {
// Some functions will only work when the instance has some concrete associated type.
type InstanceProperty;
}
fn build_with_42_for_bool<B: Builder>(builder: B)
where
// TODO: What do I put here to make this work?
for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
{
builder.build(&42);
// Do some testing here. The Instance won't be returned.
}
// Now try it out.
struct MyBuilder;
struct MyInstance<'a> {
val: &'a usize,
}
impl Builder for MyBuilder {
type InstanceForBuilder<'a> = MyInstance<'a>;
fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a> {
MyInstance { val }
}
}
impl<'a> Instance<'a> for MyInstance<'a> {
type InstanceProperty = bool;
}
fn main() {
let builder = MyBuilder;
build_with_42_for_bool(builder); // TODO: Doesn't work
}
In my actual code, build_with_42_for_bool is a helper for testing that constructs the arguments passed to build in a specific way. For now I'll probably just inline that function everywhere, since the only problem is how to specify the lifetime of this one function. The code itself works fine.
Here's the full error:
Compiling pairwise-aligner v0.1.0 (/home/philae/git/eth/git/astar-pairwise-aligner)
error[E0271]: type mismatch resolving `for<'a> <<_ as Builder>::InstanceForBuilder<'a> as Instance<'a>>::InstanceProperty == bool`
--> examples/test.rs:45:5
|
45 | build_with_42(builder); // TODO: Doesn't work
| ^^^^^^^^^^^^^ expected `bool`, found associated type
|
= note: expected type `bool`
found associated type `<<_ as Builder>::InstanceForBuilder<'_> as Instance<'_>>::InstanceProperty`
= help: consider constraining the associated type `<<_ as Builder>::InstanceForBuilder<'_> as Instance<'_>>::InstanceProperty` to `bool`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `build_with_42`
--> examples/test.rs:19:53
|
16 | fn build_with_42<B: Builder>(builder: B)
| ------------- required by a bound in this
...
19 | for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `build_with_42`
error[E0271]: type mismatch resolving `for<'a> <MyBuilder as Builder>::InstanceForBuilder<'a> == <MyBuilder as Builder>::InstanceForBuilder<'a>`
--> examples/test.rs:45:5
|
45 | build_with_42(builder); // TODO: Doesn't work
| ^^^^^^^^^^^^^ type mismatch resolving `for<'a> <MyBuilder as Builder>::InstanceForBuilder<'a> == <MyBuilder as Builder>::InstanceForBuilder<'a>`
|
note: expected this to be `<MyBuilder as Builder>::InstanceForBuilder<'a>`
--> examples/test.rs:32:35
|
32 | type InstanceForBuilder<'a> = MyInstance<'a>;
| ^^^^^^^^^^^^^^
= note: expected associated type `<MyBuilder as Builder>::InstanceForBuilder<'a>`
found struct `MyInstance<'a>`
help: a method is available that returns `<MyBuilder as Builder>::InstanceForBuilder<'a>`
--> examples/test.rs:8:5
|
8 | fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Builder::build`
note: required by a bound in `build_with_42`
--> examples/test.rs:19:40
|
16 | fn build_with_42<B: Builder>(builder: B)
| ------------- required by a bound in this
...
19 | for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `build_with_42`
For more information about this error, try `rustc --explain E0271`.
error: could not compile `pairwise-aligner` due to 2 previous errors
The correct syntax to do what you want is:
where B::InstanceForBuilder::InstanceProperty = bool
there's no need to introduce the for<'a> lifetime because the value of the associated type is not allowed to depend on the lifetime parameter. If you compile this code, you'll find that you get another error:
error: equality constraints are not yet supported in `where` clauses
--> src/main.rs:19:5
|
19 | B::InstanceForBuilder::InstanceProperty = bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
There's no immediate workaround for this. If you badly need this, you may be able to write a new trait, implement it only for bool, and then constrain things to that trait. That will get messy quickly though.
The answer from DreamConspiracy is a little outdated. I'd like to reuse the example codes from him to show a compiled solution
Instead of
where B::InstanceForBuilder::InstanceProperty = bool
You should write
fn build_with_42_for_bool_instance<'a, B, I>(builder: B)
where
B : Builder<InstanceForBuilder<'a>=I>,
I : Instance<'a, InstanceProperty=bool>,
{
builder.build(&42);
}

How to serialise into an array of slices?

Suppose I have a trait representing a pure function; memory has been provided for the outputs, and both inputs and outputs are expected to be serde/bincode encoded. Is it possible to make this do what I want, or restructure things to enable the same end idiomatically?
trait Pure {
fn pure(inputs: &[&[u8]], outputs: &[&mut [u8]]);
}
struct Identity {}
impl Pure for Identity {
fn pure(inputs: &[&[u8]], outputs: &[&mut [u8]]) {
let x: u32 = bincode::deserialize(inputs[0]).expect("input decode failed");
bincode::serialize_into(outputs[0], &x).unwrap();
}
}
makes the compiler complain:
error[E0508]: cannot move out of type `[&mut [u8]]`, a non-copy slice
--> src/main.rs:10:33
|
10 | bincode::serialize_into(outputs[0], &x).unwrap();
| ^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `outputs[_]` has type `&mut [u8]`, which does not implement the `Copy` trait
There are two issues with your code. First, if you want to be able to mutate the inner references, then you must have a mutable outer reference. IOW, your pure function should take a &mut[&mut [u8]] for parameter.
Second, in order to pass the mutable reference to deserialize_into, you need to reborrow it, to make it clear to the compiler that you are not permanently taking it out of output:
trait Pure {
fn pure(inputs: &[&[u8]], outputs: &mut[&mut [u8]]);
// ^^^ add this
}
struct Identity {}
impl Pure for Identity {
fn pure(inputs: &[&[u8]], outputs: &mut[&mut [u8]]) {
// ^^^ add this
let x: u32 = bincode::deserialize(inputs[0]).expect("input decode failed");
bincode::serialize_into(&mut*outputs[0], &x).unwrap();
// ^^^^^ add this
}
}
Playground

Implementing code from walkdir's documentation

I am new to rust and trying to figure out what I am doing wrong here. From the docs.rs page on walkdir:
The following code recursively iterates over the directory given and prints the path for each entry:
use walkdir::WalkDir;
for entry in WalkDir::new("foo") {
println!("{}", entry?.path().display());
}
However when I try to run this as a simple program:
use walkdir::WalkDir;
fn main() {
for entry in WalkDir::new("~/Documents/ExampleDir/") {
println!("{}", entry?.path().display());
}
}
I get a compilation error:
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
--> src/main.rs:4:24
|
2 | / fn main() {
3 | | for entry in WalkDir::new("foo") {
4 | | println!("{}", entry?.path().display());
| | ^^^^^^ cannot use the `?` operator in a function that returns `()`
5 | | }
6 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `Try` is not implemented for `()`
= note: required by `from_error`
If I remove the ? operator then I get a different compilation error:
error[E0599]: no method named `path` found for enum `std::result::Result<walkdir::DirEntry, walkdir::Error>` in the current scope
--> src/main.rs:4:30
|
4 | println!("{}", entry.path().display());
| ^^^^ method not found in `std::result::Result<walkdir::DirEntry, walkdir::Error>`
What am I doing wrong here? Is this an issue in my code or in the documentation?
The ? is shorthand for a match statement. See The question mark operator.
The question mark operator (?) unwraps valid values or returns erroneous values, propagating them to the calling function. It is a unary postfix operator that can only be applied to the types Result<T, E> and Option.
The (main) function requires a return value of type Result:
use std::error::Error;
use walkdir::WalkDir;
fn main() -> Result<(), Box<dyn Error>> {
for entry in WalkDir::new("~/Documents/ExampleDir/") {
println!("{}", entry?.path().display());
}
Ok(())
}

In Rust, I have a large number of receiver objects I'd like manage, however I'm running into lifetime issues using Select

Due to the possibility of there being a large number of objects, I'd like to have a way to add them to the select list, remove them for processing and then add them back. All, without having to rebuild the select list each time an object is added back for waiting. It looks something like this:
use std::collections::HashMap;
use crossbeam::{Select, Sender, Receiver};
struct WaitList <'a> {
sel: Select<'a>,
objects: HashMap<u128, Object>,
sel_index: HashMap<usize, u128>,
}
impl<'a> WaitList<'a> {
fn new () -> Self { Self { sel: Select::new(), objects: HashMap::new(), sel_index: HashMap::new() } }
fn select(&self) -> &Object {
let oper = self.sel.select();
let index = oper.index();
let id = self.sel_index.get(&index).unwrap();
let obj = self.objects.get(&id).unwrap();
obj.cmd = oper.recv(&obj.receiver).unwrap();
self.sel.remove(index);
obj
}
fn add_object(&self, object: Object) {
let id = object.id;
self.objects.insert(id, object);
self.add_select(id);
}
fn add_select(&self, id: u128) {
let idx = self.sel.recv(&self.objects.get(&id).unwrap().receiver);
self.sel_index.insert(idx, id);
}
}
Over time the select list will contain more dead entries, then live, and I'll rebuild it at that time. But, I'd like to not have to rebuild it every time. Here's the detailed error message:
Checking test-select v0.1.0 (/Users/bruce/Projects/rust/examples/test-select)
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:28:47
|
28 | let idx = self.sel.recv(&self.objects.get(&id).unwrap().receiver);
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 27:5...
--> src/main.rs:27:5
|
27 | / fn add_select(&self, id: u128) {
28 | | let idx = self.sel.recv(&self.objects.get(&id).unwrap().receiver);
29 | | self.sel_index.insert(idx, id);
30 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:28:34
|
28 | let idx = self.sel.recv(&self.objects.get(&id).unwrap().receiver);
| ^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 9:6...
--> src/main.rs:9:6
|
9 | impl<'a> WaitList<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:28:28
|
28 | let idx = self.sel.recv(&self.objects.get(&id).unwrap().receiver);
| ^^^^
= note: expected `&mut crossbeam::Select<'_>`
found `&mut crossbeam::Select<'a>`
While I believe I understand the issue, that the borrow of the receiver from the hash table doesn't live long enough, I'm having a difficult time trying to come up with an alternative -- and I'm not seeing a clean way to borrow the information. I considered creating a struct to contain the borrow, and using that instead of a plain id in the wait sel_index however that runs into the same lifetime problem.
struct SingleWaiter<'a> {
id: u128,
receiver: &'a Receiver::<Command>
}
I feel like I'm missing something or not understanding something, as it seems like it shouldn't be that difficult to do what I want to do. I can imagine that the choice of HashMap for holding object might be the issue, a Vec felt wrong, as I'm adding and inserting. BTW, the HashMap isn't normally part of the waitlist. It is part of something else, but the problem remains the same irregardless of where the HashMap lives.

Resources