diff --git a/crates/generate/src/funcs.rs b/crates/generate/src/funcs.rs index fc7593d4e2..13eff6baa1 100644 --- a/crates/generate/src/funcs.rs +++ b/crates/generate/src/funcs.rs @@ -1,8 +1,8 @@ use proc_macro2::TokenStream; use quote::quote; +use crate::lifetimes::{anon_lifetime, LifetimeExt}; use crate::names::Names; -use crate::types::{anon_lifetime, struct_is_copy}; pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { let funcname = func.name.as_str(); @@ -258,7 +258,7 @@ fn marshal_arg( }; } } - witx::Type::Struct(s) if struct_is_copy(&s) => { + witx::Type::Struct(s) if !s.needs_lifetime() => { let pointee_type = names.type_ref(tref, anon_lifetime()); let arg_name = names.func_ptr_binding(¶m.name); let name = names.func_param(¶m.name); @@ -276,7 +276,7 @@ fn marshal_arg( }; } } - witx::Type::Struct(s) if !struct_is_copy(&s) => read_conversion, + witx::Type::Struct(s) if s.needs_lifetime() => read_conversion, witx::Type::Array(arr) => { let pointee_type = names.type_ref(arr, anon_lifetime()); let ptr_name = names.func_ptr_binding(¶m.name); diff --git a/crates/generate/src/lib.rs b/crates/generate/src/lib.rs index 4a50d88874..d7ea6d23a4 100644 --- a/crates/generate/src/lib.rs +++ b/crates/generate/src/lib.rs @@ -2,6 +2,7 @@ extern crate proc_macro; mod config; mod funcs; +mod lifetimes; mod module_trait; mod names; mod types; diff --git a/crates/generate/src/lifetimes.rs b/crates/generate/src/lifetimes.rs new file mode 100644 index 0000000000..ae9631a63b --- /dev/null +++ b/crates/generate/src/lifetimes.rs @@ -0,0 +1,56 @@ +use proc_macro2::TokenStream; +use quote::quote; + +pub trait LifetimeExt { + fn needs_lifetime(&self) -> bool; +} + +impl LifetimeExt for witx::TypeRef { + fn needs_lifetime(&self) -> bool { + self.type_().needs_lifetime() + } +} + +impl LifetimeExt for witx::Type { + fn needs_lifetime(&self) -> bool { + match self { + witx::Type::Builtin(b) => b.needs_lifetime(), + witx::Type::Struct(s) => s.needs_lifetime(), + witx::Type::Union(u) => u.needs_lifetime(), + witx::Type::Enum { .. } + | witx::Type::Flags { .. } + | witx::Type::Int { .. } + | witx::Type::Handle { .. } => false, + witx::Type::Pointer { .. } + | witx::Type::ConstPointer { .. } + | witx::Type::Array { .. } => true, + } + } +} + +impl LifetimeExt for witx::BuiltinType { + fn needs_lifetime(&self) -> bool { + match self { + witx::BuiltinType::String => true, + _ => false, + } + } +} + +impl LifetimeExt for witx::StructDatatype { + fn needs_lifetime(&self) -> bool { + self.members.iter().any(|m| m.tref.needs_lifetime()) + } +} + +impl LifetimeExt for witx::UnionDatatype { + fn needs_lifetime(&self) -> bool { + self.variants + .iter() + .any(|m| m.tref.as_ref().map(|t| t.needs_lifetime()).unwrap_or(false)) + } +} + +pub fn anon_lifetime() -> TokenStream { + quote!('_) +} diff --git a/crates/generate/src/module_trait.rs b/crates/generate/src/module_trait.rs index 4cb4c45045..7fc1f46cd2 100644 --- a/crates/generate/src/module_trait.rs +++ b/crates/generate/src/module_trait.rs @@ -1,8 +1,8 @@ use proc_macro2::TokenStream; use quote::quote; +use crate::lifetimes::{anon_lifetime, LifetimeExt}; use crate::names::Names; -use crate::types::{anon_lifetime, type_needs_lifetime}; use witx::Module; pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream { @@ -11,8 +11,7 @@ pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream { // 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.results.iter().any(|ret| type_needs_lifetime(&ret.tref)) - { + let (lifetime, is_anonymous) = if f.results.iter().any(|ret| ret.tref.needs_lifetime()) { (quote!('a), false) } else { (anon_lifetime(), true) diff --git a/crates/generate/src/names.rs b/crates/generate/src/names.rs index c967f6e1da..f268514c1d 100644 --- a/crates/generate/src/names.rs +++ b/crates/generate/src/names.rs @@ -3,7 +3,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use witx::{AtomType, BuiltinType, Id, TypeRef}; -use crate::types::type_needs_lifetime; +use crate::lifetimes::LifetimeExt; use crate::Config; #[derive(Debug, Clone)] @@ -52,7 +52,7 @@ impl Names { match tref { TypeRef::Name(nt) => { let ident = self.type_(&nt.name); - if type_needs_lifetime(&nt.tref) { + if nt.tref.needs_lifetime() { quote!(#ident<#lifetime>) } else { quote!(#ident) diff --git a/crates/generate/src/types.rs b/crates/generate/src/types.rs index e6767f9144..bd05467d38 100644 --- a/crates/generate/src/types.rs +++ b/crates/generate/src/types.rs @@ -1,3 +1,4 @@ +use crate::lifetimes::{anon_lifetime, LifetimeExt}; use crate::names::Names; use proc_macro2::{Literal, TokenStream}; @@ -13,7 +14,7 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea witx::Type::Int(i) => define_int(names, &namedtype.name, &i), witx::Type::Flags(f) => define_flags(names, &namedtype.name, &f), witx::Type::Struct(s) => { - if struct_is_copy(s) { + if !s.needs_lifetime() { define_copy_struct(names, &namedtype.name, &s) } else { define_ptr_struct(names, &namedtype.name, &s) @@ -39,7 +40,7 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea fn define_alias(names: &Names, name: &witx::Id, to: &witx::NamedType) -> TokenStream { let ident = names.type_(name); let rhs = names.type_(&to.name); - if type_needs_lifetime(&to.tref) { + if to.tref.needs_lifetime() { quote!(pub type #ident<'a> = #rhs<'a>;) } else { quote!(pub type #ident = #rhs;) @@ -407,66 +408,6 @@ fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> } } -// XXX DRY - should move these funcs to be a trait that Type, BuiltinType, StructDatatype, -// UnionDatatype all implement -pub fn type_needs_lifetime(tref: &witx::TypeRef) -> bool { - match &*tref.type_() { - witx::Type::Builtin(b) => match b { - witx::BuiltinType::String => true, - _ => false, - }, - witx::Type::Enum { .. } - | witx::Type::Flags { .. } - | witx::Type::Int { .. } - | witx::Type::Handle { .. } => false, - witx::Type::Struct(s) => !struct_is_copy(&s), - witx::Type::Union(u) => !union_is_copy(&u), - witx::Type::Pointer { .. } | witx::Type::ConstPointer { .. } => true, - witx::Type::Array { .. } => true, - } -} - -pub fn struct_is_copy(s: &witx::StructDatatype) -> bool { - s.members.iter().all(|m| match &*m.tref.type_() { - witx::Type::Struct(s) => struct_is_copy(&s), - witx::Type::Builtin(b) => match &*b { - witx::BuiltinType::String => false, - _ => true, - }, - witx::Type::ConstPointer { .. } | witx::Type::Pointer { .. } | witx::Type::Array { .. } => { - false - } - witx::Type::Union(u) => union_is_copy(u), - witx::Type::Enum { .. } - | witx::Type::Int { .. } - | witx::Type::Flags { .. } - | witx::Type::Handle { .. } => true, - }) -} -pub fn union_is_copy(u: &witx::UnionDatatype) -> bool { - u.variants.iter().all(|m| { - if let Some(tref) = &m.tref { - match &*tref.type_() { - witx::Type::Struct(s) => struct_is_copy(&s), - witx::Type::Builtin(b) => match &*b { - witx::BuiltinType::String => false, - _ => true, - }, - witx::Type::ConstPointer { .. } - | witx::Type::Pointer { .. } - | witx::Type::Array { .. } => false, - witx::Type::Union(u) => union_is_copy(u), - witx::Type::Enum { .. } - | witx::Type::Int { .. } - | witx::Type::Flags { .. } - | witx::Type::Handle { .. } => true, - } - } else { - true - } - }) -} - fn define_copy_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -> TokenStream { let ident = names.type_(name); let size = s.mem_size_align().size as u32; @@ -774,7 +715,7 @@ fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDatatype) -> Toke }); let validate = union_validate(names, ident.clone(), u, &ulayout); - if union_is_copy(u) { + if !u.needs_lifetime() { // Type does not have a lifetime parameter: quote! { #[derive(Clone, Debug, PartialEq)] @@ -887,7 +828,3 @@ fn atom_token(atom: witx::AtomType) -> TokenStream { witx::AtomType::F64 => quote!(f64), } } - -pub fn anon_lifetime() -> TokenStream { - quote!('_) -}