pub fn type_ref(tref: &TypeRef, lifetime: TokenStream) -> TokenStream
Examples found in repository?
src/types/mod.rs (line 66)
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
fn define_witx_pointer(
    name: &witx::Id,
    pointer_type: TokenStream,
    pointee: &witx::TypeRef,
) -> TokenStream {
    let ident = names::type_(name);
    let pointee_type = names::type_ref(pointee, quote!('a));

    quote!(pub type #ident<'a> = #pointer_type<'a, #pointee_type>;)
}

fn define_witx_list(name: &witx::Id, arr_raw: &witx::TypeRef) -> TokenStream {
    let ident = names::type_(name);
    let pointee_type = names::type_ref(arr_raw, quote!('a));
    quote!(pub type #ident<'a> = wiggle::GuestPtr<'a, [#pointee_type]>;)
}
More examples
Hide additional examples
src/names.rs (line 51)
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
pub fn type_ref(tref: &TypeRef, lifetime: TokenStream) -> TokenStream {
    match tref {
        TypeRef::Name(nt) => {
            let ident = type_(&nt.name);
            if nt.tref.needs_lifetime() {
                quote!(#ident<#lifetime>)
            } else {
                quote!(#ident)
            }
        }
        TypeRef::Value(ty) => match &**ty {
            Type::Builtin(builtin) => builtin_type(*builtin),
            Type::Pointer(pointee) | Type::ConstPointer(pointee) => {
                let pointee_type = type_ref(&pointee, lifetime.clone());
                quote!(wiggle::GuestPtr<#lifetime, #pointee_type>)
            }
            Type::List(pointee) => match &**pointee.type_() {
                Type::Builtin(BuiltinType::Char) => {
                    quote!(wiggle::GuestPtr<#lifetime, str>)
                }
                _ => {
                    let pointee_type = type_ref(&pointee, lifetime.clone());
                    quote!(wiggle::GuestPtr<#lifetime, [#pointee_type]>)
                }
            },
            Type::Variant(v) => match v.as_expected() {
                Some((ok, err)) => {
                    let ok = match ok {
                        Some(ty) => type_ref(ty, lifetime.clone()),
                        None => quote!(()),
                    };
                    let err = match err {
                        Some(ty) => type_ref(ty, lifetime.clone()),
                        None => quote!(()),
                    };
                    quote!(Result<#ok, #err>)
                }
                None => unimplemented!("anonymous variant ref {:?}", tref),
            },
            Type::Record(r) if r.is_tuple() => {
                let types = r
                    .members
                    .iter()
                    .map(|m| type_ref(&m.tref, lifetime.clone()))
                    .collect::<Vec<_>>();
                quote!((#(#types,)*))
            }
            _ => unimplemented!("anonymous type ref {:?}", tref),
        },
    }
}
src/lib.rs (line 41)
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
pub fn generate(doc: &witx::Document, settings: &CodegenSettings) -> TokenStream {
    let types = doc
        .typenames()
        .map(|t| define_datatype(&t, settings.errors.for_name(&t)));

    let constants = doc.constants().map(|c| {
        let name = quote::format_ident!(
            "{}_{}",
            c.ty.as_str().to_shouty_snake_case(),
            c.name.as_str().to_shouty_snake_case()
        );
        let ty = names::type_(&c.ty);
        let value = Literal::u64_unsuffixed(c.value);
        quote! {
            pub const #name: #ty = #value;
        }
    });

    let user_error_methods = settings.errors.iter().filter_map(|errtype| match errtype {
        ErrorType::User(errtype) => {
            let abi_typename = names::type_ref(&errtype.abi_type(), anon_lifetime());
            let user_typename = errtype.typename();
            let methodname = names::user_error_conversion_method(&errtype);
            Some(quote! {
                fn #methodname(&mut self, e: super::#user_typename)
                    -> wiggle::anyhow::Result<#abi_typename>;
            })
        }
        ErrorType::Generated(_) => None,
    });
    let user_error_conversion = quote! {
        pub trait UserErrorConversion {
            #(#user_error_methods)*
        }
    };
    let modules = doc.modules().map(|module| {
        let modname = names::module(&module.name);
        let fs = module.funcs().map(|f| define_func(&module, &f, &settings));
        let modtrait = define_module_trait(&module, &settings);
        let wasmtime = if settings.wasmtime {
            crate::wasmtime::link_module(&module, None, &settings)
        } else {
            quote! {}
        };
        quote!(
            pub mod #modname {
                use super::types::*;
                pub use super::types::UserErrorConversion;
                #(#fs)*

                #modtrait

                #wasmtime
            }
        )
    });

    quote!(
        pub mod types {
            use std::convert::TryFrom;

            #(#types)*
            #(#constants)*
            #user_error_conversion
        }
        #(#modules)*
    )
}
src/module_trait.rs (line 37)
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
pub fn define_module_trait(m: &Module, settings: &CodegenSettings) -> TokenStream {
    let traitname = names::trait_name(&m.name);
    let traitmethods = m.funcs().map(|f| {
        // Check if we're returning an entity anotated with a lifetime,
        // in which case, we'll need to annotate the function itself, and
        // hence will need an explicit lifetime (rather than anonymous)
        let (lifetime, is_anonymous) = if f
            .params
            .iter()
            .chain(&f.results)
            .any(|ret| ret.tref.needs_lifetime())
        {
            (quote!('a), false)
        } else {
            (anon_lifetime(), true)
        };
        let funcname = names::func(&f.name);
        let args = f.params.iter().map(|arg| {
            let arg_name = names::func_param(&arg.name);
            let arg_typename = names::type_ref(&arg.tref, lifetime.clone());
            let arg_type = if passed_by_reference(&*arg.tref.type_()) {
                quote!(&#arg_typename)
            } else {
                quote!(#arg_typename)
            };
            quote!(#arg_name: #arg_type)
        });

        let result = match f.results.len() {
            0 if f.noreturn => quote!(wiggle::anyhow::Error),
            0 => quote!(()),
            1 => {
                let (ok, err) = match &**f.results[0].tref.type_() {
                    witx::Type::Variant(v) => match v.as_expected() {
                        Some(p) => p,
                        None => unimplemented!("anonymous variant ref {:?}", v),
                    },
                    _ => unimplemented!(),
                };

                let ok = match ok {
                    Some(ty) => names::type_ref(ty, lifetime.clone()),
                    None => quote!(()),
                };
                let err = match err {
                    Some(ty) => match settings.errors.for_abi_error(ty) {
                        Some(ErrorType::User(custom)) => {
                            let tn = custom.typename();
                            quote!(super::#tn)
                        }
                        Some(ErrorType::Generated(g)) => g.typename(),
                        None => names::type_ref(ty, lifetime.clone()),
                    },
                    None => quote!(()),
                };
                quote!(Result<#ok, #err>)
            }
            _ => unimplemented!(),
        };

        let asyncness = if settings.get_async(&m, &f).is_sync() {
            quote!()
        } else {
            quote!(async)
        };

        if is_anonymous {
            quote!(#asyncness fn #funcname(&mut self, #(#args),*) -> #result; )
        } else {
            quote!(#asyncness fn #funcname<#lifetime>(&mut self, #(#args),*) -> #result;)
        }
    });

    quote! {
        #[wiggle::async_trait]
        pub trait #traitname {
            #(#traitmethods)*
        }
    }
}
src/types/record.rs (line 28)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
pub(super) fn define_struct(name: &witx::Id, s: &witx::RecordDatatype) -> TokenStream {
    let ident = names::type_(name);
    let size = s.mem_size_align().size as u32;
    let align = s.mem_size_align().align as usize;

    let member_names = s.members.iter().map(|m| names::struct_member(&m.name));
    let member_decls = s.members.iter().map(|m| {
        let name = names::struct_member(&m.name);
        let type_ = match &m.tref {
            witx::TypeRef::Name(nt) => {
                let tt = names::type_(&nt.name);
                if m.tref.needs_lifetime() {
                    quote!(#tt<'a>)
                } else {
                    quote!(#tt)
                }
            }
            witx::TypeRef::Value(ty) => match &**ty {
                witx::Type::Builtin(builtin) => names::builtin_type(*builtin),
                witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => {
                    let pointee_type = names::type_ref(&pointee, quote!('a));
                    quote!(wiggle::GuestPtr<'a, #pointee_type>)
                }
                _ => unimplemented!("other anonymous struct members: {:?}", m.tref),
            },
        };
        quote!(pub #name: #type_)
    });

    let member_reads = s.member_layout().into_iter().map(|ml| {
        let name = names::struct_member(&ml.member.name);
        let offset = ml.offset as u32;
        let location = quote!(location.cast::<u8>().add(#offset)?.cast());
        match &ml.member.tref {
            witx::TypeRef::Name(nt) => {
                let type_ = names::type_(&nt.name);
                quote! {
                    let #name = <#type_ as wiggle::GuestType>::read(&#location)?;
                }
            }
            witx::TypeRef::Value(ty) => match &**ty {
                witx::Type::Builtin(builtin) => {
                    let type_ = names::builtin_type(*builtin);
                    quote! {
                        let #name = <#type_ as wiggle::GuestType>::read(&#location)?;
                    }
                }
                witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => {
                    let pointee_type = names::type_ref(&pointee, anon_lifetime());
                    quote! {
                        let #name = <wiggle::GuestPtr::<#pointee_type> as wiggle::GuestType>::read(&#location)?;
                    }
                }
                _ => unimplemented!("other anonymous struct members: {:?}", ty),
            },
        }
    });

    let member_writes = s.member_layout().into_iter().map(|ml| {
        let name = names::struct_member(&ml.member.name);
        let offset = ml.offset as u32;
        quote! {
            wiggle::GuestType::write(
                &location.cast::<u8>().add(#offset)?.cast(),
                val.#name,
            )?;
        }
    });

    let (struct_lifetime, extra_derive) = if s.needs_lifetime() {
        (quote!(<'a>), quote!())
    } else {
        (quote!(), quote!(, PartialEq))
    };

    quote! {
        #[derive(Clone, Debug #extra_derive)]
        pub struct #ident #struct_lifetime {
            #(#member_decls),*
        }

        impl<'a> wiggle::GuestType<'a> for #ident #struct_lifetime {
            fn guest_size() -> u32 {
                #size
            }

            fn guest_align() -> usize {
                #align
            }

            fn read(location: &wiggle::GuestPtr<'a, Self>) -> Result<Self, wiggle::GuestError> {
                #(#member_reads)*
                Ok(#ident { #(#member_names),* })
            }

            fn write(location: &wiggle::GuestPtr<'_, Self>, val: Self) -> Result<(), wiggle::GuestError> {
                #(#member_writes)*
                Ok(())
            }
        }
    }
}
src/types/variant.rs (line 24)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
pub(super) fn define_variant(
    name: &witx::Id,
    v: &witx::Variant,
    derive_std_error: bool,
) -> TokenStream {
    let ident = names::type_(name);
    let size = v.mem_size_align().size as u32;
    let align = v.mem_size_align().align as usize;
    let contents_offset = v.payload_offset() as u32;

    let lifetime = quote!('a);
    let tag_ty = super::int_repr_tokens(v.tag_repr);

    let variants = v.cases.iter().map(|c| {
        let var_name = names::enum_variant(&c.name);
        if let Some(tref) = &c.tref {
            let var_type = names::type_ref(&tref, lifetime.clone());
            quote!(#var_name(#var_type))
        } else {
            quote!(#var_name)
        }
    });

    let read_variant = v.cases.iter().enumerate().map(|(i, c)| {
        let i = Literal::usize_unsuffixed(i);
        let variantname = names::enum_variant(&c.name);
        if let Some(tref) = &c.tref {
            let varianttype = names::type_ref(tref, lifetime.clone());
            quote! {
                #i => {
                    let variant_ptr = location.cast::<u8>().add(#contents_offset)?;
                    let variant_val = <#varianttype as wiggle::GuestType>::read(&variant_ptr.cast())?;
                    Ok(#ident::#variantname(variant_val))
                }
            }
        } else {
            quote! { #i => Ok(#ident::#variantname), }
        }
    });

    let write_variant = v.cases.iter().enumerate().map(|(i, c)| {
        let variantname = names::enum_variant(&c.name);
        let write_tag = quote! {
            location.cast().write(#i as #tag_ty)?;
        };
        if let Some(tref) = &c.tref {
            let varianttype = names::type_ref(tref, lifetime.clone());
            quote! {
                #ident::#variantname(contents) => {
                    #write_tag
                    let variant_ptr = location.cast::<u8>().add(#contents_offset)?;
                    <#varianttype as wiggle::GuestType>::write(&variant_ptr.cast(), contents)?;
                }
            }
        } else {
            quote! {
                #ident::#variantname => {
                    #write_tag
                }
            }
        }
    });

    let mut extra_derive = quote!();
    let enum_try_from = if v.cases.iter().all(|c| c.tref.is_none()) {
        let tryfrom_repr_cases = v.cases.iter().enumerate().map(|(i, c)| {
            let variant_name = names::enum_variant(&c.name);
            let n = Literal::usize_unsuffixed(i);
            quote!(#n => Ok(#ident::#variant_name))
        });
        let abi_ty = names::wasm_type(v.tag_repr.into());
        extra_derive = quote!(, Copy);
        quote! {
            impl TryFrom<#tag_ty> for #ident {
                type Error = wiggle::GuestError;
                fn try_from(value: #tag_ty) -> Result<#ident, wiggle::GuestError> {
                    match value {
                        #(#tryfrom_repr_cases),*,
                        _ => Err(wiggle::GuestError::InvalidEnumValue(stringify!(#ident))),
                    }
                }
            }

            impl TryFrom<#abi_ty> for #ident {
                type Error = wiggle::GuestError;
                fn try_from(value: #abi_ty) -> Result<#ident, wiggle::GuestError> {
                    #ident::try_from(#tag_ty::try_from(value)?)
                }
            }
        }
    } else {
        quote!()
    };

    let enum_from = if v.cases.iter().all(|c| c.tref.is_none()) {
        let from_repr_cases = v.cases.iter().enumerate().map(|(i, c)| {
            let variant_name = names::enum_variant(&c.name);
            let n = Literal::usize_unsuffixed(i);
            quote!(#ident::#variant_name => #n)
        });
        quote! {
            impl From<#ident> for #tag_ty {
                fn from(v: #ident) -> #tag_ty {
                    match v {
                        #(#from_repr_cases),*,
                    }
                }
            }
        }
    } else {
        quote!()
    };

    let (enum_lifetime, extra_derive) = if v.needs_lifetime() {
        (quote!(<'a>), quote!())
    } else {
        (quote!(), quote!(, PartialEq #extra_derive))
    };

    let error_impls = if derive_std_error {
        quote! {
            impl std::fmt::Display for #ident {
                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                    write!(f, "{:?}", self)
                }
            }
            impl std::error::Error for #ident {}
        }
    } else {
        quote!()
    };

    quote! {
        #[derive(Clone, Debug #extra_derive)]
        pub enum #ident #enum_lifetime {
            #(#variants),*
        }
        #error_impls

        #enum_try_from
        #enum_from

        impl<'a> wiggle::GuestType<'a> for #ident #enum_lifetime {
            fn guest_size() -> u32 {
                #size
            }

            fn guest_align() -> usize {
                #align
            }

            fn read(location: &wiggle::GuestPtr<'a, Self>)
                -> Result<Self, wiggle::GuestError>
            {
                let tag = location.cast::<#tag_ty>().read()?;
                match tag {
                    #(#read_variant)*
                    _ => Err(wiggle::GuestError::InvalidEnumValue(stringify!(#ident))),
                }

            }

            fn write(location: &wiggle::GuestPtr<'_, Self>, val: Self)
                -> Result<(), wiggle::GuestError>
            {
                match val {
                    #(#write_variant)*
                }
                Ok(())
            }
        }
    }
}