Initializing a FnMut member variable with a static Fn function - rust

Problem Description
I have a Config struct that can store a FnMut callback function. The catch is: not all of my configurations require a callback function, so I would like to make adding a callback function optional. This requires the member variable to be initialized with a default function that will get used if no callback is set.
Existing Code
struct Config<'a>{
callback: &'a mut dyn (FnMut(&str))
}
fn default_fn(msg: &str){
println!("default_fn({})", msg);
}
impl<'a> Config<'a> {
pub fn new() -> Config<'a> {
Config{
callback: &default_fn // ERROR: types differ in mutability
}
}
pub fn set_callback(mut self, callback_fn: &'a mut dyn (FnMut(&str))) -> Config<'a> {
self.callback = callback_fn;
self
}
}
fn main() {
// Our FnMut callback
let mut msg_log: Vec<String> = vec![];
let mut callback_fn = |msg: &str| {
msg_log.push(msg.to_string());
};
{
let mut config = Config::new();
(config.callback)("Hello World!");
config = config.set_callback(&mut callback_fn);
(config.callback)("Hello World!");
}
// Demonstration that the callback actually works
println!("{:?}", msg_log);
}
error[E0308]: mismatched types
--> src/main.rs:13:23
|
13 | callback: &default_fn // ERROR: types differ in mutability
| ^^^^^^^^^^^ types differ in mutability
|
= note: expected type `&mut dyn for<'r> std::ops::FnMut(&'r str)`
found type `&for<'r> fn(&'r str) {default_fn}`
Does someone have any suggestions on how to solve that problem?
Things I already tried, without any success:
Initializing it with a closure: callback: &|_: &str|{}
Using a member function instead of a global function
Creating a mutable reference: callback: &mut default_fn
(causes: cannot return value referencing temporary value)
I'm running out of ideas, any help is appreciated. Even if the answer is that what I am trying to do is impossible for reasons I didn't realize yet.

You should really box the trait object function. That makes the whole code much easier to use:
struct Config<'a>{
callback: Box<dyn FnMut(&str) + 'a>,
}
fn default_fn(msg: &str){
println!("default_fn({})", msg);
}
impl<'a> Config<'a> {
pub fn new() -> Config<'a> {
Config{
callback: Box::new(default_fn)
}
}
pub fn set_callback(self, callback: &'a mut dyn (FnMut(&str))) -> Config<'a> {
Config {
callback: Box::new(callback),
..self
}
}
}
fn main() {
// Our FnMut callback
let mut msg_log = vec![];
let mut callback_fn = |msg: &str| {
msg_log.push(msg.to_string());
};
{
let mut config = Config::new();
(config.callback)("Hello World!");
config = config.set_callback(&mut callback_fn);
(config.callback)("Hello World!");
}
// Demonstration that the callback actually works
println!("{:?}", msg_log);
}
Note that it is difficult to use callbacks in idiomatic Rust. I would even say that they aren't idiomatic at all. You should use a channel, something like that:
use std::sync::mpsc::{channel, Sender, SendError};
struct Config {
sender: Sender<String>,
}
impl Config {
pub fn new(sender: Sender<String>) -> Config {
Config{
sender
}
}
pub fn send(&self, message: String) -> Result<(), SendError<String>> {
self.sender.send(message)
}
}
fn main() {
let (sender, receiver) = channel();
let config = Config::new(sender);
config.send("Hello world!".into()).unwrap();
println!("{:?}", receiver.recv().unwrap());
}

Just wanted to share the solution I found:
Single-threaded, callback-based.
While in my opinion this one really answers the question I had, I think you guys are still right about the problems I might encounter in the future with this programming style. I will definitely reconsider your advice about using channels.
struct Config<'a>{
callback: Option<&'a mut dyn (FnMut(&str))>
}
impl<'a> Config<'a> {
pub fn new() -> Config<'a> {
Config{
callback: None
}
}
pub fn set_callback(mut self, callback_fn: &'a mut dyn (FnMut(&str))) -> Config<'a> {
self.callback = Some(callback_fn);
self
}
pub fn run_callback(&mut self, msg: &str){
if let Some(callback) = &mut self.callback{
callback(msg);
} else {
// Default code
println!("default_fn({})", msg);
}
}
}
fn main() {
// Our FnMut callback
let mut msg_log: Vec<String> = vec![];
let mut callback_fn = |msg: &str| {
msg_log.push(msg.to_string());
};
let mut config = Config::new();
config.run_callback("Hello World!");
config = config.set_callback(&mut callback_fn);
config.run_callback("Hello World!");
// Demonstration that the callback actually works
println!("{:?}", msg_log);
}

