Home > Back-end >  How do I write a struct with an `AlternateScreen` as a field?
How do I write a struct with an `AlternateScreen` as a field?

Time:03-19

I'm writing a little Rust terminal crate, and I need to create a struct that has a screen field, where screen is a termion::AlternateScreen. Here is my code:

use std::io::{stdout, Write};
use termion;
use termion::raw::IntoRawMode;
use termion::screen::*;

pub struct Window {
    screen: AlternateScreen,
    stdout: termion::raw::RawTerminal<std::io::Stdout>,
}
impl Window {
    
    /// Returns the completed [`Window`]; to be called after all the builder functions
    pub fn build(self) -> Window {
        Window { screen: self.screen, stdout: self.stdout }
    }

    /// Returns a new [`Window`], which can then be built using the builder functions
    pub fn builder() -> Window {
        Window { screen: AlternateScreen::from(stdout), stdout: stdout().into_raw_mode().unwrap(), }
    }
}

Unfortunately, when I try to compile this, I get an error message:

error[E0107]: missing generics for struct `termion::screen::AlternateScreen`
  --> src/widgets.rs:11:13
   |
11 |     screen: AlternateScreen,
   |             ^^^^^^^^^^^^^^^ expected 1 generic argument
   |
note: struct defined here, with 1 generic parameter: `W`
  --> /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/termion-1.5.6/src/lib.rs:49:12
   |
49 | pub struct AlternateScreen<W: Write> {
   |            ^^^^^^^^^^^^^^^ -
help: add missing generic argument
   |
11 |     screen: AlternateScreen<W>,
   |             ~~~~~~~~~~~~~~~~~~

When I add <W> in, as it suggests, I get another error saying that W is not defined. When I fix that by adding <W> to the end of pub struct Window, I get an error message saying that none of the other uses of Window in the program have the <W>. When I fix all that (by adding <W> to the end of every Window in the code), I get yet another error message:

error[E0277]: the trait bound `W: std::io::Write` is not satisfied
  --> src/widgets.rs:11:13
   |
11 |     screen: AlternateScreen<W>,
   |             ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `W`
   |
note: required by a bound in `termion::screen::AlternateScreen`
  --> /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/termion-1.5.6/src/lib.rs:49:31
   |
49 | pub struct AlternateScreen<W: Write> {
   |                               ^^^^^ required by this bound in `termion::screen::AlternateScreen`
help: consider restricting type parameter `W`
   |
10 | pub struct Window<W: std::io::Write> {
   |                                    

For more information about this error, try `rustc --explain E0277`.

When I fix that error by replacing all <W>s with <W: Write>s, I get another error message saying that an "associated type is not allowed here". When I fix that (as the compiler suggests) by replacing all <W: Write>s with <W, W: Write>s, I get the same error message again, along with this struct takes 2 generic arguments but 1 generic argument was supplied.

I've searched on here on SO for quite a while, but I didn't find anything that helped. I'm still pretty new to Rust, so I may have missed or misunderstood some answers. Could someone point me in the right direction here? How do I make it so that Window can have an AlternateScreen as one of its fields?

CodePudding user response:

In order to properly use a generic type, you need to understand what the generic parameters are for. You don't necessarily need to make your own types generic.

In this case, the reason for <W> is that AlternateScreen wraps the Writeable thing you're writing to — in the same kind of way that RawTerminal already does. So this is what you need:

pub struct Window {
    stdout: termion::raw::RawTerminal<AlternateScreen<std::io::Stdout>>,
}

And then you will need to adjust the code that constructs it correspondingly, with AlternateScreen::from().

  • Related