Closure lifetime in Rust through simple pattern - struct

I'm trying to recreate a simple callback pattern in Rust using 2 structs. One will pass a bit of logic to execute whenever the other one is ready. The issue here is that the logic will run only if a certain value from the struct is true.
I can understand why the reference to Foo needs to live for 'static in this case, but I'm not sure how to refactor so that it compiles.
Seems like a pretty regular use case, but maybe I'm missing something since I'm new to Rust.
struct Foo {
value: bool,
}
struct Bar {
closure: Box<dyn Fn() -> ()>,
}
impl Foo {
fn new() -> Self {
Foo {
value: false,
}
}
fn set_closure(&self, b: &mut Bar) {
b.closure = self.get_closure();
}
fn get_closure(&self) -> Box<dyn Fn() -> ()> {
return Box::new(|| {
if self.value {
println!("true");
} else {
println!("false");
}
});
}
}
impl Bar {
fn new() -> Self {
Bar {
closure: Box::new(|| {})
}
}
}
fn main() {
let foo = Foo::new();
let mut bar = Bar::new();
foo.set_closure(&mut bar);
let closure = bar.closure;
closure();
}
Playground link -> here

You need to move the value into the closure:
fn get_closure(&self) -> Box<dyn Fn() -> ()> {
let value = self.value;
Box::new(move || {
if value {
println!("true");
} else {
println!("false");
}
})
}
Notice that in your example value is a bool which is Copy. If not you can either capture a reference or clone it. (If capturing a reference you may need to adjust some lifetimes there).
Playground

Related

How to downcast mutable structs not as references

I have this trait and implementation:
#[async_trait]
pub trait AsyncKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()>;
fn as_any(&self) -> &dyn Any;
}
#[async_trait]
impl AsyncKeyProvider for GoogleKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()> {
{...}
}
fn as_any(&self) -> &dyn Any {
self
}
}
In order to pass it into my handler in actix-web, I'm passing through a GoogleKeyProvider like this:
let key_provider = web::Data::from(Arc::new(GoogleKeyProvider::default()));
let server = HttpServer::new(move || {
App::new()
.app_data(key_provider.clone())
.route("/validate", web::post().to(validate))
})
With the handler doing this:
pub async fn validate(jwt_body: web::Json<JwtBody>, provider: web::Data<Box<dyn AsyncKeyProvider>>) -> impl Responder {
let provider_object: &GoogleKeyProvider = provider.as_any().downcast_ref::<GoogleKeyProvider>().expect("Wasn't a GoogleKeyProvider");
match validate_jwt(&jwt_body.jwt, provider_object).await {
{...}
}
}
validate_jwt then tries to call a method on the provider struct like this:
async fn validate_jwt(jwt: &String, provider: &GoogleKeyProvider) -> Result<bool, Box<dyn std::error::Error>> {
let key_to_use = provider.get_key_async(<thing>).await.unwrap();
}
Which presents me with this error:
error[E0596]: cannot borrow `*provider` as mutable, as it is behind a `&` reference
--> src\routes\validate.rs:48:22
|
48 | let key_to_use = provider.get_key_async(<thing>).await.unwrap();
| ^^^^^^^^ `provider` is a `&` reference, so the data it refers to cannot be borrowed as mutable
As far as I can understand, this is happening because the result of my downcasting is a reference (due to downcast_ref), but I think I'd be wanting the plain GoogleKeyProvider type instead - I'm not sure on that though. I believe the provider needs to be mutable as the values inside it (see below) can change during the lifetime of the provider (it's intended to provide a temporary cache for some keys, and automatically update them if they're out of date)
#[derive(Clone)]
pub struct GoogleKeyProvider {
cached: Option<JwkSet>,
expiration_time: Instant,
}
I'm not sure how to get this working with downcasting, though. Is anyone able to help me see where I've gone wrong?
You have to choice if get_key_async update somme thing at the struct.
The simple code below show you the error
trait Atrait {
fn afn(&mut self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&mut self) -> i32 {
2
}
}
fn main()
{
// test should be mutable
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}
This work because afn(self) is not declared mutable afn(&mut self)
trait Atrait {
fn afn(&self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&self) -> i32 {
2
}
}
fn main()
{
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}

Extracting a function which creates an instance in Rust

A bit of a beginner Rust question - say I have the following code, which compiles:
trait XGetter {
fn get_x(&self) -> i32;
}
struct Foo {
x: i32
}
impl XGetter for Foo {
fn get_x(&self) -> i32 {
self.x
}
}
struct Bar<'a>(&'a dyn XGetter);
impl<'a> XGetter for Bar<'a> {
fn get_x(&self) -> i32 {
self.0.get_x()
}
}
fn baz() -> i32 {
let foo = Foo { x: 42 };
let bar = Bar(&foo);
bar.get_x()
}
Let's say I want to extract out the creation of Bar, in order encapsulate the creation of the XGetter and Bar together, such that baz() now reads:
fn baz2() -> i32 {
let bar = createBar(42);
bar.get_x()
}
However, by implementing createBar below, I run a-fowl of the borrow checker:
fn createBar<'a>(x: i32) -> Bar<'a> {
let foo = Foo { x };
let bar = Bar(&foo);
// ---- `foo` is borrowed here
bar
// ^^^ returns a value referencing data owned by the current function
}
How would one extract out a function createBar which doesn't break the borrowing rules?
The foo in createBar() dies when the function ends, so the bar you return would be pointing to invalid memory.
Given how you have written the call to createBar(42), it looks like you want Bar to own the Foo, so do that:
struct Bar(Box<dyn XGetter>);
impl XGetter for Bar {
fn get_x(&self) -> i32 {
self.0.get_x()
}
}
fn createBar(x: i32) -> Bar {
let foo = Box::new(Foo { x });
let bar = Bar(foo);
bar
}
You can not:
The signature struct Bar<'a>(&'a dyn XGetter); and createBar(i: 32) are incompatible. Because it means that in createBar you would have to instantiate an object implementing XGetter and that reference will not live outside of the scope of createBar.
fn createBar<'a>(x: i32) -> Bar<'a> {
let foo = Foo { x };
let bar = Bar(&foo);
// ---- `foo` is borrowed here
bar
// ^^^ returns a value referencing data owned by the current function
}
^^^ That means that the variable foo will live just during createBar scope.
That said, you could use:
fn createBar(g: &dyn XGetter) -> Bar<'_> {
Bar(g)
}
That way the reference will live outside of the scope of createBar.
Playground
As per the comments. If you want to abstract that, you need Bar to own Foo
struct Bar(Box<dyn XGetter>);
fn createBar(x: i32) -> Bar {
let foo = Box::new(Foo { x });
let bar = Bar(foo);
bar
}

