Problem with referencing Rc<RefCell>>

Hi!

I've struggling with this second day and cannot figure this out. I am using nwg Windows Native API to let user choose to which database connect to. The problem here is I still get conflicts about references, whenever variable gets out of scope, borrowing etc.. It creates a small window with combobox, button and selected property which is going to be then provided to Tauri framework to setup a window object property.

#[derive(Default)]
pub struct Selector {
  window: nwg::Window,
  combobox: nwg::ComboBox<&'static str>,
  button: nwg::Button,
  svg: nwg::ImageFrame,
  selected: Option<String>
}

impl Selector {
  fn ui(dialog: Rc<RefCell<Self>>) {
    nwg::init().expect("Error while creating Windows Native UI");

    let clone = dialog.clone();

    {
      let mut borrow = RefCell::borrow_mut(&dialog);

      nwg::Window::builder()
        .size((300, 200))
        .position((300, 300))
        .title("Wybór firmy")
        .build(&mut borrow.window)
        .unwrap();

      let svg_data = include_bytes!("./assets/logo.svg");
      let tree = Tree::from_data(svg_data, &Options::default()).unwrap();
      let mut pixmap = Pixmap::new(142, 17).unwrap();
      resvg::render(&tree, Transform::from_scale(0.4, 0.4), &mut pixmap.as_mut());

      let image = DynamicImage::ImageRgba8(ImageBuffer::<Rgba<u8>, _>::from_raw(142, 17, pixmap.take()).unwrap());

      let mut image_data: Vec<u8> = Vec::new();

      {
        let mut cursor = Cursor::new(&mut image_data);
        image.write_to(&mut cursor, image::ImageFormat::Bmp).unwrap();
      }

      let nwg_image = nwg::Bitmap::from_bin(&image_data).unwrap();

      nwg::ImageFrame::builder()
        .parent(&borrow.window)
        .position((79, 15))
        .size((142, 17))
        .bitmap(Some(&nwg_image))
        .build(&mut borrow.svg)
        .unwrap();

      nwg::ComboBox::builder()
        .collection(vec!["DB 1", "DB 2", "DB 3"])
        .parent(&borrow.window)
        .position((10, 50))
        .size((280, 25))
        .build(&mut borrow.combobox)
        .unwrap();

      nwg::Button::builder()
        .text("Wybierz")
        .parent(&borrow.window)
        .position((10, 150))
        .size((280, 30))
        .build(&mut borrow.button)
        .unwrap();
    }

    let mut borrow = RefCell::get_mut(&mut clone);

    nwg::bind_event_handler(&borrow.button.handle, &borrow.window.handle, |event, _data, handle| {
      if event == nwg::Event::OnButtonClick {
          borrow.selected = Some(borrow.combobox.selection_string().unwrap());
      }
  });

    nwg::dispatch_thread_events();

  }

  pub fn new() -> Rc<RefCell<Self>> {
    Rc::new(RefCell::new(Self {
      window: Default::default(),
      combobox: Default::default(),
      button: Default::default(),
      svg: Default::default(),
      selected: None,
    }))
  }
}

I would be really grateful for any help cause I'm loosing my mind with it. I think this is not quite complicated, but on daily basis I don't use Rust and it is kinda catchy for me.

It always throws errors nearby this:

let mut borrow = RefCell::get_mut(&mut clone);

    nwg::bind_event_handler(&borrow.button.handle, &borrow.window.handle, |event, _data, handle| {
      if event == nwg::Event::OnButtonClick {
          borrow.selected = Some(borrow.combobox.selection_string().unwrap());
      }

Like "clone" is freed while borrowed etc.., and how do I modify the Option inside the structure upon content in combobox, whenever button is clicked?

Could you please copy and paste the error you are getting here? Would be helpful for us to understand your problem better.

For example:

`clone` does not live long enough
borrowed value does not live long enoughrustcClick for full compiler diagnostic
main.rs(96, 3): `clone` dropped here while still borrowed
main.rs(33, 9): binding `clone` declared here
main.rs(86, 18): argument requires that `clone` is borrowed for `'static`
closure may outlive the current function, but it borrows `borrow`, which is owned by the current function
may outlive borrowed value `borrow`rustcClick for full compiler diagnostic
main.rs(90, 11): `borrow` is borrowed here
main.rs(88, 5): function requires argument type to outlive `'static`
main.rs(88, 75): to force the closure to take ownership of `borrow` (and any other referenced variables), use the `move` keyword: `move `

Please lose the IDE noise. That's not an error from rustc+cargo, it's been heavily filtered (doesn't include pointers to the relevant code snippets, for example).

1 Like

Here you go I hope:

error[E0594]: cannot assign to data in dereference of `Ref<'_, Selector>`
  --> src/main.rs:88:11
   |
88 |           borrow.selected = Some(borrow.combobox.selection_string().unwrap());
   |           ^^^^^^^^^^^^^^^ cannot assign
   |
   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Ref<'_, Selector>`

error[E0597]: `dialog` does not live long enough
  --> src/main.rs:84:34
   |
30 |   fn ui(dialog: Rc<RefCell<Self>>) {
   |         ------ binding `dialog` declared here
...
84 |     let borrow = RefCell::borrow(&dialog);
   |                  ----------------^^^^^^^-
   |                  |               |
   |                  |               borrowed value does not live long enough
   |                  argument requires that `dialog` is borrowed for `'static`
...
94 |   }
   |   - `dialog` dropped here while still borrowed

error[E0505]: cannot move out of `borrow` because it is borrowed
  --> src/main.rs:86:75
   |
84 |     let borrow = RefCell::borrow(&dialog);
   |         ------ binding `borrow` declared here
85 |
86 |     nwg::bind_event_handler(&borrow.button.handle, &borrow.window.handle, move |event, _data, handle| {
   |     -----------------------  ------ borrow of `borrow` occurs here        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ move out of `borrow` occurs here
   |     |
   |     borrow later used by call
87 |       if event == nwg::Event::OnButtonClick {
88 |           borrow.selected = Some(borrow.combobox.selection_string().unwrap());
   |           ------ move occurs due to use in closure

Some errors have detailed explanations: E0505, E0594, E0597.
For more information about an error, try `rustc --explain E0505`.

Maybe creating a new borrow inside of the callback will work:

    let borrow = RefCell::borrow(&mut clone);
    let mut clone_for_callback = clone.clone(); // you might be able to pass `clone` directly to the callback

    nwg::bind_event_handler(&borrow.button.handle, &borrow.window.handle, move |event, _data, handle| {
        if event == nwg::Event::OnButtonClick {
            let mut borrow = RefCell::borrow_mut(&mut clone_for_callback);
            borrow.selected = Some(borrow.combobox.selection_string().unwrap());
        }
    });

I'll try this. Can you also help me how do I update the selected (Options), it looks like it doesn't implement DeRef trait.

EDIT: I think It might not work cause there are a non-mut ref and a mut one.
There cannot be non-mutable references whenever a mutable one exists, if I'm not wrong.

Looks like you need borrow splitting, which isn't possible through a DerefMut implementation like that of cell::RefMut. Instead, pull out an actual &mut Selector and work with that.

    let mut lock = clone.borrow_mut();
    let borrow = &mut *lock;
    nwg::bind_event_handler(&borrow.button.handle, &borrow.window.handle, |event, _data, handle| {
        if event == nwg::Event::OnButtonClick {
            borrow.selected = Some(borrow.combobox.selection_string().unwrap());
        }
    });
    drop(lock);

Reduced demonstration. I drop the lock to minimize the chance you'll call a conflicting borrow or borrow_mut, since you said you were running into that.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.