Moiz Sohail
Moiz Sohail

Reputation: 648

Create vector of multiple structs for Rust

I am pretty new to Rust. So I might be doing something dumb.

For context, I am using tui-rs to make a small terminal application. This is the relevant cleaned code.

use tui::widgets::{Block, List, Widget};

pub struct UI {
    widgets: Vec<Box<dyn Widget>>,
}



let block = Block::default().title("Block").borders(Borders::ALL);
let list = List::new(items)
    .block(Block::default().title("List").borders(Borders::ALL))
    .style(Style::default().fg(Color::White))
    .highlight_style(Style::default().add_modifier(Modifier::ITALIC))
    .highlight_symbol(">>");

let widgets = vec![Box::new(block),Box::new(list)];

for i in 0..self.widgets.len() {
    f.render_widget(self.widgets[i], self.chunks[i]);
}
...

Now you get the idea about what I am trying to achieve. But i keep getting this error on f.render_widget(self.widgets[i], self.chunks[i]);

the trait bound `std::boxed::Box<dyn tui::widgets::Widget>: tui::widgets::Widget` is not satisfied
the following other types implement trait `tui::widgets::Widget`:
  tui::widgets::BarChart<'a>
  tui::widgets::Block<'a>
  tui::widgets::Chart<'a>
  tui::widgets::Clear
  tui::widgets::Gauge<'a>
  tui::widgets::LineGauge<'a>
  tui::widgets::List<'a>
  tui::widgets::Paragraph<'a>
and 4 othersrustcE0277
terminal.rs(99, 12): required by a bound in `tui::Frame::<'a, B>::render_widget`

I have even tried the enum approach

struct Widgets{
    List,
    Box
}

pub struct UI {
    widgets: Vec<Widgets>,
}
let widgets = vec![block,list];

Now the error is on let widgets = vec![block,list];

mismatched types
expected enum `ui::Widgets`, found struct `tui::widgets::List`

Upvotes: 1

Views: 171

Answers (1)

Kushagra Gupta
Kushagra Gupta

Reputation: 604

The problem is not at the vec! step but rather at the render_widget step (for box way).

What is happening is that the trait Widget is not implemented for Box<dyn Widget>. It looks like the issue is at tui-rs end where they forgot to add a blanket impl for references.

You can try giving a reference like @maxim-gritsenko said: f.render_widget(&self.widgets[i], ...). I am not sure that would work, though. If it does, its probably the best solution.

The enum solution can work, but you didn't actually make the enums correctly.

What you need is something like:

enum MyWidgets {
  List(tui::widgets::List),
  Block(tui::widgets::Block),
}

let widgets = vec![MyWidgets::List(list), MyWidgets::Block(block)];

for widget in widgets {
  match widget {
    MyWidget::List(list) => f.render_widget(list, ...),
    MyWidget::Block(block) => f.render_widget(block, ...),
  }
}

Upvotes: 3

Related Questions