1 use super::{atom_token, int_repr_tokens};
2 use crate::names::Names;
3
4 use proc_macro2::TokenStream;
5 use quote::quote;
6
define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream7 pub(super) fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream {
8 let ident = names.type_(&name);
9 let rt = names.runtime_mod();
10
11 let repr = int_repr_tokens(e.repr);
12 let abi_repr = atom_token(match e.repr {
13 witx::IntRepr::U8 | witx::IntRepr::U16 | witx::IntRepr::U32 => witx::AtomType::I32,
14 witx::IntRepr::U64 => witx::AtomType::I64,
15 });
16
17 let mut variant_names = vec![];
18 let mut tryfrom_repr_cases = vec![];
19 let mut to_repr_cases = vec![];
20 let mut to_display = vec![];
21
22 for (n, variant) in e.variants.iter().enumerate() {
23 let variant_name = names.enum_variant(&variant.name);
24 let docs = variant.docs.trim();
25 let ident_str = ident.to_string();
26 let variant_str = variant_name.to_string();
27 tryfrom_repr_cases.push(quote!(#n => Ok(#ident::#variant_name)));
28 to_repr_cases.push(quote!(#ident::#variant_name => #n as #repr));
29 to_display.push(quote!(#ident::#variant_name => format!("{} ({}::{}({}))", #docs, #ident_str, #variant_str, #repr::from(*self))));
30 variant_names.push(variant_name);
31 }
32
33 quote! {
34 #[repr(#repr)]
35 #[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)]
36 pub enum #ident {
37 #(#variant_names),*
38 }
39
40 impl ::std::fmt::Display for #ident {
41 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
42 let to_str = match self {
43 #(#to_display,)*
44 };
45 write!(f, "{}", to_str)
46 }
47 }
48
49 impl ::std::convert::TryFrom<#repr> for #ident {
50 type Error = #rt::GuestError;
51 fn try_from(value: #repr) -> Result<#ident, #rt::GuestError> {
52 match value as usize {
53 #(#tryfrom_repr_cases),*,
54 _ => Err( #rt::GuestError::InvalidEnumValue(stringify!(#ident))),
55 }
56 }
57 }
58
59 impl ::std::convert::TryFrom<#abi_repr> for #ident {
60 type Error = #rt::GuestError;
61 fn try_from(value: #abi_repr) -> Result<#ident, #rt::GuestError> {
62 #ident::try_from(value as #repr)
63 }
64 }
65
66 impl From<#ident> for #repr {
67 fn from(e: #ident) -> #repr {
68 match e {
69 #(#to_repr_cases),*
70 }
71 }
72 }
73
74 impl From<#ident> for #abi_repr {
75 fn from(e: #ident) -> #abi_repr {
76 #repr::from(e) as #abi_repr
77 }
78 }
79
80 impl<'a> #rt::GuestType<'a> for #ident {
81 fn guest_size() -> u32 {
82 #repr::guest_size()
83 }
84
85 fn guest_align() -> usize {
86 #repr::guest_align()
87 }
88
89 fn read(location: & #rt::GuestPtr<#ident>) -> Result<#ident, #rt::GuestError> {
90 use std::convert::TryFrom;
91 let reprval = #repr::read(&location.cast())?;
92 let value = #ident::try_from(reprval)?;
93 Ok(value)
94 }
95
96 fn write(location: & #rt::GuestPtr<'_, #ident>, val: Self)
97 -> Result<(), #rt::GuestError>
98 {
99 #repr::write(&location.cast(), #repr::from(val))
100 }
101 }
102
103 unsafe impl <'a> #rt::GuestTypeTransparent<'a> for #ident {
104 #[inline]
105 fn validate(location: *mut #ident) -> Result<(), #rt::GuestError> {
106 use std::convert::TryFrom;
107 // Validate value in memory using #ident::try_from(reprval)
108 let reprval = unsafe { (location as *mut #repr).read() };
109 let _val = #ident::try_from(reprval)?;
110 Ok(())
111 }
112 }
113 }
114 }
115
116 impl super::WiggleType for witx::EnumDatatype {
impls_display(&self) -> bool117 fn impls_display(&self) -> bool {
118 true
119 }
120 }
121