Related

Moving out of a function both owned and borrowed entities?

What is proper way of doing that? What options are available? I am aware about the problem of dangled references and the problem of self-referential struct. Still I have strong intuition it's a reachable problem because both owner and borrowed reference are returned and no memory deallocation happen. Also it's quite general problem! In theory, it's a solvable one.
use byte_slice_cast::*;
fn main() {
let context = context_make();
dbg!(&context);
}
//
fn context_make<'a>() -> Context<'a> {
Context::<'a>::new()
}
//
#[derive(Debug)]
struct Context<'a> {
pub dst_buffer: Box<[f32]>,
pub dst_buffer_bytes: &'a [u8],
}
//
impl<'a> Context<'a> {
fn new() -> Context<'a> {
let len: usize = 13;
let dst_buffer: Box<[f32]> = vec![0_f32; len].into_boxed_slice();
let dst_buffer_bytes = dst_buffer.as_byte_slice();
Context {
dst_buffer,
dst_buffer_bytes,
}
}
}
Note: this code requires byte-slice-cast = "1.2.0"
Interesting to compare solutions if there are more than one alternatives.
Playground
You can not do this in safe rust. There are good reasons for this like not being able to trivially move the struct without changing where the reference points to.
Instead, you would implement a function to get that reference:
struct Context {
pub dst_buffer: Box<[f32]>,
}
impl Context {
fn new() -> Context {
let len: usize = 13;
Context {
dst_buffer: vec![0_f32; len].into_boxed_slice(),
}
}
fn dst_buffer_bytes(&self) -> &[u8] {
self.dst_buffer.as_byte_slice()
}
}
And if you really want to print out the bytes too:
use std::fmt;
impl fmt::Debug for Context {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Context")
.field("dst_buffer", &self.dst_buffer)
.field("dst_buffer_bytes", self.dst_buffer_bytes())
.finish()
}
}
Solution I have found. It possible with help of create owning-ref. Interesting is it possible to reach the same result with help of standard Pin?
use byte_slice_cast::*;
use owning_ref::*;
fn main() {
let context = Context::new();
dbg!(&context);
dbg!(context.dst.as_owner());
dbg!(&*context.dst);
}
//
#[derive(Debug)]
struct Context {
// pub dst_buffer : Box::< [ f32 ] >,
// pub dst_buffer_bytes : &'a [ u8 ],
pub dst: OwningRef<Box<[f32]>, [u8]>,
}
//
impl Context {
fn new() -> Context {
let len: usize = 2;
let dst_buffer: Box<[f32]> = vec![0_f32; len].into_boxed_slice();
// let dst_buffer_bytes = dst_buffer.as_byte_slice();
let dst = OwningRef::new(dst_buffer);
let dst = dst.map(|dst_buffer| dst_buffer.as_byte_slice());
Context { dst }
// Context { dst_buffer, dst_buffer_bytes }
}
}
Playground

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);
}

Sending a closure (which returns a struct with a trait) to a thread leads to sized error

I'm trying to send a closure which will generate a structure to a thread, however when I try to do it I get a Sized error. I understand the error (the size is indeed not known at compile time), however adding Boxes and other such tricks does not seem to solve it.
I've tried to look into how to implement the Sized trait, however it seems to be quite special and honestly above my understanding.
I've written a minimal reproducible example:
use std::thread;
trait DataProcess {
fn start(&self);
fn run(&self);
fn stop(&self);
}
struct SomeDP {
name: String,
}
impl DataProcess for SomeDP {
fn start(&self) {
println!("Started");
}
fn run(&self) {
println!("Running");
}
fn stop(&self) {
println!("Stopped");
}
}
fn thread_maker(builder: Box<dyn Fn() -> (dyn DataProcess + Send)>) {
let thread_builder = thread::Builder::new();
let handle = thread_builder.spawn(move || {
let dp = builder();
dp.start();
});
}
fn main() {
let dp_builder = || SomeDP {
name: "nice".to_string(),
};
thread_maker(Box::new(dp_builder));
}
Which you can also find on the playground here
This works
use std::thread;
trait DataProcess{
fn start(&self);
fn run(&self);
fn stop(&self);
}
struct SomeDP{
name: String
}
impl DataProcess for SomeDP{
fn start(&self){println!("Started");}
fn run(&self){println!("Running");}
fn stop(&self){println!("Stopped");}
}
fn thread_maker<F>(builder: F)
where
F: Fn() -> Box<dyn DataProcess>,
F: Send + 'static {
let thread_builder = thread::Builder::new();
let handle = thread_builder.spawn(
move ||{
let dp = builder();
dp.start();
}
);
}
fn main(){
let dp_builder = || -> Box<dyn DataProcess> {
Box::new(SomeDP{name: "nice".to_string()})
};
thread_maker(dp_builder);
}

