wiggle_generate/types/
flags.rs

1use crate::names;
2
3use proc_macro2::{Literal, TokenStream};
4use quote::quote;
5
6pub(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}