Skip to content

nik-rev/displaystr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

displaystr

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("+")
            )),
        }
    }
}

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

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

About

Ergonomically implement the `Display` trait

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Languages