match + RefCell = X does not live long enough

I need to initialize an item (fn init(&mut self) -> Option<&Error>), and use it if there's no errors.
pub fn add(&mut self, mut m: Box<Item>) {
if let None = m.init() {
self.items.push(m);
}
}
This works unless I need to check the error if there's any:
pub fn add(&mut self, mut m: Box<Item>) {
if let Some(e) = m.init() {
//process error
} else {
self.items.push(m); //won't compile, m is borrowed
}
}
Fair. Need to use RefCell. However, this
pub fn add(&mut self, mut m: Box<Item>) {
let rc = RefCell::new(m);
if let Some(e) = rc.borrow_mut().init() {
//process error
} else {
self.items.push(rc.borrow_mut())
}
}
ends with weird
error: `rc` does not live long enough
if let Some(e) = rc.borrow_mut().init() {
^~
note: reference must be valid for the destruction scope surrounding block at 75:60...
pub fn add_module(&mut self, mut m: Box<RuntimeModule>) {
^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 76:30
let rc = RefCell::new(m);
I tried nearly everything: plain box, Rc'ed box, RefCell'ed box, Rc'ed RefCell. Tried to adapt this answer to my case. No use.
Complete example:
use std::cell::RefCell;
use std::error::Error;
trait Item {
fn init(&mut self) -> Option<&Error>;
}
struct ItemImpl {}
impl Item for ItemImpl {
fn init(&mut self) -> Option<&Error> {
None
}
}
//===========================================
struct Storage {
items: Vec<Box<Item>>,
}
impl Storage {
fn new() -> Storage {
Storage{
items: Vec::new(),
}
}
fn add(&mut self, mut m: Box<Item>) {
let rc = RefCell::new(m);
if let Some(e) = rc.borrow_mut().init() {
//process error
} else {
self.items.push(*rc.borrow_mut())
}
}
}
fn main() {
let mut s = Storage::new();
let mut i = Box::new(ItemImpl{});
s.add(i);
}
(Playground)
UPD: As suggested, this is a "family" of mistakes like I did, it is well explained here. However my case has easier solution.
As krdln suggested, the simplest way to work around this is to return in the if block and thus scope the borrow:
fn add(&mut self, mut m: Box<Item>) {
if let Some(e) = m.init() {
//process error
return;
}
self.items.push(m);
}

Borrows and ownership of object on thread

Sorry for newbie question. The error here is
<anon>:30:5: 30:17 error: cannot borrow immutable borrowed content as mutable
<anon>:30 routing_node.put(3);
^^^^^^^^^^^^
I have tried many things to work around this but know for sure this is a simple error. Any help much appreciated.
use std::thread;
use std::thread::spawn;
use std::sync::Arc;
struct RoutingNode {
data: u16
}
impl RoutingNode {
pub fn new() -> RoutingNode {
RoutingNode { data: 0 }
}
pub fn run(&self) {
println!("data : {}", self.data);
}
pub fn put(&mut self, increase: u16) {
self.data += increase;
}
}
fn main() {
let mut routing_node = Arc::new(RoutingNode::new());
let mut my_node = routing_node.clone();
{
spawn(move || {my_node.run(); });
}
routing_node.put(3);
}
Arc isn't allowing to mutate of it's inner state, even if container is marked as mutable. You should use one of Cell, RefCell or Mutex. Both Cell and RefCell are non-threadsafe so you should use Mutex (last paragraph in docs).
Example:
use std::thread::spawn;
use std::sync::Mutex;
use std::sync::Arc;
struct RoutingNode {
data: u16,
}
impl RoutingNode {
pub fn new() -> Self { RoutingNode { data: 0, } }
pub fn run(&self) { println!("data : {}" , self.data); }
pub fn put(&mut self, increase: u16) { self.data += increase; }
}
fn main() {
let routing_node = Arc::new(Mutex::new(RoutingNode::new()));
let my_node = routing_node.clone();
let thread = spawn(move || { my_node.lock().unwrap().run(); });
routing_node.lock().unwrap().put(3);
let _ = thread.join();
}
Playpen

Resources