Hello fellow Rust experts,
I'm seeking some advice for the following code snippet.
As a new years resolution, I challenged myself to finally start getting my hands dirty in Rust and stop just reading about it. I think I got the basics down like working with the borrow checker etc. but the more I work on the following code, the more I have the feeling that I'm doing something which is really against Rust's best practices & design principle. The code just feels wrong.
What I want to achieve:
Creating a rust library that communicates with a Socket.IO server using the rust_socketio crate.
I want to be able to listen for the save
event and emit events (the last one is the easy part).
As my professional background is in web technologies (JavaScript, TypeScript) my first idea was to recreate something like "addEventListener". E.g: I have a Communicator
which holds a vector of closures (event callbacks) that can be registered. As soon as the save
event is triggered by the rust_socketio crate I would then loop through the vector and execute every registered closure. See save_callbacks
.
Due to this idea, it is not possible to set the client directly in Communicator::new()
as I somehow need a reference to the instance (e.g: self.save_callbacks to iterate over them in the closure).
Therefore I tried to introduce a get_client
methods which dynamically creates a SocketIo Client if it doesn't exist. Due to this I now needed to make self mutable (obviously) but also the consumer needs to make the variable mutable (see src/main.rs). It makes total sense but it somehow feels so wrong and I think the approach I'm trying here is not the way to go. Therefore I'm seeking some advice from you on how to improve this.
Remarks:
The code compiles as it is. If you uncomment the callback it fails due to lifetime issues. That's a problem for another day I left it in the snippet so that it's clear what my final goal is.
Thanks for the help!
Code
src/lib.rs
use rust_socketio::{Client, ClientBuilder, Payload};
pub struct Communicator {
client: Option<Client>,
save_callbacks: Vec<Option<fn(payload: Payload, client: Client) -> usize>>
}
impl Communicator {
pub fn new() -> Communicator {
Communicator {
client: None,
save_callbacks: vec!(None)
}
}
fn get_client(&mut self) -> &Client {
match self.client {
Some(ref client) => client,
None => {
// let callback = |payload: Payload, client: Client| {
// for callback in self.save_callbacks.iter() {
// if let Some(c) = callback {
// c(payload.clone(), client.clone());
// }
// }
// };
let client = ClientBuilder::new("http://localhost:3000")
.on("error", |err, _| eprintln!("Error: {:#?}", err))
// .on("save", callback)
.connect()
.expect("Connecton failed");
self.client = Some(client.clone());
self.client.as_ref().unwrap()
}
}
}
}
src/bin.rs
use sts;
fn main() {
let mut communicator = sts::Communicator::new();
//...
}