Skip to content

Commit

Permalink
Simplify code generation (#2686)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Oct 20, 2023
1 parent 22de1c9 commit 30e0fbb
Show file tree
Hide file tree
Showing 19 changed files with 98 additions and 117 deletions.
26 changes: 13 additions & 13 deletions crates/libs/bindgen/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub enum AsyncKind {
pub struct Guid(pub u32, pub u16, pub u16, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl Guid {
pub fn from_args(args: &[(String, Value)]) -> Self {
pub fn from_args(args: &[(&str, Value)]) -> Self {
fn unwrap_u32(value: &Value) -> u32 {
match value {
Value::U32(value) => *value,
Expand Down Expand Up @@ -442,9 +442,7 @@ pub fn type_interfaces(ty: &Type) -> Vec<Interface> {
// This will both sort the results and should make finding dupes faster
fn walk(result: &mut Vec<Interface>, parent: &Type, is_base: bool) {
if let Type::TypeDef(row, generics) = parent {
for imp in row.interface_impls() {
let mut child = Interface { ty: imp.ty(generics), kind: if imp.has_attribute("DefaultAttribute") { InterfaceKind::Default } else { InterfaceKind::None } };

for mut child in type_def_interfaces(*row, generics) {
child.kind = if !is_base && child.kind == InterfaceKind::Default {
InterfaceKind::Default
} else if child.kind == InterfaceKind::Overridable {
Expand Down Expand Up @@ -482,8 +480,7 @@ pub fn type_interfaces(ty: &Type) -> Vec<Interface> {
"StaticAttribute" | "ActivatableAttribute" => {
for (_, arg) in attribute.args() {
if let Value::TypeName(type_name) = arg {
let type_name = parse_type_name(&type_name);
let def = row.reader().get_type_def(type_name.0, type_name.1).next().expect("Type not found");
let def = row.reader().get_type_def(type_name.namespace, type_name.name).next().expect("Type not found");
result.push(Interface { ty: Type::TypeDef(def, Vec::new()), kind: InterfaceKind::Static });
break;
}
Expand All @@ -498,7 +495,7 @@ pub fn type_interfaces(ty: &Type) -> Vec<Interface> {
result
}

fn type_name<'a>(ty: &Type) -> &'a str {
fn type_name(ty: &Type) -> &str {
match ty {
Type::TypeDef(row, _) => row.name(),
_ => "",
Expand Down Expand Up @@ -657,8 +654,15 @@ pub fn type_def_has_packing(row: TypeDef) -> bool {
}
}

pub fn type_def_interfaces(def: TypeDef, generics: &[Type]) -> impl Iterator<Item = Interface> + '_ {
def.interface_impls().map(|imp| {
let kind = if imp.has_attribute("DefaultAttribute") { InterfaceKind::Default } else { InterfaceKind::None };
Interface { kind, ty: imp.ty(generics) }
})
}

pub fn type_def_default_interface(row: TypeDef) -> Option<Type> {
row.interface_impls().find_map(move |row| if row.has_attribute("DefaultAttribute") { Some(row.ty(&[])) } else { None })
type_def_interfaces(row, &[]).find_map(move |interface| if interface.kind == InterfaceKind::Default { Some(interface.ty) } else { None })
}

fn type_signature(ty: &Type) -> String {
Expand Down Expand Up @@ -792,7 +796,7 @@ pub fn type_def_vtables(row: TypeDef) -> Vec<Type> {
}
} else {
let mut next = row;
while let Some(base) = type_def_interfaces(next, &[]).next() {
while let Some(base) = next.interface_impls().map(move |imp| imp.ty(&[])).next() {
match base {
Type::TypeDef(row, _) => {
next = row;
Expand All @@ -813,7 +817,3 @@ pub fn type_def_vtables(row: TypeDef) -> Vec<Type> {
}
result
}

pub fn type_def_interfaces(row: TypeDef, generics: &[Type]) -> impl Iterator<Item = Type> + '_ {
row.interface_impls().map(move |row| row.ty(generics))
}
40 changes: 19 additions & 21 deletions crates/libs/bindgen/src/rdl/from_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::tokens::{quote, to_ident, TokenStream};
use crate::{rdl, Error, Result, Tree};
use metadata::*;

pub fn from_reader(reader: &metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> {
pub fn from_reader(reader: &'static metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> {
let dialect = match config.remove("type") {
Some("winrt") => Dialect::WinRT,
Some("win32") => Dialect::Win32,
Expand All @@ -30,7 +30,7 @@ pub fn from_reader(reader: &metadata::Reader, mut config: std::collections::BTre

fn gen_split(writer: &Writer) -> Result<()> {
let tree = Tree::new(writer.reader);
let directory = crate::directory(writer.output);
let directory = crate::directory(&writer.output);

// TODO: parallelize
for tree in tree.flatten() {
Expand All @@ -48,7 +48,7 @@ fn gen_split(writer: &Writer) -> Result<()> {
fn gen_file(writer: &Writer) -> Result<()> {
let tree = Tree::new(writer.reader);
let tokens = writer.tree(&tree);
writer.write_to_file(writer.output, tokens)
writer.write_to_file(&writer.output, tokens)
}

#[derive(Debug, Copy, Clone, PartialEq)]
Expand All @@ -57,21 +57,21 @@ enum Dialect {
WinRT,
}

struct Writer<'a> {
reader: &'a metadata::Reader,
namespace: &'a str,
struct Writer {
reader: &'static metadata::Reader,
namespace: &'static str,
dialect: Dialect,
split: bool,
output: &'a str,
output: String,
}

impl<'a> Writer<'a> {
fn new(reader: &'a metadata::Reader, output: &'a str, dialect: Dialect) -> Self {
Self { reader, namespace: "", output, dialect, split: false }
impl Writer {
fn new(reader: &'static metadata::Reader, output: &str, dialect: Dialect) -> Self {
Self { reader, namespace: "", output: output.to_string(), dialect, split: false }
}

fn with_namespace(&self, namespace: &'a str) -> Self {
Self { reader: self.reader, namespace, dialect: self.dialect, output: self.output, split: self.split }
fn with_namespace(&self, namespace: &'static str) -> Self {
Self { reader: self.reader, namespace, dialect: self.dialect, output: self.output.clone(), split: self.split }
}

fn write_to_file(&self, output: &str, tokens: TokenStream) -> Result<()> {
Expand All @@ -90,7 +90,7 @@ impl<'a> Writer<'a> {
//crate::write_to_file(output, tokens.into_string())
}

fn tree(&self, tree: &'a Tree) -> TokenStream {
fn tree(&self, tree: &Tree) -> TokenStream {
let items = self.items(tree);

if self.split {
Expand Down Expand Up @@ -128,7 +128,7 @@ impl<'a> Writer<'a> {
}
}

fn items(&self, tree: &'a Tree) -> TokenStream {
fn items(&self, tree: &Tree) -> TokenStream {
let mut functions = vec![];
let mut constants = vec![];
let mut types = vec![];
Expand Down Expand Up @@ -286,12 +286,11 @@ impl<'a> Writer<'a> {
// TODO: then list default interface first
// Then everything else

for imp in def.interface_impls() {
let ty = imp.ty(generics);
if imp.has_attribute("DefaultAttribute") {
types.insert(0, self.ty(&ty));
for interface in type_def_interfaces(def, generics) {
if interface.kind == InterfaceKind::Default {
types.insert(0, self.ty(&interface.ty));
} else {
types.push(self.ty(&ty));
types.push(self.ty(&interface.ty));
}
}

Expand Down Expand Up @@ -358,8 +357,7 @@ impl<'a> Writer<'a> {
}
}

metadata::Type::TypeRef(code) => {
let type_name = code.type_name();
metadata::Type::TypeRef(type_name) => {
let namespace = self.namespace(type_name.namespace);
let name = to_ident(type_name.name);
quote! { #namespace #name }
Expand Down
13 changes: 3 additions & 10 deletions crates/libs/bindgen/src/rust/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,12 @@ pub fn type_def_cfg_impl(def: TypeDef, generics: &[Type]) -> Cfg {

combine(def, generics, &mut cfg);

for def in type_def_vtables(def) {
if let Type::TypeDef(def, generics) = def {
for interface in type_interfaces(&Type::TypeDef(def, generics.to_vec())) {
if let Type::TypeDef(def, generics) = interface.ty {
combine(def, &generics, &mut cfg);
}
}

if def.flags().contains(TypeAttributes::WindowsRuntime) {
for interface in type_def_interfaces(def, generics) {
if let Type::TypeDef(def, generics) = interface {
combine(def, &generics, &mut cfg);
}
}
}

cfg_add_attributes(&mut cfg, def);
cfg
}
Expand Down Expand Up @@ -156,6 +148,7 @@ pub fn type_cfg(ty: &Type) -> Cfg {
type_cfg_combine(ty, &mut cfg);
cfg
}

fn type_cfg_combine(ty: &Type, cfg: &mut Cfg) {
match ty {
Type::TypeDef(row, generics) => type_def_cfg_combine(*row, generics, cfg),
Expand Down
8 changes: 2 additions & 6 deletions crates/libs/bindgen/src/rust/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::*;

pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream {
if writer.sys {
if type_def_has_default_interface(def) {
if def.interface_impls().next().is_some() {
let name = to_ident(def.name());
quote! {
pub type #name = *mut ::core::ffi::c_void;
Expand Down Expand Up @@ -64,7 +64,7 @@ fn gen_class(writer: &Writer, def: TypeDef) -> TokenStream {
_ => None,
});

if type_def_has_default_interface(def) {
if def.interface_impls().next().is_some() {
let new = if type_def_has_default_constructor(def) {
quote! {
pub fn new() -> ::windows_core::Result<Self> {
Expand Down Expand Up @@ -172,10 +172,6 @@ fn type_def_has_default_constructor(row: TypeDef) -> bool {
false
}

fn type_def_has_default_interface(row: TypeDef) -> bool {
row.interface_impls().any(|imp| imp.has_attribute("DefaultAttribute"))
}

fn type_is_exclusive(ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => type_def_is_exclusive(*row),
Expand Down
8 changes: 4 additions & 4 deletions crates/libs/bindgen/src/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{Error, Result, Tree};
use cfg::*;
use rayon::prelude::*;

pub fn from_reader(reader: &metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> {
pub fn from_reader(reader: &'static metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> {
let mut writer = Writer::new(reader, output);
writer.package = config.remove("package").is_some();
writer.flatten = config.remove("flatten").is_some();
Expand Down Expand Up @@ -56,7 +56,7 @@ fn gen_file(writer: &Writer) -> Result<()> {

if writer.flatten {
let tokens = standalone::standalone_imp(writer);
crate::write_to_file(writer.output, try_format(writer, &tokens))
crate::write_to_file(&writer.output, try_format(writer, &tokens))
} else {
let mut tokens = String::new();
let root = Tree::new(writer.reader);
Expand All @@ -65,12 +65,12 @@ fn gen_file(writer: &Writer) -> Result<()> {
tokens.push_str(&namespace(writer, tree));
}

crate::write_to_file(writer.output, try_format(writer, &tokens))
crate::write_to_file(&writer.output, try_format(writer, &tokens))
}
}

fn gen_package(writer: &Writer) -> Result<()> {
let directory = crate::directory(writer.output);
let directory = crate::directory(&writer.output);
let root = Tree::new(writer.reader);
let mut root_len = 0;

Expand Down
18 changes: 9 additions & 9 deletions crates/libs/bindgen/src/rust/writer.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::*;

#[derive(Clone)]
pub struct Writer<'a> {
pub reader: &'a Reader,
pub output: &'a str,
pub namespace: &'a str,
pub struct Writer {
pub reader: &'static Reader,
pub output: String,
pub namespace: &'static str,
pub implement: bool, // TODO: ideally we can use this to generate implementation traits on the fly and
// and have a single interface definition macro for consumption that expands to include
// impl traits when the `implement` cfg flag is set and then this writer option would be
Expand All @@ -20,11 +20,11 @@ pub struct Writer<'a> {
pub no_inner_attributes: bool, // skips the inner attributes at the start of the file
}

impl<'a> Writer<'a> {
pub fn new(reader: &'a Reader, output: &'a str) -> Self {
impl Writer {
pub fn new(reader: &'static Reader, output: &str) -> Self {
Self {
reader,
output,
output: output.to_string(),
namespace: "",
implement: false,
std: false,
Expand Down Expand Up @@ -403,7 +403,7 @@ impl<'a> Writer<'a> {
quote! { #arch #features }
}

fn cfg_features_imp(&self, cfg: &'a Cfg, namespace: &'a str) -> Vec<&'a str> {
fn cfg_features_imp(&self, cfg: &Cfg, namespace: &str) -> Vec<&'static str> {
let mut compact = Vec::<&'static str>::new();
if self.package {
for feature in cfg.types.keys() {
Expand Down Expand Up @@ -568,7 +568,7 @@ impl<'a> Writer<'a> {
let mut async_generics = generics.to_vec();

if kind == AsyncKind::None {
for interface in type_def_interfaces(def, generics) {
for interface in def.interface_impls().map(move |imp| imp.ty(generics)) {
if let Type::TypeDef(interface_def, interface_generics) = &interface {
kind = type_def_async_kind(*interface_def);
if kind != AsyncKind::None {
Expand Down
14 changes: 7 additions & 7 deletions crates/libs/bindgen/src/tree.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use super::*;

#[derive(Debug)]
pub struct Tree<'a> {
pub namespace: &'a str,
pub nested: std::collections::BTreeMap<&'a str, Tree<'a>>,
pub struct Tree {
pub namespace: &'static str,
pub nested: std::collections::BTreeMap<&'static str, Tree>,
}

impl<'a> Tree<'a> {
pub fn new(reader: &'a metadata::Reader) -> Self {
impl Tree {
pub fn new(reader: &'static metadata::Reader) -> Self {
let mut tree = Tree::from_namespace("");
for ns in reader.namespaces() {
if reader.includes_namespace(ns) {
Expand All @@ -17,10 +17,10 @@ impl<'a> Tree<'a> {
tree
}

fn from_namespace(namespace: &'a str) -> Self {
fn from_namespace(namespace: &'static str) -> Self {
Self { namespace, nested: std::collections::BTreeMap::new() }
}
fn insert_namespace(&mut self, namespace: &'a str, pos: usize) -> &mut Self {
fn insert_namespace(&mut self, namespace: &'static str, pos: usize) -> &mut Self {
if let Some(next) = namespace[pos..].find('.') {
let next = pos + next;
self.nested.entry(&namespace[pos..next]).or_insert_with(|| Self::from_namespace(&namespace[..next])).insert_namespace(namespace, next + 1)
Expand Down
9 changes: 4 additions & 5 deletions crates/libs/bindgen/src/winmd/from_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,15 @@ pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap

for generic in def.generics() {
writer.tables.GenericParam.push(writer::GenericParam {
Number: generic.number(),
Number: generic.number(), // TODO: isn't this just going to be incremental?
Flags: 0,
Owner: writer::TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1).encode(),
Name: writer.strings.insert(generic.name()),
});
}

for imp in def.interface_impls() {
let ty = imp.ty(generics);
let ty = winmd_type(&ty);
for interface in metadata::type_def_interfaces(def, generics) {
let ty = winmd_type(&interface.ty);

let reference = match &ty {
winmd::Type::TypeRef(type_name) if type_name.generics.is_empty() => writer.insert_type_ref(&type_name.namespace, &type_name.name),
Expand Down Expand Up @@ -122,7 +121,7 @@ fn winmd_type(ty: &metadata::Type) -> winmd::Type {
metadata::Type::PCSTR => winmd::Type::PCSTR,
metadata::Type::PCWSTR => winmd::Type::PCWSTR,
metadata::Type::BSTR => winmd::Type::BSTR,
metadata::Type::TypeName => winmd::Type::TypeName,
metadata::Type::Type => winmd::Type::Type,
metadata::Type::TypeDef(def, generics) => winmd::Type::TypeRef(winmd::TypeName { namespace: def.namespace().to_string(), name: def.name().to_string(), generics: generics.iter().map(winmd_type).collect() }),
metadata::Type::GenericParam(generic) => winmd::Type::GenericParam(generic.number()),
metadata::Type::ConstRef(ty) => winmd::Type::ConstRef(Box::new(winmd_type(ty))),
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/winmd/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn verify(reader: &metadata::Reader) -> crate::Result<()> {

fn not_type_ref(ty: &metadata::Type) -> crate::Result<()> {
if let metadata::Type::TypeRef(ty) = ty {
return Err(crate::Error::new(&format!("missing type definition `{}`", ty.type_name())));
return Err(crate::Error::new(&format!("missing type definition `{}`", ty)));
}
Ok(())
}
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/winmd/writer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ impl Writer {
usize_blob(1, blob); // count
usize_blob(*bounds, blob);
}
Type::TypeName => {
Type::Type => {
let code = self.insert_type_ref("System", "Type");
blob.push(metadata::ELEMENT_TYPE_CLASS);
usize_blob(code as usize, blob);
Expand Down
Loading

0 comments on commit 30e0fbb

Please sign in to comment.