[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH 08/25] tools/xenbindgen: Add support for enums in TOML specs
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@xxxxxxxxx> --- tools/rust/xenbindgen/src/c_lang.rs | 57 +++++++++++++++++++++++++---- tools/rust/xenbindgen/src/spec.rs | 45 +++++++++++++++++++++++ 2 files changed, 95 insertions(+), 7 deletions(-) diff --git a/tools/rust/xenbindgen/src/c_lang.rs b/tools/rust/xenbindgen/src/c_lang.rs index 597e0ed41362..f15feca8df91 100644 --- a/tools/rust/xenbindgen/src/c_lang.rs +++ b/tools/rust/xenbindgen/src/c_lang.rs @@ -17,10 +17,10 @@ use std::fmt::Write; -use crate::spec::{OutFileDef, StructDef, Typ}; +use crate::spec::{EnumDef, OutFileDef, StructDef, Typ}; use convert_case::{Case, Casing}; -use log::{debug, trace}; +use log::{debug, error, trace}; /// An abstract indentation level. 0 is no indentation, 1 is [`INDENT_WIDTH`] /// and so on. @@ -31,7 +31,7 @@ struct Indentation(usize); const INDENT_WIDTH: usize = 4; /// Create a C-compatible struct field. Without the terminating semicolon. -fn structfield(typ: &Typ, name: &str) -> String { +fn structfield(filedef: &OutFileDef, typ: &Typ, name: &str) -> String { match typ { Typ::Ptr(x) => { let t: &Typ = x; @@ -51,7 +51,20 @@ fn structfield(typ: &Typ, name: &str) -> String { ) } Typ::Struct(x) => format!("struct {x} {name}"), - Typ::Array(x, len) => format!("{}{name}[{len}]", structfield(x, "")), + Typ::Enum(x) => { + // C can't use an enum as a field and fix its width. Look for its + // underlying layout and use that type instead. + let Some(e) = filedef.enums.iter().find(|y| *x == y.name) else { + error!("Can't find enum {x}. Typo?"); + std::process::exit(1); + }; + format!( + "{} /* See {} */", + structfield(filedef, &e.typ, name), + e.name + ) + } + Typ::Array(x, len) => format!("{}{name}[{len}]", structfield(filedef, x, "")), Typ::U8 => format!("uint8_t {name}"), Typ::U16 => format!("uint16_t {name}"), Typ::U32 => format!("uint32_t {name}"), @@ -83,7 +96,7 @@ fn comment(out: &mut String, comment: &str, ind: Indentation) { } /// Write a C-compatible struct onto `out` -fn structgen(out: &mut String, def: &StructDef) { +fn structgen(out: &mut String, filedef: &OutFileDef, def: &StructDef) { debug!("struct {}", def.name); comment(out, &def.description, Indentation(0)); @@ -92,7 +105,33 @@ fn structgen(out: &mut String, def: &StructDef) { trace!(" field {} type={:?}", f.name, f.typ); comment(out, &f.description, Indentation(1)); - writeln!(out, " {};", structfield(&f.typ, &f.name),).unwrap(); + writeln!(out, " {};", structfield(filedef, &f.typ, &f.name),).unwrap(); + } + writeln!(out, "}};").unwrap(); + writeln!(out).unwrap(); +} + +/// Write a C-compatible enum onto `out` +/// +/// This is a generator for the enum _type_, not an instantiation of a bitmap +/// in a struct field. Use [`structfield`] for that. +fn enumgen(out: &mut String, def: &EnumDef) { + debug!("enum {}", def.name); + + comment(out, &def.description, Indentation(0)); + writeln!(out, "enum {} {{", def.name).unwrap(); + for f in &def.variants { + trace!(" variant {}={}", f.name, f.value); + + comment(out, &f.description, Indentation(1)); + writeln!( + out, + " {}_{} = {},", + def.name.from_case(Case::Snake).to_case(Case::UpperSnake), + f.name.from_case(Case::Snake).to_case(Case::UpperSnake), + f.value + ) + .unwrap(); } writeln!(out, "}};").unwrap(); writeln!(out).unwrap(); @@ -117,8 +156,12 @@ pub fn parse(filedef: &OutFileDef) -> String { writeln!(out, "#ifndef __XEN_AUTOGEN_{name}_H").unwrap(); writeln!(out, "#define __XEN_AUTOGEN_{name}_H\n").unwrap(); + for def in &filedef.enums { + enumgen(&mut out, def); + } + for def in &filedef.structs { - structgen(&mut out, def); + structgen(&mut out, filedef, def); } writeln!(out, "#endif /* __XEN_AUTOGEN_{name}_H */\n").unwrap(); diff --git a/tools/rust/xenbindgen/src/spec.rs b/tools/rust/xenbindgen/src/spec.rs index e183378329ad..f6cfedad2150 100644 --- a/tools/rust/xenbindgen/src/spec.rs +++ b/tools/rust/xenbindgen/src/spec.rs @@ -28,6 +28,7 @@ use log::{debug, info}; #[derive(Debug, serde::Deserialize, PartialEq)] #[serde(rename_all = "lowercase", tag = "tag", content = "args")] pub enum Typ { + Enum(String), Struct(String), U8, U16, @@ -66,11 +67,47 @@ pub struct FieldDef { pub typ: Typ, } +/// Description of a lang-agnostic enumerated type. +#[derive(Debug, serde::Deserialize)] +pub struct EnumDef { + /// snake-cased name of this enumeration. + /// + /// Must be converted to whatever is idiomatic in the target language. + pub name: String, + /// Description of what the type is for. + /// + /// Must be turned into documentation in the autogenerated file. + pub description: String, + /// Width of the type given as an equivalent primitive unsigned integer + /// of the same width. + pub typ: Typ, + /// List of variants present in this enum. + /// + /// The backend must export all of these under the same namespace if + /// possible. + pub variants: Vec<VariantDef>, +} + +/// A lang-agnostic description of a single variant of an enumerated type. +#[derive(Debug, serde::Deserialize)] +pub struct VariantDef { + /// Name of this variant. Depending on the backend, the name might be + /// prefixed by the name of its type (as is commonly done in C). + pub name: String, + /// Meaning of this variant in the context of its type. + pub description: String, + /// Actual value associated with this variant. Must be explicit to enable + /// deprecation of variants. + pub value: u64, +} + /// A language-agnostic specification. #[derive(Debug, serde::Deserialize)] struct InFileDef { /// List of structs described in this input specification. structs: Option<Vec<StructDef>>, + /// List of lang-agnostic enumerated descriptions. + enums: Option<Vec<EnumDef>>, } /// Description of an abstract output (i.e: `.rs`, `.h`, etc). @@ -82,6 +119,10 @@ pub struct OutFileDef { pub name: String, /// List of structs described by all input spec files merged on this file. pub structs: Vec<StructDef>, + /// List of enumerated descriptions. + /// + /// Implementation is lang-specific. + pub enums: Vec<EnumDef>, } impl OutFileDef { @@ -97,6 +138,7 @@ impl OutFileDef { let mut ret = Self { name, structs: Vec::new(), + enums: Vec::new(), }; for entry in from_ioerr(dir.read_dir())? { @@ -107,6 +149,9 @@ impl OutFileDef { if let Some(structs) = filedef.structs { ret.structs.extend(structs); } + if let Some(enums) = filedef.enums { + ret.enums.extend(enums); + } } Ok(ret) -- 2.47.0
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |