Passing "trait" object reference to function

Hello,

TLDR summary: lib does not have pub trait, tried to hack around and write generic fn for various structs, failing to succeed.


I'm trying to write some simple UI using native-windows-gui (-derive).

I got app up&running nicely, UI elements being dynamically added/removed to/from running app (nwg::Label, nwg::ComboBox, nwg::TextInput, etc.) as needed.

And then i started to make my code cleaner...

As i have few groups of such dynamically handled elements, i try to create "generic" function that will remove dynamic elements of various types from UI layout when needed...
(use-case - opening new file to process requires larger change of currently shown UI nodes)

Executive part does something like this:

// layout that internally binds all the shown items etc.
let layout = // FlexboxLayout handling the shown elements...;

// various dynamically apprering/disappearing elements
let dropdowns: RefCell<Vec<nwg::ComboBox::<String>>>;
let labels: RefCell<Vec<nwg::Label>>;
// etc. - RefCell-ed items like these are placed where
// they belong according to nwg guide/documentation

// When some events trigger, i need to execute
// following steps to remove them from UI:

let group = dropdowns.borrow();
for item in group.iter() {
    if layout.has_child(item) {
        layout.remove_child(item);
    }
}
drop(group);
dropdowns.replace(Default::default());

// and basically "same" should be repeated
// for all the dynamically managed RefCells shown above...

Code above is a bit abstracted (variables located elsewhere etc.), but important is that so far everything seems work as it should, compiles, runs, and makes app user happy.

Now, i try to "abstract" the "deletion" code into function to be invoked easily on various RefCells.

The nwg crate does NOT explicitly "export" pub trait that groups together behavior of ComboBox<>/Label/other-"controls".

Although enum ControlHandle seems to be some king of magical internal glue that, via other implementations/traits etc. (me be rust beginner) seems to make layout modification code to work for any of the mentioned UI types...

So i tried to come up with this so far:

fn clear_objects_from_layout<W: Into<nwg::ControlHandle>>(keeper: &RefCell<Vec<W>>, layout: &nwg::FlexboxLayout) {
    let children = keeper.borrow();
    for d in children.iter() {
        if layout.has_child(*d) {
            layout.remove_child(*d);
        }
    }
    drop(children);
    keeper.replace(Default::default());
}

and the function itself shows no "errors" so far.

I think i understand (at least the surface level) of all the code and concepts used above, until i try to use it, and fail to compile:

clear_objects_from_layout(&dropdowns, &tokens_layout);

The error message gives sort of feeling i might be not that off with implementation:

error[E0277]: the trait bound `nwg::ControlHandle: std::convert::From<nwg::ComboBox<std::string::String>>` is not satisfied
   --> src\main.rs:120:9
    |
106 | fn clear_objects_from_layout<W: Into<nwg::ControlHandle>>(keeper: &RefCell<Vec<W>>, layout: &nwg::FlexboxLayout) {
    |                                 ------------------------ required by this bound in `clear_objects_from_layout`
...
120 |         clear_objects_from_layout(&dropdowns, &layout);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<nwg::ComboBox<std::string::String>>` is not implemented for `nwg::ControlHandle`
    |
    = help: the following implementations were found:
              <nwg::ControlHandle as std::convert::From<&nwg::Button>>
              <nwg::ControlHandle as std::convert::From<&nwg::CheckBox>>
              <nwg::ControlHandle as std::convert::From<&nwg::ComboBox<D>>>
              <nwg::ControlHandle as std::convert::From<&nwg::ControlHandle>>
            and 27 others

But i fail to decipher the details of the reported message, and how it relates to a provded vs expected types:

<nwg::ControlHandle: std::convert::From<nwg::ComboBox<std::string::String>>
...
<nwg::ControlHandle as std::convert::From<&nwg::ComboBox<D>>>.

Any tips or even recommendations to go other directions will be greatly appreciated. :slight_smile:

Would something like the following help?

- fn clear_objects_from_layout<W: Into<nwg::ControlHandle>>(
+ fn clear_objects_from_layout<W>(
      keeper: &RefCell<Vec<W>>,
      layout: &nwg::FlexboxLayout,
  )
+ where
+     for<'local> &'local W : Into<nwg::ControlHandle>,
  {

Basically it looks like you need to say that &W : Into..., but &W is not a type, it is missing the lifetime. You could try to add a lifetime parameter <'a> and use &'a W : Into..., but that 'a, by virtue of being a(n outer) generic parameter, cannot be used to refer to borrows inside the function.

The solution here is to add a bound that applies to all / any lifetime parameter, which is written with that for /*all / any */ <'lifetime> syntax.

See also the documentation on HRTB.

2 Likes

thank you for direction! seems to work as expected.

Lifetimes were one of the concepts i was ignoring (not using explicitly) so far, so back to the books it is... :slight_smile:

1 Like