Crate displaystr

Crate displaystr 

Source
Expand description

crates.io docs.rs license msrv github

This crate provides a convenient attribute macro that implements Display for you

[dependencies]
displaystr = "0.1"

This crate has 0 dependencies. I think compile-times are very important, so I have put a lot of effort into optimizing them.

§Example

Apply #[display] on enums:

use displaystr::display;

#[display]
pub enum DataStoreError {
    Disconnect(std::io::Error) = "data store disconnected",
    Redaction(String) = "the data for key `{_0}` is not available",
    InvalidHeader {
        expected: String,
        found: String,
    } = "invalid header (expected {expected:?}, found {found:?})",
    Unknown = "unknown data store error",
}

The above expands to this:

use displaystr::display;

pub enum DataStoreError {
    Disconnect(std::io::Error),
    Redaction(String),
    InvalidHeader {
        expected: String,
        found: String,
    },
    Unknown,
}

impl ::core::fmt::Display for DataStoreError {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::Disconnect(_0) => {
                f.write_fmt(format_args!("data store disconnected"))
            }
            Self::Redaction(_0) => {
                f.write_fmt(format_args!("the data for key `{_0}` is not available"))
            }
            Self::InvalidHeader { expected, found } => {
                f.write_fmt(format_args!("invalid header (expected {expected}, found {found})"))
            }
            Self::Unknown => {
                f.write_fmt(format_args!("unknown data store error"))
            }
        }
    }
}

§IDE Support

  • rustfmt formats it flawlessly
  • rust-analyzer supports hover and goto definition on the actual strings

§Auto-generated doc comments

Use #[display(doc)] to automatically generate /// comments:

use displaystr::display;

#[display(doc)]
pub enum DataStoreError {
    Disconnect(std::io::Error) = "data store disconnected",
    Redaction(String) = "the data for key `{_0}` is not available",
    InvalidHeader {
        expected: String,
        found: String,
    } = "invalid header (expected {expected:?}, found {found:?})",
    Unknown = "unknown data store error",
}

The above example’s expands to this:

use displaystr::display;

pub enum DataStoreError {
    /// data store disconnected
    Disconnect(std::io::Error),
    /// the data for key `{_0}` is not available
    Redaction(String),
    /// invalid header (expected {expected:?}, found {found:?})
    InvalidHeader {
        expected: String,
        found: String,
    },
    /// unknown data store error
    Unknown,
}

// impl Display omitted since it's identical to the previous section

§Multiple arguments

You can use a tuple to supply multiple arguments to the format_args!:

use displaystr::display;

#[display]
pub enum DataStoreError {
    Redaction(String, Vec<String>) = (
        "the data for key `{_0}` is not available, but we recovered: {}",
        _1.join("+"),
    ),
}

Expands to this:

use displaystr::display;

pub enum DataStoreError {
    Redaction(String, Vec<String>),
}

impl ::core::fmt::Display for DataStoreError {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::Redaction(_0, _1) => f.write_fmt(format_args!(
                "the data for key `{_0}` is not available, but we recovered: {}",
                _1.join("+")
            )),
        }
    }
}

§Notes

  • #[display] cannot be applied on generic types like Foo<T>, because that significantly increases complexity of the parsing logic required, which also leads to much higher compile-times
  • #[display] only applies to enums

§Comparison between displaystr, thiserror and displaydoc

These 3 errors are identical.

displaystr expresses the same error in the most concise way while being significantly faster to compile (both “cold” compile times, and also each individual invocation)

§displaystr

use thiserror::Error;
use displaystr::display;

#[derive(Error, Debug)]
#[display]
pub enum DataStoreError {
    Disconnect(#[from] io::Error) = "data store disconnected",
    Redaction(String) = "the data for key `{_0}` is not available",
    InvalidHeader {
        expected: String,
        found: String,
    } = "invalid header (expected {expected:?}, found {found:?})",
    Unknown = "unknown data store error",
}

§thiserror

use thiserror::Error;

#[derive(Error, Debug)]
pub enum DataStoreError {
    #[error("data store disconnected")]
    Disconnect(#[from] io::Error),
    #[error("the data for key `{0}` is not available")]
    Redaction(String),
    #[error("invalid header (expected {expected:?}, found {found:?})")]
    InvalidHeader {
        expected: String,
        found: String,
    },
    #[error("unknown data store error")]
    Unknown,
}

§displaydoc

use thiserror::Error;
use displaydoc::Display;

#[derive(Display, Error, Debug)]
pub enum DataStoreError {
    /// data store disconnected
    Disconnect(#[source] io::Error),
    /// the data for key `{0}` is not available
    Redaction(String),
    /// invalid header (expected {expected:?}, found {found:?})
    InvalidHeader {
        expected: String,
        found: String,
    },
    /// unknown data store error
    Unknown,
}

Attribute Macros§

display
Ergonomically implement Display for enums