Attribute Macro as_dyn

Source
#[as_dyn]
Expand description

Generates methods for an enum that match on the enum and return the variant’s first field as a trait object.

Takes a comma-separated list of traits as an argument. The name of the trait is snake_cased for the method names. For example, for the trait ExampleTrait it would generate

fn as_dyn_example_trait(&self) -> &dyn ExampleTrait
fn as_dyn_example_trait_mut(&mut self) -> &mut dyn ExampleTrait
fn into_dyn_example_trait(self) -> Box<dyn ExampleTrait>

§Example

//! The variant of the writer is dynamically selected with an environment variable.
//! Using the macro, we can conveniently turn the enum into a trait object when necessary.

use std::{
    fmt::Debug,
    fs::File,
    io::{Cursor, Write},
};

#[impl_enum::as_dyn(Debug, Write)]
pub enum Writer {
    Cursor(Cursor<Vec<u8>>),
    File { file: File },
}

fn get_writer() -> Writer {
    if let Ok(path) = std::env::var("WRITER_FILE") {
        Writer::File {
            file: File::create(path).unwrap(),
        }
    } else {
        Writer::Cursor(Cursor::new(vec![]))
    }
}

fn main() {
    let mut writer = get_writer();

    let dyn_debug = writer.as_dyn_debug();
    println!("{:?}", dyn_debug);

    let dyn_writer_mut = writer.as_dyn_write_mut();
    dyn_writer_mut.write_all(b"hello!").unwrap();

    let box_dyn_debug = writer.into_dyn_debug();
    println!("{:?}", box_dyn_debug);
}

The macro generates an impl block equivalent to

impl Writer {
    fn as_dyn_write(&self) -> &dyn Write {
        match self {
            Self::Cursor(first, ..) => first as &dyn Write,
            Self::File { file, .. } => file as &dyn Write,
        }
    }
    fn as_dyn_write_mut(&mut self) -> &mut dyn Write {
        match self {
            Self::Cursor(first, ..) => first as &mut dyn Write,
            Self::File { file, .. } => file as &mut dyn Write,
        }
    }
    fn into_dyn_write(self) -> Box<dyn Write> {
        match self {
            Self::Cursor(first, ..) => Box::new(first) as Box<dyn Write>,
            Self::File { file, .. } => Box::new(file) as Box<dyn Write>,
        }
    }
}