I am just starting to learn Rust. For this purpose I am rewriting my C++ project in Rust, but the biggest problems are lifetimes of closures and such.
I created a absolute minimal scenario of my problem seen here and below:
use std::sync::Arc;
use std::cell::{RefCell, Cell};
struct Context {
handler: RefCell<Option<Arc<Handler>>>,
}
impl Context {
pub fn new() -> Arc<Context> {
let context = Arc::new(Context{
handler: RefCell::new(None),
});
let handler = Handler::new(context.clone());
(*context.handler.borrow_mut()) = Some(handler);
context
}
pub fn get_handler(&self) -> Arc<Handler> {
self.handler.borrow().as_ref().unwrap().clone()
}
}
struct Handler {
context: Arc<Context>,
clickables: RefCell<Vec<Arc<Clickable>>>,
}
impl Handler {
pub fn new(context: Arc<Context>) -> Arc<Handler> {
Arc::new(Handler{
context: context,
clickables: RefCell::new(Vec::new()),
})
}
pub fn add_clickable(&self, clickable: Arc<Clickable>) {
self.clickables.borrow_mut().push(clickable);
}
pub fn remove_clickable(&self, clickable: Arc<Clickable>) {
// remove stuff ...
}
}
struct Clickable {
context: Arc<Context>,
callback: RefCell<Option<Box<Fn()>>>,
}
impl Clickable {
pub fn new(context: Arc<Context>) -> Arc<Clickable> {
let clickable = Arc::new(Clickable{
context: context.clone(),
callback: RefCell::new(None),
});
context.get_handler().add_clickable(clickable.clone());
clickable
}
pub fn remove(clickable: Arc<Clickable>) {
clickable.context.get_handler().remove_clickable(clickable);
}
pub fn set_callback(&self, callback: Option<Box<Fn()>>) {
(*self.callback.borrow_mut()) = callback;
}
pub fn click(&self) {
match *self.callback.borrow() {
Some(ref callback) => (callback)(),
None => (),
}
}
}
struct Button {
context: Arc<Context>,
clickable: Arc<Clickable>,
}
impl Button {
pub fn new(context: Arc<Context>) -> Arc<Button> {
let clickable = Clickable::new(context.clone());
let button = Arc::new(Button{
context: context,
clickable: clickable.clone(),
});
let tmp_callback = Box::new(|| {
button.do_stuff();
});
clickable.set_callback(Some(tmp_callback));
button
}
pub fn do_stuff(&self) {
// doing crazy stuff
let mut i = 0;
for j in 0..100 {
i = j*i;
}
}
pub fn click(&self) {
self.clickable.click();
}
}
impl Drop for Button {
fn drop(&mut self) {
Clickable::remove(self.clickable.clone());
}
}
fn main() {
let context = Context::new();
let button = Button::new(context.clone());
button.click();
}
I just don't know how to pass references in closures.
Another ugly thing is that my Handler
and my Context
need each other. Is there a nicer way to to create this dependency?