How to get list of unmutable elements form list of mutable?

Is that possible to simplify the code by reducing it to a version with one dynamic array of references instead of two?

                self.terminal.borrow_mut().draw(|frame| {
                    let visuals: Vec<&dyn VisualActiveRenderInterface> = vec![
                        &self.help_panel,
                        &self.backup_panel,
                        &self.text_editor,
                        &self.status_bar,
                        &self.hint_bar,
                        &self.debug_bar,
                    ];

                    let viewport = frame.size();
                    let viewports = Self::viewports_for_visuals(visuals, &viewport);

                    let visuals: Vec<&mut dyn VisualActiveRenderInterface> = vec![
                        &mut self.help_panel,
                        &mut self.backup_panel,
                        &mut self.text_editor,
                        &mut self.status_bar,
                        &mut self.hint_bar,
                        &mut self.debug_bar,
                    ];

                    for (i, component) in visuals.into_iter().enumerate() {
                        component.render(frame, viewports[i].clone())
                    }

What's the signature of viewports_for_visuals, and perhaps it's possible to change it?

Or perhaps it's possible to do something like

        let frame_size = frame.size();
        let mut viewports = Vec::new();
        let visuals: [
            &mut self.help_panel,
            &mut self.backup_panel,
            &mut self.text_editor,
            &mut self.status_bar,
            &mut self.hint_bar,
            &mut self.debug_bar,
        ];

        for component in visuals {
            let viewport = Self::viewport_for_visual(component, &frame_size);
            component.render(frame, viewport.clone());
            viewports.push(viewport);
        }
1 Like

Hello


        /// TUI constraints of the visual component.
        fn render(&mut self, frame: &mut terminal::Frame<'_, Backend>, viewports: Vec<layout::Rect>);

        /// Calculate viewports for each visual in a list.
        pub fn viewports_for_visuals<'a, IntoIter>(visuals: IntoIter, viewport: &layout::Rect) -> Vec<Vec<layout::Rect>>
        where
            IntoIter: IntoIterator<Item = &'a dyn VisualActiveRenderInterface> + Clone,
                    let viewport = frame.size();
                    let mut viewports = Vec::new();
                    let visuals = [
                        &mut self.help_panel,
                        &mut self.backup_panel,
                        &mut self.text_editor,
                        &mut self.status_bar,
                        &mut self.hint_bar,
                        &mut self.debug_bar,
                    ];

                    for component in visuals {
                        let viewport = Self::viewports_for_visuals(component, &viewport);
                        component.render(frame, viewport.clone());
                        viewports.push(viewport);
                    }

Thank you, but does not compile...

   --> module/tui/src/app.rs:148:25
    |
148 |                         &mut self.backup_panel,
    |                         ^^^^^^^^^^^^^^^^^^^^^^ expected struct `help_panel::private::HelpPanel`, found struct `backup_panel::private::BackupPanel`
    |
    = note: expected mutable reference `&mut help_panel::private::HelpPanel`
               found mutable reference `&mut backup_panel::private::BackupPanel`

On mobile, but you can probably create the array of &mut, then use array.iter().map(|r| &**r) or such to get the viewports.

I'll look again when at a proper keyboard.

1 Like

Thank you.
Thing is nonmutable list is used first then mutable.
Even if mutable -> nonmutable is convertible nonmutable -> mutable is not.
Also, visuals.clone() does not work if visuals is list of mutable dyns.
Perhaps using unsafe is option to solve this problem.

The idea is you take the mutable borrows, temporarily reborrow them as immutable, then use them as mutable.

Not a good one, and if your mean treating immutable refs as mutable, not at all (that's always UB).

2 Likes

I see. Trying.

Lots of blind guesses at my mocking here, but something like this.

2 Likes

Amazing! :smiley:
That works. Cool trick! I was not aware about that. Thank you @quinedot :purple_heart:

  let visuals: Vec<&mut dyn VisualActiveRenderInterface> = vec![
      &mut self.help_panel,
      &mut self.backup_panel,
      &mut self.text_editor,
      &mut self.status_bar,
      &mut self.hint_bar,
      &mut self.debug_bar,
  ];

  let viewport = frame.size();
  let visuals_iter = visuals.iter().map(|v| &**v);
  let viewports = Self::viewports_for_visuals(visuals_iter, &viewport);

  for (i, component) in visuals.into_iter().enumerate() {
      component.render(frame, viewports[i].clone())
  }

As an aside, you shouldn't be enumerate()ing if the only thing you do with the index is index into another collection. There is also no reason to clone() everything. Just use zip() instead:

for (component, vp) in visuals.into_iter().zip(viewports) {
    component.render(frame, vp);
}
1 Like

@H2CO3 that is really nicer :slight_smile: thank you