impl-enum

Crates.ioimpl-enum
lib.rsimpl-enum
version0.3.1
sourcesrc
created_at2020-07-29 22:31:37.471788
updated_at2023-11-07 20:50:29.778369
descriptionMacros that make using enums like trait objects more convenient.
homepage
repositoryhttps://github.com/Heliozoa/impl-enum
max_upload_size
id271099
size39,542
Martinez (Heliozoa)

documentation

README

impl-enum

Crates.io docs.rs Crates.io GitHub

Contains proc macro attributes with_methods and as_dyn that make using enums like trait objects more convenient.

Use cases

When the concrete type of some value depends on a runtime condition, a trait object or an enum with variants for each concrete type are the most natural choices, each having their own pros and cons. One of the cons of using an enum is that it can be inconvenient to use. The trait object method can also be problematic if you want to use types that cannot be turned into trait objects, or when working with types and traits defined in other crates. This crate aims to make such enums more convenient to use.

with_methods

//! The variant of the writer is dynamically selected with an environment variable.
//! Using the macro, we can use the enum with the convenience of a trait object.

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

#[impl_enum::with_methods {
    fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()>
    pub fn write(&mut self, buf: &[u8]) -> std::io::Result<usize>
}]
pub enum Writer {
    Cursor(Cursor<Vec<u8>>),
    File { file: File },
}

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

fn main() {
    let mut writer = get_writer();
    writer.write_all(b"hello!").unwrap();
}

The macro generates an impl block equivalent to

impl Writer {
    fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
        match self {
            Self::Cursor(first, ..) => first.write_all(buf),
            Self::File { file, .. } => file.write_all(buf),
        }
    }
    pub fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::Cursor(first, ..) => first.write(buf),
            Self::File { file, .. } => file.write(buf),
        }
    }
}

as_dyn

//! 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>,
        }
    }
}

Alternatives

License

Licensed under the Mozilla Public License Version 2.0.

Commit count: 21

cargo fmt