diff options
author | Joseph Rafael Ferrer <rafael2x0@gmail.com> | 2019-10-26 17:57:13 +0800 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2019-11-08 14:08:09 +0100 |
commit | 1c31f29e4e5d514e6df14d2e82662de7e947c2af (patch) | |
tree | b407b31ff85476f00aa3f3dcc5ddac9461ca319a /src/codegen/mod.rs | |
parent | 3609bd6ecbf229bcab7967b974708cf8974d9f93 (diff) |
Option to use #[repr(transparent)] structs instead of type aliasing.
Diffstat (limited to 'src/codegen/mod.rs')
-rw-r--r-- | src/codegen/mod.rs | 106 |
1 files changed, 102 insertions, 4 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index a3755867..ea01d4b7 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -749,6 +749,16 @@ impl CodeGenerator for Type { quote! {} }; + let alias_style = if ctx.options().type_alias.matches(&name) { + AliasVariation::TypeAlias + } else if ctx.options().new_type_alias.matches(&name) { + AliasVariation::NewType + } else if ctx.options().new_type_alias_deref.matches(&name) { + AliasVariation::NewTypeDeref + } else { + ctx.options().default_alias_style + }; + // We prefer using `pub use` over `pub type` because of: // https://github.com/rust-lang/rust/issues/26264 if inner_rust_type.to_string().chars().all(|c| match c { @@ -758,6 +768,7 @@ impl CodeGenerator for Type { _ => false, }) && outer_params.is_empty() && !is_opaque && + alias_style == AliasVariation::TypeAlias && inner_item.expect_type().canonical_type(ctx).is_enum() { tokens.append_all(quote! { @@ -772,8 +783,21 @@ impl CodeGenerator for Type { return; } - tokens.append_all(quote! { - pub type #rust_name + tokens.append_all(match alias_style { + AliasVariation::TypeAlias => quote! { + pub type #rust_name + }, + AliasVariation::NewType | AliasVariation::NewTypeDeref => { + assert!( + ctx.options().rust_features().repr_transparent, + "repr_transparent feature is required to use {:?}", + alias_style + ); + quote! { + #[repr(transparent)] + pub struct #rust_name + } + } }); let params: Vec<_> = outer_params @@ -806,10 +830,36 @@ impl CodeGenerator for Type { }); } - tokens.append_all(quote! { - = #inner_rust_type ; + tokens.append_all(match alias_style { + AliasVariation::TypeAlias => quote! { + = #inner_rust_type ; + }, + AliasVariation::NewType | AliasVariation::NewTypeDeref => { + quote! { + (pub #inner_rust_type) ; + } + } }); + if alias_style == AliasVariation::NewTypeDeref { + let prefix = ctx.trait_prefix(); + tokens.append_all(quote! { + impl ::#prefix::ops::Deref for #rust_name { + type Target = #inner_rust_type; + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::#prefix::ops::DerefMut for #rust_name { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + }); + } + result.push(tokens); } TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item), @@ -2870,6 +2920,54 @@ impl CodeGenerator for Enum { } } +/// Enum for how aliases should be translated. +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AliasVariation { + /// Convert to regular Rust alias + TypeAlias, + /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)] + NewType, + /// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type + NewTypeDeref, +} + +impl AliasVariation { + /// Convert an `AliasVariation` to its str representation. + pub fn as_str(&self) -> &str { + match self { + AliasVariation::TypeAlias => "type_alias", + AliasVariation::NewType => "new_type", + AliasVariation::NewTypeDeref => "new_type_deref", + } + } +} + +impl Default for AliasVariation { + fn default() -> AliasVariation { + AliasVariation::TypeAlias + } +} + +impl std::str::FromStr for AliasVariation { + type Err = std::io::Error; + + /// Create an `AliasVariation` from a string. + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "type_alias" => Ok(AliasVariation::TypeAlias), + "new_type" => Ok(AliasVariation::NewType), + "new_type_deref" => Ok(AliasVariation::NewTypeDeref), + _ => Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + concat!( + "Got an invalid AliasVariation. Accepted values ", + "are 'type_alias', 'new_type', and 'new_type_deref'" + ), + )), + } + } +} + /// Fallible conversion to an opaque blob. /// /// Implementors of this trait should provide the `try_get_layout` method to |