1 use crate::names;
2 
3 use proc_macro2::{Literal, TokenStream};
4 use quote::quote;
5 
define_flags( name: &witx::Id, repr: witx::IntRepr, record: &witx::RecordDatatype, ) -> TokenStream6 pub(super) fn define_flags(
7     name: &witx::Id,
8     repr: witx::IntRepr,
9     record: &witx::RecordDatatype,
10 ) -> TokenStream {
11     let ident = names::type_(&name);
12     let abi_repr = names::wasm_type(repr.into());
13     let repr = super::int_repr_tokens(repr);
14 
15     let mut names_ = vec![];
16     let mut values_ = vec![];
17     for (i, member) in record.members.iter().enumerate() {
18         let name = names::flag_member(&member.name);
19         let value_token = Literal::usize_unsuffixed(1 << i);
20         names_.push(name);
21         values_.push(value_token);
22     }
23 
24     quote! {
25         wiggle::bitflags::bitflags! {
26             #[derive(Copy, Clone, Debug, PartialEq, Eq)]
27             pub struct #ident: #repr {
28                 #(const #names_ = #values_;)*
29             }
30         }
31 
32         impl ::std::fmt::Display for #ident {
33             fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
34                 f.write_str(stringify!(#ident))?;
35                 f.write_str("(")?;
36                 ::std::fmt::Debug::fmt(self, f)?;
37                 f.write_str(" (0x")?;
38                 ::std::fmt::LowerHex::fmt(&self.bits(), f)?;
39                 f.write_str("))")?;
40                 Ok(())
41             }
42         }
43 
44         impl TryFrom<#repr> for #ident {
45             type Error = wiggle::GuestError;
46             #[inline]
47             fn try_from(value: #repr) -> Result<Self, wiggle::GuestError> {
48                 #ident::from_bits(value)
49                     .ok_or(wiggle::GuestError::InvalidFlagValue(stringify!(#ident)))
50             }
51         }
52 
53         impl TryFrom<#abi_repr> for #ident {
54             type Error = wiggle::GuestError;
55             #[inline]
56             fn try_from(value: #abi_repr) -> Result<Self, wiggle::GuestError> {
57                 #ident::try_from(#repr::try_from(value)?)
58             }
59         }
60 
61         impl From<#ident> for #repr {
62             #[inline]
63             fn from(e: #ident) -> #repr {
64                 e.bits()
65             }
66         }
67 
68         impl wiggle::GuestType for #ident {
69             #[inline]
70             fn guest_size() -> u32 {
71                 #repr::guest_size()
72             }
73 
74             #[inline]
75             fn guest_align() -> usize {
76                 #repr::guest_align()
77             }
78 
79             fn read(mem: &wiggle::GuestMemory, location: wiggle::GuestPtr<#ident>) -> Result<#ident, wiggle::GuestError> {
80                 use std::convert::TryFrom;
81                 let reprval = #repr::read(mem, location.cast())?;
82                 let value = #ident::try_from(reprval)?;
83                 Ok(value)
84             }
85 
86             fn write(mem: &mut wiggle::GuestMemory, location: wiggle::GuestPtr<#ident>, val: Self) -> Result<(), wiggle::GuestError> {
87                 let val: #repr = #repr::from(val);
88                 #repr::write(mem, location.cast(), val)
89             }
90         }
91     }
92 }
93