Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify code generation #2686

Merged
merged 13 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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