summaryrefslogtreecommitdiff
path: root/vendor/windows-implement/src
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-15 16:37:08 -0600
committermo khan <mo@mokhan.ca>2025-07-17 16:30:22 -0600
commit45df4d0d9b577fecee798d672695fe24ff57fb1b (patch)
tree1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/windows-implement/src
parentf94f79608393d4ab127db63cc41668445ef6b243 (diff)
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/windows-implement/src')
-rw-r--r--vendor/windows-implement/src/gen.rs587
-rw-r--r--vendor/windows-implement/src/lib.rs383
-rw-r--r--vendor/windows-implement/src/tests.rs135
3 files changed, 0 insertions, 1105 deletions
diff --git a/vendor/windows-implement/src/gen.rs b/vendor/windows-implement/src/gen.rs
deleted file mode 100644
index 56253b99..00000000
--- a/vendor/windows-implement/src/gen.rs
+++ /dev/null
@@ -1,587 +0,0 @@
-//! Generates output for the `implement` proc macro.
-//!
-//! Each function in this module focuses on generating one thing, or one kind of thing.
-//! Each takes `ImplementInputs` as its input. `gen_all` calls all of the `gen_*` functions
-//! and merges them into the final list of output items.
-//!
-//! We use `parse_quote` so that we can verify that a given function generates a well-formed AST
-//! item, within the narrowest possible scope. This allows us to detect errors more quickly during
-//! development. If the input to `parse_quote` cannot be parsed, then the macro will panic and
-//! the panic will point to the specific `parse_quote` call, rather than the entire output of the
-//! `implement` proc macro being unparsable. This greatly aids in development.
-
-use super::*;
-use quote::{quote, quote_spanned};
-use syn::{parse_quote, parse_quote_spanned};
-
-/// Generates code for the `#[implements]` macro.
-pub(crate) fn gen_all(inputs: &ImplementInputs) -> Vec<syn::Item> {
- let mut items: Vec<syn::Item> = Vec::with_capacity(64);
-
- items.push(gen_original_impl(inputs));
- items.push(gen_impl_struct(inputs));
- items.push(gen_impl_deref(inputs));
- items.push(gen_impl_impl(inputs));
- items.push(gen_iunknown_impl(inputs));
- items.push(gen_impl_com_object_inner(inputs));
- items.extend(gen_impl_from(inputs));
- items.extend(gen_impl_com_object_interfaces(inputs));
-
- for (i, interface_chain) in inputs.interface_chains.iter().enumerate() {
- items.push(gen_impl_as_impl(inputs, interface_chain, i));
- }
-
- items
-}
-
-/// Generates an `impl` block for the original `Foo` type.
-///
-/// This `impl` block will contain `into_outer` and `into_static` (if applicable).
-fn gen_original_impl(inputs: &ImplementInputs) -> syn::Item {
- let original_ident = &inputs.original_ident;
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
-
- let mut output: syn::ItemImpl = parse_quote! {
- impl #generics #original_ident::#generics where #constraints {}
- };
-
- output.items.push(gen_into_outer(inputs));
-
- // Static COM objects have a lot of constraints. They can't be generic (open parameters),
- // because that would be meaningless (an open generic type cannot have a known representation).
- //
- // Right now, we can't generate static COM objects that have base classes because we rely on
- // boxing and then unboxing during construction of aggregated types.
- if !inputs.is_generic {
- output.items.push(gen_into_static(inputs));
- }
-
- syn::Item::Impl(output)
-}
-
-/// Generates the structure definition for the `Foo_Impl` type.
-fn gen_impl_struct(inputs: &ImplementInputs) -> syn::Item {
- let impl_ident = &inputs.impl_ident;
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
- let original_ident = &inputs.original_ident;
- let vis = &inputs.original_type.vis;
-
- let mut impl_fields = quote! {
- identity: &'static ::windows_core::IInspectable_Vtbl,
- };
-
- for interface_chain in inputs.interface_chains.iter() {
- let vtbl_ty = interface_chain.implement.to_vtbl_ident();
- let chain_field_ident = &interface_chain.field_ident;
- impl_fields.extend(quote! {
- #chain_field_ident: &'static #vtbl_ty,
- });
- }
-
- impl_fields.extend(quote! {
- this: #original_ident::#generics,
- count: ::windows_core::imp::WeakRefCount,
- });
-
- parse_quote! {
- #[repr(C)]
- #[allow(non_camel_case_types)]
- #vis struct #impl_ident #generics where #constraints {
- #impl_fields
- }
- }
-}
-
-/// Generates the implementation of `core::ops::Deref` for the generated `Foo_Impl` type.
-fn gen_impl_deref(inputs: &ImplementInputs) -> syn::Item {
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
- let original_ident = &inputs.original_type.ident;
- let impl_ident = &inputs.impl_ident;
-
- parse_quote! {
- impl #generics ::core::ops::Deref for #impl_ident::#generics where #constraints {
- type Target = #original_ident::#generics;
-
- #[inline(always)]
- fn deref(&self) -> &Self::Target {
- &self.this
- }
- }
- }
-}
-
-/// Generates an `impl` block for the generated `Foo_Impl` block.
-///
-/// This generates:
-///
-/// ```rust,ignore
-/// const VTABLE_IDENTITY = IInspectable_Vtbl = ...;
-/// const VTABLE_INTERFACE1_IFOO: IFoo_Vtbl = ...;
-/// const VTABLE_INTERFACE2_IBAR: IBar_Vtbl = ...;
-/// ```
-///
-/// These constants are used when constructing vtables. The benefit of using constants instead
-/// of directly generating these expressions is that it allows us to overcome limitations in
-/// using generics in constant contexts. Right now, Rust has a lot of limitations around using
-/// constants in constant contexts. Fortunately, associated constants (constants defined within
-/// `impl` blocks) work in stable Rust, even for generic types.
-fn gen_impl_impl(inputs: &ImplementInputs) -> syn::Item {
- let impl_ident = &inputs.impl_ident;
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
-
- let mut output: syn::ItemImpl = parse_quote! {
- impl #generics #impl_ident::#generics where #constraints {}
- };
-
- // This is here so that IInspectable::GetRuntimeClassName can work properly.
- // For a test case for this, see crates/tests/misc/component_client.
- let identity_type = if let Some(first) = inputs.interface_chains.first() {
- first.implement.to_ident()
- } else {
- quote! { ::windows_core::IInspectable }
- };
-
- output.items.push(parse_quote! {
- const VTABLE_IDENTITY: ::windows_core::IInspectable_Vtbl =
- ::windows_core::IInspectable_Vtbl::new::<
- #impl_ident::#generics,
- #identity_type,
- 0,
- >();
- });
-
- for (interface_index, interface_chain) in inputs.interface_chains.iter().enumerate() {
- let vtbl_ty = interface_chain.implement.to_vtbl_ident();
- let vtable_const_ident = &interface_chain.vtable_const_ident;
-
- let chain_offset_in_pointers: isize = -1 - interface_index as isize;
- output.items.push(parse_quote! {
- const #vtable_const_ident: #vtbl_ty = #vtbl_ty::new::<
- #impl_ident::#generics,
- #chain_offset_in_pointers,
- >();
- });
- }
-
- syn::Item::Impl(output)
-}
-
-/// Generates the `IUnknownImpl` implementation for the `Foo_Impl` type.
-fn gen_iunknown_impl(inputs: &ImplementInputs) -> syn::Item {
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
- let impl_ident = &inputs.impl_ident;
- let original_ident = &inputs.original_type.ident;
-
- let trust_level = proc_macro2::Literal::usize_unsuffixed(inputs.trust_level);
-
- let mut output: syn::ItemImpl = parse_quote! {
- impl #generics ::windows_core::IUnknownImpl for #impl_ident::#generics where #constraints {
- type Impl = #original_ident::#generics;
-
- #[inline(always)]
- fn get_impl(&self) -> &Self::Impl {
- &self.this
- }
-
- #[inline(always)]
- fn get_impl_mut(&mut self) -> &mut Self::Impl {
- &mut self.this
- }
-
- #[inline(always)]
- fn into_inner(self) -> Self::Impl {
- self.this
- }
-
- #[inline(always)]
- fn AddRef(&self) -> u32 {
- self.count.add_ref()
- }
-
- #[inline(always)]
- unsafe fn Release(self_: *mut Self) -> u32 {
- let remaining = (*self_).count.release();
- if remaining == 0 {
- _ = ::windows_core::imp::Box::from_raw(self_);
- }
- remaining
- }
-
- #[inline(always)]
- fn is_reference_count_one(&self) -> bool {
- self.count.is_one()
- }
-
- unsafe fn GetTrustLevel(&self, value: *mut i32) -> ::windows_core::HRESULT {
- if value.is_null() {
- return ::windows_core::imp::E_POINTER;
- }
- *value = #trust_level;
- ::windows_core::HRESULT(0)
- }
-
- fn to_object(&self) -> ::windows_core::ComObject<Self::Impl> {
- self.count.add_ref();
- unsafe {
- ::windows_core::ComObject::from_raw(
- ::core::ptr::NonNull::new_unchecked(self as *const Self as *mut Self)
- )
- }
- }
- }
- };
-
- let query_interface_fn = gen_query_interface(inputs);
- output.items.push(syn::ImplItem::Fn(query_interface_fn));
-
- syn::Item::Impl(output)
-}
-
-/// Generates the implementation of `ComObjectInner`.
-fn gen_impl_com_object_inner(inputs: &ImplementInputs) -> syn::Item {
- let original_ident = &inputs.original_type.ident;
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
- let impl_ident = &inputs.impl_ident;
-
- parse_quote! {
- impl #generics ::windows_core::ComObjectInner for #original_ident::#generics where #constraints {
- type Outer = #impl_ident::#generics;
-
- // IMPORTANT! This function handles assembling the "boxed" type of a COM object.
- // It immediately moves the box into a heap allocation (box) and returns only a ComObject
- // reference that points to it. We intentionally _do not_ expose any owned instances of
- // Foo_Impl to safe Rust code, because doing so would allow unsound behavior in safe Rust
- // code, due to the adjustments of the reference count that Foo_Impl permits.
- //
- // This is why this function returns ComObject<Self> instead of returning #impl_ident.
-
- fn into_object(self) -> ::windows_core::ComObject<Self> {
- let boxed = ::windows_core::imp::Box::<#impl_ident::#generics>::new(self.into_outer());
- unsafe {
- let ptr = ::windows_core::imp::Box::into_raw(boxed);
- ::windows_core::ComObject::from_raw(
- ::core::ptr::NonNull::new_unchecked(ptr)
- )
- }
- }
- }
- }
-}
-
-/// Generates the `query_interface` method.
-fn gen_query_interface(inputs: &ImplementInputs) -> syn::ImplItemFn {
- let queries = inputs.interface_chains.iter().map(|interface_chain| {
- let chain_ty = interface_chain.implement.to_vtbl_ident();
- let chain_field = &interface_chain.field_ident;
- quote_spanned! {
- interface_chain.implement.span =>
- if #chain_ty::matches(&iid) {
- break 'found &self.#chain_field as *const _ as *const ::core::ffi::c_void;
- }
- }
- });
-
- // Dynamic casting requires that the object not contain non-static lifetimes.
- let enable_dyn_casting = inputs.original_type.generics.lifetimes().count() == 0;
- let dynamic_cast_query = if enable_dyn_casting {
- quote! {
- if iid == ::windows_core::DYNAMIC_CAST_IID {
- // DYNAMIC_CAST_IID is special. We _do not_ increase the reference count for this pseudo-interface.
- // Also, instead of returning an interface pointer, we simply write the `&dyn Any` directly to the
- // 'interface' pointer. Since the size of `&dyn Any` is 2 pointers, not one, the caller must be
- // prepared for this. This is not a normal QueryInterface call.
- //
- // See the `Interface::cast_to_any` method, which is the only caller that should use DYNAMIC_CAST_ID.
- (interface as *mut *const dyn core::any::Any).write(self as &dyn ::core::any::Any as *const dyn ::core::any::Any);
- return ::windows_core::HRESULT(0);
- }
- }
- } else {
- quote!()
- };
-
- let identity_query = quote! {
- if iid == <::windows_core::IUnknown as ::windows_core::Interface>::IID
- || iid == <::windows_core::IInspectable as ::windows_core::Interface>::IID
- || iid == <::windows_core::imp::IAgileObject as ::windows_core::Interface>::IID {
- break 'found &self.identity as *const _ as *const ::core::ffi::c_void;
- }
- };
-
- let marshal_query = quote! {
- #[cfg(windows)]
- if iid == <::windows_core::imp::IMarshal as ::windows_core::Interface>::IID {
- return ::windows_core::imp::marshaler(self.to_interface(), interface);
- }
- };
-
- let tear_off_query = quote! {
- let tear_off_ptr = self.count.query(&iid, &self.identity as *const _ as *mut _);
- if !tear_off_ptr.is_null() {
- *interface = tear_off_ptr;
- return ::windows_core::HRESULT(0);
- }
- };
-
- parse_quote! {
- unsafe fn QueryInterface(
- &self,
- iid: *const ::windows_core::GUID,
- interface: *mut *mut ::core::ffi::c_void,
- ) -> ::windows_core::HRESULT {
- unsafe {
- if iid.is_null() || interface.is_null() {
- return ::windows_core::imp::E_POINTER;
- }
-
- let iid = *iid;
-
- let interface_ptr: *const ::core::ffi::c_void = 'found: {
- #identity_query
- #(#queries)*
- #marshal_query
- #dynamic_cast_query
- #tear_off_query
-
- *interface = ::core::ptr::null_mut();
- return ::windows_core::imp::E_NOINTERFACE;
- };
-
- debug_assert!(!interface_ptr.is_null());
- *interface = interface_ptr as *mut ::core::ffi::c_void;
- self.count.add_ref();
- return ::windows_core::HRESULT(0);
- }
- }
- }
-}
-
-/// Generates the `T::into_outer` function. This function is part of how we construct a
-/// `ComObject<T>` from a `T`.
-fn gen_into_outer(inputs: &ImplementInputs) -> syn::ImplItem {
- let generics = &inputs.generics;
- let impl_ident = &inputs.impl_ident;
-
- let mut initializers = quote! {
- identity: &#impl_ident::#generics::VTABLE_IDENTITY,
- };
-
- for interface_chain in inputs.interface_chains.iter() {
- let vtbl_field_ident = &interface_chain.field_ident;
- let vtable_const_ident = &interface_chain.vtable_const_ident;
-
- initializers.extend(quote_spanned! {
- interface_chain.implement.span =>
- #vtbl_field_ident: &#impl_ident::#generics::#vtable_const_ident,
- });
- }
-
- // If the type is generic then into_outer() cannot be a const fn.
- let maybe_const = if inputs.is_generic {
- quote!()
- } else {
- quote!(const)
- };
-
- parse_quote! {
- // This constructs an "outer" object. This should only be used by the implementation
- // of the outer object, never by application code.
- //
- // The callers of this function (`into_static` and `into_object`) are both responsible
- // for maintaining one of our invariants: Application code never has an owned instance
- // of the outer (implementation) type. into_static() maintains this invariant by
- // returning a wrapped StaticComObject value, which owns its contents but never gives
- // application code a way to mutably access its contents. This prevents the refcount
- // shearing problem.
- //
- // TODO: Make it impossible for app code to call this function, by placing it in a
- // module and marking this as private to the module.
- #[inline(always)]
- #maybe_const fn into_outer(self) -> #impl_ident::#generics {
- #impl_ident::#generics {
- #initializers
- count: ::windows_core::imp::WeakRefCount::new(),
- this: self,
- }
- }
- }
-}
-
-/// Generates the `T::into_static` function. This function is part of how we construct a
-/// `StaticComObject<T>` from a `T`.
-fn gen_into_static(inputs: &ImplementInputs) -> syn::ImplItem {
- assert!(!inputs.is_generic);
- parse_quote! {
- /// This converts a partially-constructed COM object (in the sense that it contains
- /// application state but does not yet have vtable and reference count constructed)
- /// into a `StaticComObject`. This allows the COM object to be stored in static
- /// (global) variables.
- pub const fn into_static(self) -> ::windows_core::StaticComObject<Self> {
- ::windows_core::StaticComObject::from_outer(self.into_outer())
- }
- }
-}
-
-/// Generates `From`-based conversions.
-///
-/// These conversions convert from the user's type `T` to `ComObject<T>` or to an interface
-/// implemented by `T`. These conversions are shorthand for calling `ComObject::new(value)`.
-///
-/// We can only generate conversions from `T` to the roots of each interface chain. We can't
-/// generate `From` conversions from `T` to an interface that is inherited by an interface chain,
-/// because this proc macro does not have access to any information about the inheritance chain
-/// of interfaces that are referenced.
-///
-/// For example:
-///
-/// ```rust,ignore
-/// #[implement(IFoo3)]
-/// struct MyType;
-/// ```
-///
-/// If `IFoo3` inherits from `IFoo2`, then this code will _not_ generate a conversion for `IFoo2`.
-/// However, user code can still do this:
-///
-/// ```rust,ignore
-/// let ifoo2 = IFoo3::from(MyType).into();
-/// ```
-///
-/// This works because the `IFoo3` type has an `Into` impl for `IFoo2`.
-fn gen_impl_from(inputs: &ImplementInputs) -> Vec<syn::Item> {
- let mut items = Vec::new();
-
- let original_ident = &inputs.original_type.ident;
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
-
- items.push(parse_quote! {
- impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IUnknown where #constraints {
- #[inline(always)]
- fn from(this: #original_ident::#generics) -> Self {
- let com_object = ::windows_core::ComObject::new(this);
- com_object.into_interface()
- }
- }
- });
-
- items.push(parse_quote! {
- impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IInspectable where #constraints {
- #[inline(always)]
- fn from(this: #original_ident::#generics) -> Self {
- let com_object = ::windows_core::ComObject::new(this);
- com_object.into_interface()
- }
- }
- });
-
- for interface_chain in inputs.interface_chains.iter() {
- let interface_ident = interface_chain.implement.to_ident();
-
- items.push(parse_quote_spanned! {
- interface_chain.implement.span =>
- impl #generics ::core::convert::From<#original_ident::#generics> for #interface_ident where #constraints {
- #[inline(always)]
- fn from(this: #original_ident::#generics) -> Self {
- let com_object = ::windows_core::ComObject::new(this);
- com_object.into_interface()
- }
- }
- });
- }
-
- items
-}
-
-/// Generates the `ComObjectInterface` implementation for each interface chain.
-///
-/// Each of these `impl` blocks says "this COM object implements this COM interface".
-/// It allows the `ComObject` type to do conversions from the `ComObject` to `IFoo` instances,
-/// _without_ doing a `QueryInterface` call.
-fn gen_impl_com_object_interfaces(inputs: &ImplementInputs) -> Vec<syn::Item> {
- let mut items = Vec::new();
-
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
- let impl_ident = &inputs.impl_ident;
-
- items.push(parse_quote! {
- impl #generics ::windows_core::ComObjectInterface<::windows_core::IUnknown> for #impl_ident::#generics where #constraints {
- #[inline(always)]
- fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IUnknown> {
- unsafe {
- let interface_ptr = &self.identity;
- ::core::mem::transmute(interface_ptr)
- }
- }
- }
- });
-
- items.push(parse_quote! {
- impl #generics ::windows_core::ComObjectInterface<::windows_core::IInspectable> for #impl_ident::#generics where #constraints {
- #[inline(always)]
- fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IInspectable> {
- unsafe {
- let interface_ptr = &self.identity;
- ::core::mem::transmute(interface_ptr)
- }
- }
- }
- });
-
- for interface_chain in inputs.interface_chains.iter() {
- let chain_field = &interface_chain.field_ident;
- let interface_ident = interface_chain.implement.to_ident();
-
- items.push(parse_quote_spanned! {
- interface_chain.implement.span =>
- #[allow(clippy::needless_lifetimes)]
- impl #generics ::windows_core::ComObjectInterface<#interface_ident> for #impl_ident::#generics where #constraints {
- #[inline(always)]
- fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, #interface_ident> {
- unsafe {
- ::core::mem::transmute(&self.#chain_field)
- }
- }
- }
- });
- }
-
- items
-}
-
-/// Generates the implementation of the `AsImpl` trait for a given interface chain.
-fn gen_impl_as_impl(
- inputs: &ImplementInputs,
- interface_chain: &InterfaceChain,
- interface_chain_index: usize,
-) -> syn::Item {
- let generics = &inputs.generics;
- let constraints = &inputs.constraints;
- let interface_ident = interface_chain.implement.to_ident();
- let original_ident = &inputs.original_type.ident;
- let impl_ident = &inputs.impl_ident;
-
- parse_quote_spanned! {
- interface_chain.implement.span =>
- impl #generics ::windows_core::AsImpl<#original_ident::#generics> for #interface_ident where #constraints {
- // SAFETY: the offset is guaranteed to be in bounds, and the implementation struct
- // is guaranteed to live at least as long as `self`.
- #[inline(always)]
- unsafe fn as_impl_ptr(&self) -> ::core::ptr::NonNull<#original_ident::#generics> {
- unsafe {
- let this = ::windows_core::Interface::as_raw(self);
- // Subtract away the vtable offset plus 1, for the `identity` field, to get
- // to the impl struct which contains that original implementation type.
- let this = (this as *mut *mut ::core::ffi::c_void).sub(1 + #interface_chain_index) as *mut #impl_ident::#generics;
- ::core::ptr::NonNull::new_unchecked(::core::ptr::addr_of!((*this).this) as *const #original_ident::#generics as *mut #original_ident::#generics)
- }
- }
- }
- }
-}
diff --git a/vendor/windows-implement/src/lib.rs b/vendor/windows-implement/src/lib.rs
deleted file mode 100644
index c50509af..00000000
--- a/vendor/windows-implement/src/lib.rs
+++ /dev/null
@@ -1,383 +0,0 @@
-//! Implement COM interfaces for Rust types.
-//!
-//! Take a look at [macro@implement] for an example.
-//!
-//! Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
-
-use quote::{quote, ToTokens};
-
-mod r#gen;
-use r#gen::gen_all;
-
-#[cfg(test)]
-mod tests;
-
-/// Implements one or more COM interfaces.
-///
-/// # Example
-/// ```rust,no_run
-/// use windows_core::*;
-///
-/// #[interface("094d70d6-5202-44b8-abb8-43860da5aca2")]
-/// unsafe trait IValue: IUnknown {
-/// fn GetValue(&self, value: *mut i32) -> HRESULT;
-/// }
-///
-/// #[implement(IValue)]
-/// struct Value(i32);
-///
-/// impl IValue_Impl for Value_Impl {
-/// unsafe fn GetValue(&self, value: *mut i32) -> HRESULT {
-/// *value = self.0;
-/// HRESULT(0)
-/// }
-/// }
-///
-/// let object: IValue = Value(123).into();
-/// // Call interface methods...
-/// ```
-#[proc_macro_attribute]
-pub fn implement(
- attributes: proc_macro::TokenStream,
- type_tokens: proc_macro::TokenStream,
-) -> proc_macro::TokenStream {
- implement_core(attributes.into(), type_tokens.into()).into()
-}
-
-fn implement_core(
- attributes: proc_macro2::TokenStream,
- item_tokens: proc_macro2::TokenStream,
-) -> proc_macro2::TokenStream {
- let attributes = syn::parse2::<ImplementAttributes>(attributes).unwrap();
- let original_type = syn::parse2::<syn::ItemStruct>(item_tokens).unwrap();
-
- // Do a little thinking and assemble ImplementInputs. We pass ImplementInputs to
- // all of our gen_* function.
- let inputs = ImplementInputs {
- original_ident: original_type.ident.clone(),
- interface_chains: convert_implements_to_interface_chains(attributes.implement),
- trust_level: attributes.trust_level,
- impl_ident: quote::format_ident!("{}_Impl", &original_type.ident),
- constraints: {
- if let Some(where_clause) = &original_type.generics.where_clause {
- where_clause.predicates.to_token_stream()
- } else {
- quote!()
- }
- },
- generics: if !original_type.generics.params.is_empty() {
- let mut params = quote! {};
- original_type.generics.params.to_tokens(&mut params);
- quote! { <#params> }
- } else {
- quote! { <> }
- },
- is_generic: !original_type.generics.params.is_empty(),
- original_type,
- };
-
- let items = gen_all(&inputs);
- let mut tokens = inputs.original_type.into_token_stream();
- for item in items {
- tokens.extend(item.into_token_stream());
- }
-
- tokens
-}
-
-/// This provides the inputs to the `gen_*` functions, which generate the proc macro output.
-struct ImplementInputs {
- /// The user's type that was marked with `#[implement]`.
- original_type: syn::ItemStruct,
-
- /// The identifier for the user's original type definition.
- original_ident: syn::Ident,
-
- /// The list of interface chains that this type implements.
- interface_chains: Vec<InterfaceChain>,
-
- /// The "trust level", which is returned by `IInspectable::GetTrustLevel`.
- trust_level: usize,
-
- /// The identifier of the `Foo_Impl` type.
- impl_ident: syn::Ident,
-
- /// The list of constraints needed for this `Foo_Impl` type.
- constraints: proc_macro2::TokenStream,
-
- /// The list of generic parameters for this `Foo_Impl` type, including `<` and `>`.
- /// If there are no generics, this contains `<>`.
- generics: proc_macro2::TokenStream,
-
- /// True if the user type has any generic parameters.
- is_generic: bool,
-}
-
-/// Describes one COM interface chain.
-struct InterfaceChain {
- /// The name of the field for the vtable chain, e.g. `interface4_ifoo`.
- field_ident: syn::Ident,
-
- /// The name of the associated constant item for the vtable chain's initializer,
- /// e.g. `INTERFACE4_IFOO_VTABLE`.
- vtable_const_ident: syn::Ident,
-
- implement: ImplementType,
-}
-
-struct ImplementType {
- type_name: String,
- generics: Vec<ImplementType>,
-
- /// The best span for diagnostics.
- span: proc_macro2::Span,
-}
-
-impl ImplementType {
- 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) -> proc_macro2::TokenStream {
- let ident = self.to_ident();
- quote! {
- <#ident as ::windows_core::Interface>::Vtable
- }
- }
-}
-
-#[derive(Default)]
-struct ImplementAttributes {
- pub implement: Vec<ImplementType>,
- pub trust_level: usize,
-}
-
-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() {
- input.parse_implement(cursor)?;
- }
-
- Ok(input)
- }
-}
-
-impl ImplementAttributes {
- 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::<syn::Token![,]>()?;
- }
-
- Ok(())
- }
-
- fn walk_implement(
- &mut self,
- tree: &UseTree2,
- namespace: &mut String,
- ) -> syn::parse::Result<()> {
- match tree {
- UseTree2::Path(input) => {
- if !namespace.is_empty() {
- namespace.push_str("::");
- }
-
- namespace.push_str(&input.ident.to_string());
- self.walk_implement(&input.tree, namespace)?;
- }
- UseTree2::Name(_) => {
- self.implement.push(tree.to_element_type(namespace)?);
- }
- UseTree2::Group(input) => {
- for tree in &input.items {
- self.walk_implement(tree, namespace)?;
- }
- }
- UseTree2::TrustLevel(input) => self.trust_level = *input,
- }
-
- Ok(())
- }
-}
-
-enum UseTree2 {
- Path(UsePath2),
- Name(UseName2),
- Group(UseGroup2),
- TrustLevel(usize),
-}
-
-impl UseTree2 {
- fn to_element_type(&self, namespace: &mut String) -> syn::parse::Result<ImplementType> {
- match self {
- UseTree2::Path(input) => {
- if !namespace.is_empty() {
- namespace.push_str("::");
- }
-
- namespace.push_str(&input.ident.to_string());
- input.tree.to_element_type(namespace)
- }
- UseTree2::Name(input) => {
- let mut type_name = input.ident.to_string();
- let span = input.ident.span();
-
- if !namespace.is_empty() {
- type_name = format!("{namespace}::{type_name}");
- }
-
- let mut generics = vec![];
-
- for g in &input.generics {
- generics.push(g.to_element_type(&mut String::new())?);
- }
-
- Ok(ImplementType {
- type_name,
- generics,
- span,
- })
- }
- UseTree2::Group(input) => Err(syn::parse::Error::new(
- input.brace_token.span.join(),
- "Syntax not supported",
- )),
- _ => unimplemented!(),
- }
- }
-}
-
-struct UsePath2 {
- pub ident: syn::Ident,
- pub tree: Box<UseTree2>,
-}
-
-struct UseName2 {
- pub ident: syn::Ident,
- pub generics: Vec<UseTree2>,
-}
-
-struct UseGroup2 {
- pub brace_token: syn::token::Brace,
- pub items: syn::punctuated::Punctuated<UseTree2, syn::Token![,]>,
-}
-
-impl syn::parse::Parse for UseTree2 {
- fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result<UseTree2> {
- let lookahead = input.lookahead1();
- if lookahead.peek(syn::Ident) {
- use syn::ext::IdentExt;
- 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 if input.peek(syn::Token![=]) {
- if ident != "TrustLevel" {
- return Err(syn::parse::Error::new(
- ident.span(),
- "Unrecognized key-value pair",
- ));
- }
- input.parse::<syn::Token![=]>()?;
- let span = input.span();
- let value = input.call(syn::Ident::parse_any)?;
- match value.to_string().as_str() {
- "Partial" => Ok(UseTree2::TrustLevel(1)),
- "Full" => Ok(UseTree2::TrustLevel(2)),
- _ => Err(syn::parse::Error::new(
- span,
- "`TrustLevel` must be `Partial` or `Full`",
- )),
- }
- } else {
- 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::<syn::Token![,]>().is_err() {
- break;
- }
- }
- input.parse::<syn::Token![>]>()?;
- generics
- } else {
- Vec::new()
- };
-
- Ok(UseTree2::Name(UseName2 { ident, generics }))
- }
- } else if lookahead.peek(syn::token::Brace) {
- let content;
- let brace_token = syn::braced!(content in input);
- let items = content.parse_terminated(UseTree2::parse, syn::Token![,])?;
-
- Ok(UseTree2::Group(UseGroup2 { brace_token, items }))
- } else {
- Err(lookahead.error())
- }
- }
-}
-
-fn convert_implements_to_interface_chains(implements: Vec<ImplementType>) -> Vec<InterfaceChain> {
- let mut chains = Vec::with_capacity(implements.len());
-
- for (i, implement) in implements.into_iter().enumerate() {
- // Create an identifier for this interface chain.
- // We only use this for naming fields; it is never visible to the developer.
- // This helps with debugging.
- //
- // We use i + 1 so that it matches the numbering of our interface offsets. Interface 0
- // is the "identity" interface.
-
- let mut ident_string = format!("interface{}", i + 1);
-
- let suffix = get_interface_ident_suffix(&implement.type_name);
- if !suffix.is_empty() {
- ident_string.push('_');
- ident_string.push_str(&suffix);
- }
- let field_ident = syn::Ident::new(&ident_string, implement.span);
-
- let mut vtable_const_string = ident_string.clone();
- vtable_const_string.make_ascii_uppercase();
- vtable_const_string.insert_str(0, "VTABLE_");
- let vtable_const_ident = syn::Ident::new(&vtable_const_string, implement.span);
-
- chains.push(InterfaceChain {
- implement,
- field_ident,
- vtable_const_ident,
- });
- }
-
- chains
-}
-
-fn get_interface_ident_suffix(type_name: &str) -> String {
- let mut suffix = String::new();
- for c in type_name.chars() {
- let c = c.to_ascii_lowercase();
-
- if suffix.len() >= 20 {
- break;
- }
-
- if c.is_ascii_alphanumeric() {
- suffix.push(c);
- }
- }
-
- suffix
-}
diff --git a/vendor/windows-implement/src/tests.rs b/vendor/windows-implement/src/tests.rs
deleted file mode 100644
index 3f5c3493..00000000
--- a/vendor/windows-implement/src/tests.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-//! These tests are just a way to quickly run the `#[implement]` macro and see its output.
-//! They don't check the output in any way.
-//!
-//! This exists because of some difficulties of running `cargo expand` against the `#[implement]`
-//! macro. It's also just really convenient. You can see the output by using `--nocapture` and
-//! you'll probably want to restrict the output to a single thread:
-//!
-//! ```text
-//! cargo test -p windows-implement --lib -- --nocapture --test-threads=1
-//! ```
-
-use std::io::{Read, Write};
-use std::process::{Command, Stdio};
-
-use proc_macro2::TokenStream;
-use quote::quote;
-
-fn implement(attributes: TokenStream, item_tokens: TokenStream) -> String {
- let out_tokens = crate::implement_core(attributes, item_tokens);
- let tokens_string = out_tokens.to_string();
-
- let out_string = rustfmt(&tokens_string);
- println!("// output of #[implement] :");
- println!();
- println!("{}", out_string);
- out_string
-}
-
-fn rustfmt(input: &str) -> String {
- let mut rustfmt = Command::new("rustfmt");
-
- rustfmt.stdin(Stdio::piped());
- rustfmt.stdout(Stdio::piped());
- rustfmt.stderr(Stdio::inherit());
-
- let mut child = match rustfmt.spawn() {
- Ok(c) => c,
- Err(e) => {
- eprintln!("failed to spawn rustfmt: {e:?}");
- return input.to_string();
- }
- };
-
- let mut stdout = child.stdout.take().unwrap();
-
- // spawn thread to read stdout
- let stdout_thread = std::thread::spawn(move || {
- let mut buf = String::new();
- stdout.read_to_string(&mut buf).unwrap();
- buf
- });
-
- // write unformatted into stdin
- let mut stdin = child.stdin.take().unwrap();
- stdin.write_all(input.as_bytes()).unwrap();
- drop(stdin);
-
- let stdout_string: String = stdout_thread.join().unwrap();
-
- let exit = child.wait().unwrap();
- if !exit.success() {
- eprintln!("rustfmt terminated with failure status code");
- return input.to_string();
- }
-
- stdout_string
-}
-
-#[test]
-fn simple_type() {
- implement(
- quote!(IFoo),
- quote! {
- struct Foo {
- x: u32,
- }
- },
- );
-}
-
-#[test]
-fn zero_sized_type() {
- implement(
- quote!(IFoo),
- quote! {
- struct Foo;
- },
- );
-}
-
-#[test]
-fn no_interfaces() {
- implement(
- quote!(),
- quote! {
- struct Foo {}
- },
- );
-}
-
-#[test]
-fn generic_no_lifetime() {
- implement(
- quote!(IAsyncOperationWithProgress<T, P>, IAsyncInfo),
- quote! {
- struct OperationWithProgress<T, P>(SyncState<IAsyncOperationWithProgress<T, P>>)
- where
- T: RuntimeType + 'static,
- P: RuntimeType + 'static;
-
- },
- );
-}
-
-#[test]
-fn generic_with_lifetime() {
- implement(
- quote!(),
- quote! {
- pub struct Foo<'a> {
- pub x: &'a [u8],
- }
- },
- );
-}
-
-#[test]
-fn tuple_type() {
- implement(
- quote!(IFoo),
- quote! {
- struct Foo(pub i32);
- },
- );
-}