alnyan/yggdrasil: add #define-style enums
This commit is contained in:
parent
3e96ed3258
commit
b9c3b9a1fe
@ -360,7 +360,9 @@ impl CDecl {
|
||||
|
||||
if never_return && config.language != Language::Cython {
|
||||
if let Some(ref no_return_attr) = config.function.no_return {
|
||||
out.write_fmt(format_args!(" {}", no_return_attr));
|
||||
if no_return_attr != "[[noreturn]]" {
|
||||
out.write_fmt(format_args!(" {}", no_return_attr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,6 +552,18 @@ impl StructConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum generation style.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum EnumStyle {
|
||||
/// enum E { ... }
|
||||
Enum,
|
||||
/// enum class E { ... } (if C++)
|
||||
EnumClass,
|
||||
/// #define ... if a primitive enum, fall back to EnumClass otherwise
|
||||
Define,
|
||||
}
|
||||
|
||||
/// Settings to apply to generated enums.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
@ -601,12 +613,14 @@ pub struct EnumConfig {
|
||||
pub derive_tagged_enum_copy_assignment: bool,
|
||||
/// Whether to generate a ostream serializer for the struct
|
||||
pub derive_ostream: bool,
|
||||
/// Declare the enum as an enum class.
|
||||
/// Only relevant when targeting C++.
|
||||
pub enum_class: bool,
|
||||
// /// Declare the enum as an enum class.
|
||||
// /// Only relevant when targeting C++.
|
||||
// pub enum_class: bool,
|
||||
/// Whether to generate empty, private default-constructors for tagged
|
||||
/// enums.
|
||||
pub private_default_tagged_enum_constructor: bool,
|
||||
/// How to emit enum and its variants
|
||||
pub enum_style: EnumStyle,
|
||||
}
|
||||
|
||||
impl Default for EnumConfig {
|
||||
@ -629,8 +643,8 @@ impl Default for EnumConfig {
|
||||
derive_tagged_enum_copy_constructor: false,
|
||||
derive_tagged_enum_copy_assignment: false,
|
||||
derive_ostream: false,
|
||||
enum_class: true,
|
||||
private_default_tagged_enum_constructor: false,
|
||||
enum_style: EnumStyle::EnumClass,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -688,7 +702,7 @@ impl EnumConfig {
|
||||
if let Some(x) = annotations.bool("enum-class") {
|
||||
return x;
|
||||
}
|
||||
self.enum_class
|
||||
self.enum_style == EnumStyle::EnumClass
|
||||
}
|
||||
pub(crate) fn private_default_tagged_enum_constructor(
|
||||
&self,
|
||||
|
@ -12,6 +12,7 @@ impl DeclarationType {
|
||||
DeclarationType::Struct => "struct",
|
||||
DeclarationType::Enum => "enum",
|
||||
DeclarationType::Union => "union",
|
||||
DeclarationType::IntEnum => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,6 +22,7 @@ pub enum DeclarationType {
|
||||
Struct,
|
||||
Enum,
|
||||
Union,
|
||||
IntEnum,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -35,6 +37,10 @@ impl DeclarationTypeResolver {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_int_enum(&mut self, path: &Path) {
|
||||
self.insert(path, Some(DeclarationType::IntEnum));
|
||||
}
|
||||
|
||||
pub fn add_enum(&mut self, path: &Path) {
|
||||
self.insert(path, Some(DeclarationType::Enum));
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ use crate::bindgen::monomorph::Monomorphs;
|
||||
use crate::bindgen::rename::{IdentifierType, RenameRule};
|
||||
use crate::bindgen::reserved;
|
||||
use crate::bindgen::writer::{ListType, SourceWriter};
|
||||
use crate::bindgen::EnumStyle;
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone)]
|
||||
@ -305,6 +306,7 @@ pub struct Enum {
|
||||
pub cfg: Option<Cfg>,
|
||||
pub annotations: AnnotationSet,
|
||||
pub documentation: Documentation,
|
||||
pub define_enum: bool,
|
||||
}
|
||||
|
||||
impl Enum {
|
||||
@ -409,6 +411,8 @@ impl Enum {
|
||||
None
|
||||
};
|
||||
|
||||
let define_enum = config.enumeration.enum_style == EnumStyle::Define && !has_data;
|
||||
|
||||
Ok(Enum::new(
|
||||
path,
|
||||
generic_params,
|
||||
@ -418,6 +422,7 @@ impl Enum {
|
||||
Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
|
||||
annotations,
|
||||
Documentation::load(&item.attrs),
|
||||
define_enum,
|
||||
))
|
||||
}
|
||||
|
||||
@ -431,6 +436,7 @@ impl Enum {
|
||||
cfg: Option<Cfg>,
|
||||
annotations: AnnotationSet,
|
||||
documentation: Documentation,
|
||||
define_enum: bool,
|
||||
) -> Self {
|
||||
let export_name = path.name().to_owned();
|
||||
Self {
|
||||
@ -443,6 +449,7 @@ impl Enum {
|
||||
cfg,
|
||||
annotations,
|
||||
documentation,
|
||||
define_enum,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -483,7 +490,7 @@ impl Item for Enum {
|
||||
} else {
|
||||
resolver.add_union(&self.path);
|
||||
}
|
||||
} else if self.repr.style == ReprStyle::C {
|
||||
} else if self.repr.style == ReprStyle::C && !self.define_enum {
|
||||
resolver.add_enum(&self.path);
|
||||
} else {
|
||||
// This is important to handle conflicting names with opaque items.
|
||||
@ -629,6 +636,7 @@ impl Item for Enum {
|
||||
self.cfg.clone(),
|
||||
self.annotations.clone(),
|
||||
self.documentation.clone(),
|
||||
false,
|
||||
);
|
||||
|
||||
out.insert_enum(library, self, monomorph, generic_values.to_owned());
|
||||
@ -642,6 +650,26 @@ impl Item for Enum {
|
||||
}
|
||||
|
||||
impl Enum {
|
||||
// TODO configure prefix for #define variants?
|
||||
pub(crate) fn write_define_enum<
|
||||
F: Write,
|
||||
LB: LanguageBackend,
|
||||
WV: Fn(&mut LB, &mut SourceWriter<F>, &EnumVariant),
|
||||
>(
|
||||
&self,
|
||||
_config: &Config,
|
||||
language_backend: &mut LB,
|
||||
out: &mut SourceWriter<F>,
|
||||
write_variant: WV,
|
||||
) {
|
||||
for (i, variant) in self.variants.iter().enumerate() {
|
||||
if i != 0 {
|
||||
out.new_line()
|
||||
}
|
||||
write_variant(language_backend, out, variant);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit the tag enum and convenience methods for it.
|
||||
/// For enums with data this is only a part of the output,
|
||||
/// but for enums without data it's the whole output (modulo doc comments etc.).
|
||||
|
@ -1,14 +1,14 @@
|
||||
use crate::bindgen::ir::{
|
||||
to_known_assoc_constant, ConditionWrite, DeprecatedNoteKind, Documentation, Enum, EnumVariant,
|
||||
Field, GenericParams, Item, Literal, OpaqueItem, ReprAlign, Static, Struct, ToCondition, Type,
|
||||
Typedef, Union,
|
||||
Field, GenericParams, IntKind, Item, Literal, OpaqueItem, PrimitiveType, ReprAlign, Static,
|
||||
Struct, ToCondition, Type, Typedef, Union,
|
||||
};
|
||||
use crate::bindgen::language_backend::LanguageBackend;
|
||||
use crate::bindgen::rename::IdentifierType;
|
||||
use crate::bindgen::writer::{ListType, SourceWriter};
|
||||
use crate::bindgen::{cdecl, Bindings, Config, Language};
|
||||
use crate::bindgen::{DocumentationLength, DocumentationStyle};
|
||||
use crate::bindgen::{IsizeType, UsizeType};
|
||||
use crate::bindgen::{EnumStyle, IsizeType, UsizeType};
|
||||
use std::io::Write;
|
||||
|
||||
pub struct CLikeLanguageBackend<'a> {
|
||||
@ -43,6 +43,18 @@ impl<'a> CLikeLanguageBackend<'a> {
|
||||
condition.write_after(self.config, out);
|
||||
}
|
||||
|
||||
fn write_enum_define<W: Write>(&mut self, out: &mut SourceWriter<W>, u: &EnumVariant) {
|
||||
let discriminant = u.discriminant.as_ref().unwrap();
|
||||
let condition = u.cfg.to_condition(self.config);
|
||||
|
||||
condition.write_before(self.config, out);
|
||||
|
||||
self.write_documentation(out, &u.documentation);
|
||||
write!(out, "#define {} ", u.export_name);
|
||||
self.write_literal(out, discriminant);
|
||||
out.new_line();
|
||||
}
|
||||
|
||||
fn write_field<W: Write>(&mut self, out: &mut SourceWriter<W>, f: &Field) {
|
||||
let condition = f.cfg.to_condition(self.config);
|
||||
condition.write_before(self.config, out);
|
||||
@ -472,6 +484,7 @@ impl LanguageBackend for CLikeLanguageBackend<'_> {
|
||||
fn write_enum<W: Write>(&mut self, out: &mut SourceWriter<W>, e: &Enum) {
|
||||
let size = e.repr.ty.map(|ty| ty.to_primitive().to_repr_c(self.config));
|
||||
let has_data = e.tag.is_some();
|
||||
|
||||
let inline_tag_field = Enum::inline_tag_field(&e.repr);
|
||||
let tag_name = e.tag_name();
|
||||
|
||||
@ -481,6 +494,32 @@ impl LanguageBackend for CLikeLanguageBackend<'_> {
|
||||
self.write_documentation(out, &e.documentation);
|
||||
self.write_generic_param(out, &e.generic_params);
|
||||
|
||||
if !has_data && self.config.enumeration.enum_style == EnumStyle::Define {
|
||||
self.write_type_def(
|
||||
out,
|
||||
&Typedef::new(
|
||||
e.path.clone(),
|
||||
e.generic_params.clone(),
|
||||
Type::Primitive(PrimitiveType::Integer {
|
||||
zeroable: false,
|
||||
signed: true,
|
||||
kind: IntKind::Int,
|
||||
}),
|
||||
e.cfg.clone(),
|
||||
e.annotations.clone(),
|
||||
e.documentation.clone(),
|
||||
),
|
||||
);
|
||||
|
||||
out.new_line();
|
||||
|
||||
// Write the enum as a series of #define ...
|
||||
e.write_define_enum(self.config, self, out, Self::write_enum_define);
|
||||
|
||||
condition.write_after(self.config, out);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the enum has data, we need to emit a struct or union for the data
|
||||
// and enum for the tag. C++ supports nested type definitions, so we open
|
||||
// the struct or union here and define the tag enum inside it (*).
|
||||
|
@ -1 +1,3 @@
|
||||
usize_is_size_t = true
|
||||
# usize_is_size_t = true
|
||||
usize_type = "size_t"
|
||||
isize_type = "ptrdiff_t"
|
||||
|
Loading…
x
Reference in New Issue
Block a user