How to make a struct accept type `impl std::ops::Fn<()>` as its field?

In Rust 1.26 a new feature called impl Trait was stabilized which makes function able to return an unboxed closure. But how to define a struct field's type for an unboxed closure, code below doesn't compile:
fn return_closure() -> impl Fn() -> () {
move || {
println!("abc");
}
}
struct HoldClosure {
closure: impl Fn() -> ()
}
fn main() {
let hold_my_closure = HoldClosure {
closure: return_closure()
};
}
Just use a generic type argument.
fn return_closure() -> impl Fn() {
move || {
println!("abc");
}
}
struct HoldClosure<F: Fn()> {
closure: F,
}
fn main() {
let hold_my_closure = HoldClosure {
closure: return_closure()
};
(hold_my_closure.closure)();
}

Rust matching and borrow checker

I keep stumbling on a pattern in my Rust programs that always puts me at odds with the borrow-checker. Consider the following toy example:
use std::sync::{Arc,RwLock};
pub struct Test {
thing: i32,
}
pub struct Test2 {
pub test: Arc<RwLock<Test>>,
pub those: i32,
}
impl Test {
pub fn foo(&self) -> Option<i32> {
Some(3)
}
}
impl Test2 {
pub fn bar(&mut self) {
let mut test_writer = self.test.write().unwrap();
match test_writer.foo() {
Some(thing) => {
self.add(thing);
},
None => {}
}
}
pub fn add(&mut self, addme: i32) {
self.those += addme;
}
}
This doesn't compile because the add function in the Some arm tries to borrow self mutably, which was already borrowed immutably just above the match statement in order to open the read-write lock.
I've encountered this pattern a few times in Rust, mainly when using RwLock. I've also found a workaround, namely by introducing a boolean before the match statement and then changing the value of the boolean in the Some arm and then finally introducing a test on this boolean after the match statement to do whatever it is I wanted to do in the Some arm.
It just seems to me that that's not the way to go about it, I assume there's a more idiomatic way to do this in Rust - or solve the problem in an entirely different way - but I can't find it. If I'm not mistaken the problem has to do with lexical borrowing so self cannot be mutably borrowed within the arms of the match statement.
Is there an idiomatic Rust way to solve this sort of problem?
Use directly the field those, for example with custom type:
use std::sync::{Arc,RwLock};
pub struct Those(i32);
impl Those {
fn get(&self) -> i32 {
self.0
}
fn add(&mut self, n: i32) {
self.0 += n;
}
}
pub struct Test {
thing: Those,
}
pub struct Test2 {
pub test: Arc<RwLock<Test>>,
pub those: Those,
}
impl Test {
pub fn foo(&self) -> Option<Those> {
Some(Those(3))
}
}
impl Test2 {
pub fn bar(&mut self) {
let mut test_writer = self.test.write().unwrap();
match test_writer.foo() {
Some(thing) => {
// call a method add directly on your type to get around the borrow checker
self.those.add(thing.get());
},
None => {}
}
}
}
You either need to end borrow of a part of self, before mutating self
pub fn bar1(&mut self) {
let foo = self.test.write().unwrap().foo();
match foo {
Some(thing) => {
self.add(thing);
},
None => {}
}
}
or directly mutate non borrowed part of self
pub fn bar2(&mut self) {
let test_writer = self.test.write().unwrap();
match test_writer.foo() {
Some(thing) => {
self.those += thing;
},
None => {}
}
}

How to make &mut self from &self?

I want to expose a public function with immutable self which calls a private function with mutable self.
struct Foo {
value: i32,
}
impl Foo {
fn f1(&self) {
self.f2(); // <--- is it possible to make self mutable?
}
fn f2(&mut self) {
self.value = 5;
}
}
fn main() {
let foo = Foo { value: 0 };
foo.f1();
}
When compiling this code I get an error
cannot borrow immutable borrowed content *self as mutable
Is it possible to make self mutable?
EDIT:
After missing that last sentence.. you could get away with wrapping the property in a Cell:
use std::cell::Cell;
struct Foo { value: Cell<i32> }
impl Foo {
fn f1(&self) {
self.f2();
}
fn f2(&self) {
self.value.set(5);
}
}
fn main() {
let foo = Foo { value: Cell::new(0) };
foo.f1();
println!("{:?}", foo.value.get()); // prints 5
}
What you want cannot be done: you cannot convert a non-mutable reference into a mutable one.
But you can get almost that with RefCell:
struct Foo { value: RefCell<i32> }
impl Foo {
fn f1(&self) {
let mutValue = self.value.borrow_mut();
*mutValue = 5;
}
}
I didn't even need the f2 function!

Resources