Several trait implementations as a single type

Hi,

I've got something like this:

pub trait Spinner {
    fn new() -> Self;
    fn message(&self, line: String);
    fn stop(&mut self);
}
pub struct DaddySpinner {
    spinner: Option<daddy::SpinnerHandle>,
}
impl Spinner for DaddySpinner { ... }

pub struct PrettySpinner {
    spinner: Option<pretty::Spinner>,
}
impl Spinner for PrettySpinner { ... }

pub struct CuteSpinner {
    spinner: Option<cute::SpinnerHandle>,
}
impl Spinner for CuteSpinner { ... }

Employed this way:

struct GlobalState {
    pub spinner: spin::DaddySpinner,
    ...
}
fn main() {
    let mut g = GlobalState {
        spinner: spin::DaddySpinner::new(),
        ...
    };
    ...
}

Whenever I want to change the spinner, I have to replace <...>Spinner in two places. What's the best way to make the spinners naturally interchangeable?

You can use Box<dyn Spinner> as a universal type that can hold any of the spinners. It can be changed even at run time.

Alternatively, you can parametrize GlobalState by spinner:

struct GlobalState<S: Spinner> {
   spinner: S,
}

Spinner isn't object-safe, because of new.

Declaring it as fn new() -> Self where Self: Sized should do the trick. It won't be possible to call new on a dyn Spinner.

Somehow, I can't figure out what else do I have to do after

struct GlobalState<S: Spinner> {
   spinner: S,
}

:blush:

If you just want to keep the required edit simpler and not change anything else, you can replace

spinner: spin::DaddySpinner::new(),

with

spinner: Spinner::new(),

and it will call the trait implementation's new() for whichever concrete type is chosen. This will also work if you make GlobalState generic.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.