Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't create IterTable with header row #465

Open
MonterraByte opened this issue Dec 9, 2024 · 3 comments
Open

Can't create IterTable with header row #465

MonterraByte opened this issue Dec 9, 2024 · 3 comments
Labels
question Further information is requested

Comments

@MonterraByte
Copy link

Hello. I'm having trouble getting an IterTable with a header row. Initially, I tried:

use std::iter;

use tabled::settings::Style;
use tabled::tables::IterTable;

fn main() {
    let data = [1, 2, 3];
    let table = IterTable::new(
        iter::once([String::from("x"), String::from("x * 2")])
            .chain(data.iter().map(|n| [n.to_string(), (n * 2).to_string()])),
    )
    .with(Style::sharp());

    table.build(std::io::stdout().lock()).unwrap();
    println!();
}

Expected:

┌───┬───────┐
│ x │ x * 2 │
├───┼───────┤
│ 1 │ 2     │
│ 2 │ 4     │
│ 3 │ 6     │
└───┴───────┘

Actual result:

┌───┬───────┐
│ x │ x * 2 │
│ 1 │ 2     │
│ 2 │ 4     │
│ 3 │ 6     │
└───┴───────┘

Then, I tried using ColumnNames:

use tabled::settings::themes::ColumnNames;
use tabled::settings::{Settings, Style};
use tabled::tables::IterTable;

fn main() {
    let data = [1, 2, 3];
    let table = IterTable::new(data.iter().map(|n| [n.to_string(), (n * 2).to_string()])).with(
        Settings::empty()
            .with(Style::sharp())
            .with(ColumnNames::new(["x", "x * 2"])),
    );

    table.build(std::io::stdout().lock()).unwrap();
    println!();
}

but that fails with:

error[E0277]: the trait bound `for<'a> ColumnNames: TableOption<IterRecords<&'a Map<std::slice::Iter<'_, {integer}>, {closure@src/main.rs:7:48: 7:51}>>, CompactConfig, StaticDimension>` is not satisfied
   --> src/main.rs:8:9
    |
7   |       let table = IterTable::new(data.iter().map(|n| [n.to_string(), (n * 2).to_string()])).with(
    |                                                                                             ---- required by a bound introduced by this call
8   | /         Settings::empty()
9   | |             .with(Style::sharp())
10  | |             .with(ColumnNames::new(["x", "x * 2"])),
    | |___________________________________________________^ the trait `for<'a> TableOption<IterRecords<&'a Map<std::slice::Iter<'_, {integer}>, {closure@src/main.rs:7:48: 7:51}>>, CompactConfig, StaticDimension>` is not implemented for `ColumnNames`
    |
    = help: the trait `TableOption<IterRecords<&'a Map<std::slice::Iter<'_, {integer}>, {closure@src/main.rs:7:48: 7:51}>>, CompactConfig, StaticDimension>` is not implemented for `ColumnNames`
            but trait `TableOption<VecRecords<Text<String>>, ColoredConfig, CompleteDimensionVecRecords<'_>>` is implemented for it
    = note: required for `Settings<Settings<Settings, Style<On, On, On, On, (), On, 1, 0>>, ColumnNames>` to implement `for<'a> TableOption<IterRecords<&'a Map<std::slice::Iter<'_, {integer}>, {closure@src/main.rs:7:48: 7:51}>>, CompactConfig, StaticDimension>`
note: required by a bound in `IterTable::<I>::with`
   --> /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tabled-0.17.0/src/tables/iter.rs:122:20
    |
120 |     pub fn with<O>(mut self, option: O) -> Self
    |            ---- required by a bound in this associated function
121 |     where
122 |         for<'a> O: TableOption<IterRecords<&'a I>, CompactConfig, StaticDimension>,
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `IterTable::<I>::with`
[...]
For more information about this error, try `rustc --explain E0277`.
error: could not compile `tabled_test` (bin "tabled_test") due to 1 previous error

Any ideas?

@zhiburt zhiburt added the question Further information is requested label Dec 12, 2024
@zhiburt
Copy link
Owner

zhiburt commented Dec 12, 2024

Hi @MonterraByte

Really sorry for late response.

It would suppose to work something like this

use tabled::settings::style::HorizontalLine;
use tabled::settings::Style;
use tabled::tables::IterTable;

fn main() {
    let data = [1, 2, 3];
    let iter = iter::once([String::from("x"), String::from("x * 2")])
        .chain(data.iter().map(|n| [n.to_string(), (n * 2).to_string()]));

    let style = Style::sharp().horizontals([(1, HorizontalLine::inherit(Style::modern()))]);

    let table = IterTable::new(iter).with(style);

    table.build(std::io::stdout().lock()).unwrap();
    println!();
}

But unfortunately ... it was chosen to remove some capabilities of Table in IterTable to make IterTable faster.

Anyhow, now I am thinking probably we could do this, with little penalty, maybe in all cases?
But it's worth to think about, need some time.

Do you test IterTable?
Cause you can do just that with Table, see next example.
Exactly under the hood there's big differences, I think you maybe aware of them already.

use std::iter::{self, FromIterator};

use tabled::settings::style::HorizontalLine;
use tabled::settings::Style;
use tabled::Table;

fn main() {
    let data = [1, 2, 3];
    let iter = iter::once([String::from("x"), String::from("x * 2")])
        .chain(data.iter().map(|n| [n.to_string(), (n * 2).to_string()]));

    let style = Style::sharp().horizontals([(1, HorizontalLine::inherit(Style::modern()))]);

    let table = Table::from_iter(iter).with(style).to_string();

    println!("{table}");
}

So what do you think,
Do you think it's worth to add such a support for custom horizontal lines in IterTable?

It's not a hard change, the question just is it worth those a few ifs we will add 😄

Have a great weekend,
Once again sorry for late reply.

@zhiburt
Copy link
Owner

zhiburt commented Dec 12, 2024

In any case it would need to be mentioned somewhere till then for sure.
All though I was thinking it is 😅

@zhiburt
Copy link
Owner

zhiburt commented Dec 12, 2024

Originally I think the issue was that
We don't know how many lines are will be rendered with iterator in general.
Because of that we can't tell if we need to rely on those custom lines.

For example imagine you set a line somewhere on the 90th line.
But the iterator will never get there.
Do we need to rely on it still?
I think so.

But see it's kind of was decided to not to back then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants