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

Use a consistent set of dependencies across the implement and interface crates #1931

Merged
merged 1 commit into from
Jul 25, 2022
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
3 changes: 2 additions & 1 deletion crates/libs/implement/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ proc-macro = true

[dependencies]
syn = { version = "1.0", default-features = false, features = ["parsing", "proc-macro", "printing", "full", "derive"] }
tokens = { package = "windows-tokens", path = "../tokens", version = "0.39.0" }
quote = "1.0"
proc-macro2 = "1.0"
100 changes: 43 additions & 57 deletions crates/libs/implement/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
use std::collections::*;
use syn::parse::*;
use syn::Ident;
use syn::*;
use tokens::*;
use quote::quote;

#[proc_macro_attribute]
pub fn implement(attributes: proc_macro::TokenStream, original_type: proc_macro::TokenStream) -> proc_macro::TokenStream {
let attributes = syn::parse_macro_input!(attributes as ImplementAttributes);
let generics = attributes.generics();
let interfaces_len = Literal::usize_unsuffixed(attributes.implement.len());
let generics: Vec<proc_macro2::TokenStream> = attributes.generics().iter().map(|g| syn::parse_str::<proc_macro2::TokenStream>(g).expect("Invalid token stream")).collect();
let interfaces_len = proc_macro2::Literal::usize_unsuffixed(attributes.implement.len());

let constraints = quote! {
#(#generics: ::windows::core::RuntimeType + 'static,)*
Expand All @@ -21,25 +17,22 @@ pub fn implement(attributes: proc_macro::TokenStream, original_type: proc_macro:
};

let original_type2 = original_type.clone();
let original_ident = TokenStream(syn::parse_macro_input!(original_type2 as syn::ItemStruct).ident.to_string());
let impl_ident = original_ident.join("_Impl");
let original_ident = syn::parse_macro_input!(original_type2 as syn::ItemStruct).ident;
let impl_ident = quote::format_ident!("{}_Impl", original_ident);
let vtbl_idents = attributes.implement.iter().map(|implement| implement.to_vtbl_ident());
let vtbl_idents2 = vtbl_idents.clone();

let vtable_news = attributes.implement.iter().enumerate().map(|(enumerate, implement)| {
let vtbl_ident = implement.to_vtbl_ident();
let offset: TokenStream = format!("{}", -2 - enumerate as isize).into();
let offset = proc_macro2::Literal::isize_unsuffixed(-2 - enumerate as isize);
quote! { #vtbl_ident::new::<Self, #original_ident::<#(#generics,)*>, #offset>() }
});

let offset = attributes.implement.iter().enumerate().map(|(offset, _)| {
let offset: TokenStream = format!("{}", offset).into();
offset
});
let offset = attributes.implement.iter().enumerate().map(|(offset, _)| proc_macro2::Literal::usize_unsuffixed(offset));

let queries = attributes.implement.iter().enumerate().map(|(count, implement)| {
let vtbl_ident = implement.to_vtbl_ident();
let offset: TokenStream = format!("{}", count).into();
let offset = proc_macro2::Literal::usize_unsuffixed(count);
quote! {
else if #vtbl_ident::matches(iid) {
&self.vtables.#offset as *const _ as *const _
Expand All @@ -49,7 +42,7 @@ pub fn implement(attributes: proc_macro::TokenStream, original_type: proc_macro:

let conversions = attributes.implement.iter().enumerate().map(|(enumerate, implement)| {
let interface_ident = implement.to_ident();
let offset: TokenStream = enumerate.to_string().into();
let offset = proc_macro2::Literal::usize_unsuffixed(enumerate);
quote! {
impl <#constraints> ::core::convert::From<#original_ident::<#(#generics,)*>> for #interface_ident {
fn from(this: #original_ident::<#(#generics,)*>) -> Self {
Expand Down Expand Up @@ -186,7 +179,7 @@ pub fn implement(attributes: proc_macro::TokenStream, original_type: proc_macro:
#(#conversions)*
};

let mut tokens = tokens.parse::<proc_macro::TokenStream>().unwrap();
let mut tokens: proc_macro::TokenStream = tokens.into();
tokens.extend(core::iter::once(original_type));
tokens
}
Expand All @@ -198,29 +191,22 @@ struct ImplementType {
}

impl ImplementType {
fn to_ident(&self) -> TokenStream {
let mut tokens: TokenStream = self.type_name.clone().into();
tokens.push_str("<");

for g in &self.generics {
tokens.combine(&g.to_ident());
tokens.push_str(",");
}

tokens.push_str(">");
tokens
fn to_ident(&self) -> proc_macro2::TokenStream {
let type_name = syn::parse_str::<proc_macro2::TokenStream>(&self.type_name).expect("Invalid token stream");
let generics = self.generics.iter().map(|g| g.to_ident());
quote! { #type_name<#(#generics,)*> }
}
fn to_vtbl_ident(&self) -> TokenStream {
fn to_vtbl_ident(&self) -> proc_macro2::TokenStream {
let ident = self.to_ident();
quote! {
<#ident as ::windows::core::Interface>::Vtable
}
}
fn generics(&self) -> BTreeSet<TokenStream> {
let mut set = BTreeSet::new();
fn generics(&self) -> std::collections::BTreeSet<String> {
let mut set = std::collections::BTreeSet::new();

if self.type_name.len() == 1 && self.type_name == self.type_name.to_uppercase() {
set.insert(self.type_name.clone().into());
set.insert(self.type_name.clone());
}

for def in &self.generics {
Expand All @@ -236,8 +222,8 @@ struct ImplementAttributes {
pub implement: Vec<ImplementType>,
}

impl Parse for ImplementAttributes {
fn parse(cursor: ParseStream) -> Result<Self> {
impl syn::parse::Parse for ImplementAttributes {
fn parse(cursor: syn::parse::ParseStream) -> syn::parse::Result<Self> {
let mut input = Self::default();

while !cursor.is_empty() {
Expand All @@ -249,8 +235,8 @@ impl Parse for ImplementAttributes {
}

impl ImplementAttributes {
fn generics(&self) -> BTreeSet<TokenStream> {
let mut set = BTreeSet::new();
fn generics(&self) -> std::collections::BTreeSet<String> {
let mut set = std::collections::BTreeSet::new();

for def in &self.implement {
set.append(&mut def.generics());
Expand All @@ -259,18 +245,18 @@ impl ImplementAttributes {
set
}

fn parse_implement(&mut self, cursor: ParseStream) -> Result<()> {
fn parse_implement(&mut self, cursor: syn::parse::ParseStream) -> syn::parse::Result<()> {
let tree = cursor.parse::<UseTree2>()?;
self.walk_implement(&tree, &mut String::new())?;

if !cursor.is_empty() {
cursor.parse::<Token![,]>()?;
cursor.parse::<syn::Token![,]>()?;
}

Ok(())
}

fn walk_implement(&mut self, tree: &UseTree2, namespace: &mut String) -> Result<()> {
fn walk_implement(&mut self, tree: &UseTree2, namespace: &mut String) -> syn::parse::Result<()> {
match tree {
UseTree2::Path(input) => {
if !namespace.is_empty() {
Expand Down Expand Up @@ -301,7 +287,7 @@ enum UseTree2 {
}

impl UseTree2 {
fn to_element_type(&self, namespace: &mut String) -> Result<ImplementType> {
fn to_element_type(&self, namespace: &mut String) -> syn::parse::Result<ImplementType> {
match self {
UseTree2::Path(input) => {
if !namespace.is_empty() {
Expand All @@ -326,57 +312,57 @@ impl UseTree2 {

Ok(ImplementType { type_name, generics })
}
UseTree2::Group(input) => Err(Error::new(input.brace_token.span, "Syntax not supported")),
UseTree2::Group(input) => Err(syn::parse::Error::new(input.brace_token.span, "Syntax not supported")),
}
}
}

struct UsePath2 {
pub ident: Ident,
pub ident: syn::Ident,
pub tree: Box<UseTree2>,
}

struct UseName2 {
pub ident: Ident,
pub ident: syn::Ident,
pub generics: Vec<UseTree2>,
}

struct UseGroup2 {
pub brace_token: token::Brace,
pub items: syn::punctuated::Punctuated<UseTree2, Token![,]>,
pub brace_token: syn::token::Brace,
pub items: syn::punctuated::Punctuated<UseTree2, syn::Token![,]>,
}

impl Parse for UseTree2 {
fn parse(input: ParseStream) -> Result<UseTree2> {
impl syn::parse::Parse for UseTree2 {
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<UseTree2> {
let lookahead = input.lookahead1();
if lookahead.peek(Ident) {
if lookahead.peek(syn::Ident) {
use syn::ext::IdentExt;
let ident = input.call(Ident::parse_any)?;
if input.peek(Token![::]) {
input.parse::<Token![::]>()?;
let ident = input.call(syn::Ident::parse_any)?;
if input.peek(syn::Token![::]) {
input.parse::<syn::Token![::]>()?;
Ok(UseTree2::Path(UsePath2 { ident, tree: Box::new(input.parse()?) }))
} else {
let generics = if input.peek(Token![<]) {
input.parse::<Token![<]>()?;
let generics = if input.peek(syn::Token![<]) {
input.parse::<syn::Token![<]>()?;
let mut generics = Vec::new();
loop {
generics.push(input.parse::<UseTree2>()?);

if input.parse::<Token![,]>().is_err() {
if input.parse::<syn::Token![,]>().is_err() {
break;
}
}
input.parse::<Token![>]>()?;
input.parse::<syn::Token![>]>()?;
generics
} else {
Vec::new()
};

Ok(UseTree2::Name(UseName2 { ident, generics }))
}
} else if lookahead.peek(token::Brace) {
} else if lookahead.peek(syn::token::Brace) {
let content;
let brace_token = braced!(content in input);
let brace_token = syn::braced!(content in input);
let items = content.parse_terminated(UseTree2::parse)?;

Ok(UseTree2::Group(UseGroup2 { brace_token, items }))
Expand Down