Implement fmt::Display for enums, flags, and ints (#18)

* Implement fmt::Display for enums

`wasi_common` relies on `strerror` to nicely format error messages.
`strerror` is autoimplemented in `wig`. I thought it might be useful
to provide a Rust-idiomatic alternative which boils down to autoimplementing
`fmt::Display` for all enums.

* Implement fmt::Display for flags

* Implement fmt::Display for ints
This commit is contained in:
Jakub Konka
2020-02-24 21:11:08 +01:00
committed by GitHub
parent b7cd003b93
commit 678065011e
2 changed files with 43 additions and 9 deletions

View File

@@ -72,6 +72,12 @@ fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) -> TokenStr
#(#consts;)*
}
impl ::std::fmt::Display for #ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl ::std::convert::TryFrom<#repr> for #ident {
type Error = wiggle_runtime::GuestError;
fn try_from(value: #repr) -> Result<Self, wiggle_runtime::GuestError> {
@@ -153,6 +159,8 @@ fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDatatype) -> Toke
}
let all_values_token = Literal::u128_unsuffixed(all_values);
let ident_str = ident.to_string();
quote! {
#[repr(transparent)]
#[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)]
@@ -167,6 +175,12 @@ fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDatatype) -> Toke
}
}
impl ::std::fmt::Display for #ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "{}({:#b})", #ident_str, self.0)
}
}
impl ::std::ops::BitAnd for #ident {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
@@ -286,15 +300,21 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
witx::IntRepr::U64 => witx::AtomType::I64,
});
let variant_names = e.variants.iter().map(|v| names.enum_variant(&v.name));
let tryfrom_repr_cases = e.variants.iter().enumerate().map(|(n, v)| {
let variant_name = names.enum_variant(&v.name);
quote!(#n => Ok(#ident::#variant_name))
});
let to_repr_cases = e.variants.iter().enumerate().map(|(n, v)| {
let variant_name = names.enum_variant(&v.name);
quote!(#ident::#variant_name => #n as #repr)
});
let mut variant_names = vec![];
let mut tryfrom_repr_cases = vec![];
let mut to_repr_cases = vec![];
let mut to_display = vec![];
for (n, variant) in e.variants.iter().enumerate() {
let variant_name = names.enum_variant(&variant.name);
let docs = variant.docs.trim();
let ident_str = ident.to_string();
let variant_str = variant_name.to_string();
tryfrom_repr_cases.push(quote!(#n => Ok(#ident::#variant_name)));
to_repr_cases.push(quote!(#ident::#variant_name => #n as #repr));
to_display.push(quote!(#ident::#variant_name => format!("{} ({}::{}({}))", #docs, #ident_str, #variant_str, #repr::from(*self))));
variant_names.push(variant_name);
}
quote! {
#[repr(#repr)]
@@ -303,6 +323,15 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
#(#variant_names),*
}
impl ::std::fmt::Display for #ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
let to_str = match self {
#(#to_display,)*
};
write!(f, "{}", to_str)
}
}
impl ::std::convert::TryFrom<#repr> for #ident {
type Error = wiggle_runtime::GuestError;
fn try_from(value: #repr) -> Result<#ident, wiggle_runtime::GuestError> {