summaryrefslogtreecommitdiff
path: root/vendor/windows-interface/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-interface/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-interface/src')
-rw-r--r--vendor/windows-interface/src/lib.rs762
1 files changed, 0 insertions, 762 deletions
diff --git a/vendor/windows-interface/src/lib.rs b/vendor/windows-interface/src/lib.rs
deleted file mode 100644
index 73c8f40c..00000000
--- a/vendor/windows-interface/src/lib.rs
+++ /dev/null
@@ -1,762 +0,0 @@
-//! Define COM interfaces to call or implement.
-//!
-//! Take a look at [macro@interface] for an example.
-//!
-//! Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
-
-use quote::quote;
-use syn::spanned::Spanned;
-
-/// Defines a COM interface to call or implement.
-///
-/// # 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 interface(
- attributes: proc_macro::TokenStream,
- original_type: proc_macro::TokenStream,
-) -> proc_macro::TokenStream {
- let guid = syn::parse_macro_input!(attributes as Guid);
- let interface = syn::parse_macro_input!(original_type as Interface);
- let tokens = match interface.gen_tokens(&guid) {
- Ok(t) => t,
- Err(e) => return e.to_compile_error().into(),
- };
- tokens.into()
-}
-
-macro_rules! bail {
- ($item:expr, $($msg:tt),*) => {
- return Err(syn::Error::new($item.span(), std::fmt::format(format_args!($($msg),*))));
- };
-
-}
-
-macro_rules! unexpected_token {
- ($item:expr, $msg:expr) => {
- if let Some(i) = $item {
- bail!(i, "unexpected {}", $msg);
- }
- };
-}
-macro_rules! expected_token {
- ($sig:tt.$item:tt(), $msg:expr) => {
- if let None = $sig.$item() {
- bail!($sig, "expected {}", $msg);
- }
- };
-}
-
-/// Parsed interface
-///
-/// ```rust,ignore
-/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
-/// unsafe trait IUIAnimationVariable: IUnknown {
-/// //^ parses this
-/// fn GetValue(&self, value: *mut f64) -> HRESULT;
-/// }
-/// ```
-struct Interface {
- visibility: syn::Visibility,
- name: syn::Ident,
- parent: Option<syn::Path>,
- methods: Vec<InterfaceMethod>,
- docs: Vec<syn::Attribute>,
-}
-
-impl Interface {
- /// Generates all the code needed for a COM interface
- fn gen_tokens(&self, guid: &Guid) -> syn::Result<proc_macro2::TokenStream> {
- let vis = &self.visibility;
- let name = &self.name;
- let docs = &self.docs;
- let parent = self.parent_type();
- let vtable_name = quote::format_ident!("{}_Vtbl", name);
- let guid = guid.to_tokens()?;
- let implementation = self.gen_implementation();
- let com_trait = self.get_com_trait();
- let vtable = self.gen_vtable(&vtable_name);
- let conversions = self.gen_conversions();
-
- Ok(quote! {
- #[repr(transparent)]
- #(#docs)*
- #vis struct #name(#parent);
- #implementation
- unsafe impl ::windows_core::Interface for #name {
- type Vtable = #vtable_name;
- const IID: ::windows_core::GUID = #guid;
- }
- impl ::windows_core::RuntimeName for #name {}
- impl ::core::ops::Deref for #name {
- type Target = #parent;
- fn deref(&self) -> &Self::Target {
- unsafe { ::core::mem::transmute(self) }
- }
- }
- #com_trait
- #vtable
- #conversions
- })
- }
-
- /// Generates the methods users can call on the COM interface pointer
- fn gen_implementation(&self) -> proc_macro2::TokenStream {
- let name = &self.name;
- let methods = self
- .methods
- .iter()
- .map(|m| {
- let vis = &m.visibility;
- let name = &m.name;
-
- let generics = m.gen_consume_generics();
- let params = m.gen_consume_params();
- let args = m.gen_consume_args();
- let ret = &m.ret;
-
- if m.is_result() {
- quote! {
- #[inline(always)]
- #vis unsafe fn #name<#(#generics),*>(&self, #(#params),*) #ret {
- (::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#args),*).ok()
- }
- }
- } else {
- quote! {
- #[inline(always)]
- #vis unsafe fn #name<#(#generics),*>(&self, #(#params),*) #ret {
- (::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#args),*)
- }
- }
- }
- })
- .collect::<Vec<_>>();
- quote! {
- impl #name {
- #(#methods)*
- }
- }
- }
-
- fn get_com_trait(&self) -> proc_macro2::TokenStream {
- let name = quote::format_ident!("{}_Impl", self.name);
- let vis = &self.visibility;
- let methods = self
- .methods
- .iter()
- .map(|m| {
- let name = &m.name;
- let docs = &m.docs;
- let args = m.gen_args();
- let ret = &m.ret;
- quote! {
- #(#docs)*
- unsafe fn #name(&self, #(#args),*) #ret;
- }
- })
- .collect::<Vec<_>>();
- let parent = self.parent_trait_constraint();
-
- quote! {
- #[allow(non_camel_case_types)]
- #vis trait #name: Sized + #parent {
- #(#methods)*
- }
- }
- }
-
- /// Generates the vtable for a COM interface
- fn gen_vtable(&self, vtable_name: &syn::Ident) -> proc_macro2::TokenStream {
- let vis = &self.visibility;
- let name = &self.name;
- let trait_name = quote::format_ident!("{}_Impl", name);
- let implvtbl_name = quote::format_ident!("{}_ImplVtbl", name);
-
- let vtable_entries = self
- .methods
- .iter()
- .map(|m| {
- let name = &m.name;
- let ret = &m.ret;
- let args = m.gen_args();
-
- if m.is_result() {
- quote! {
- pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) -> ::windows_core::HRESULT,
- }
- } else {
- quote! {
- pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) #ret,
- }
- }
- })
- .collect::<Vec<_>>();
-
- let parent_vtable_generics = quote!(Identity, OFFSET);
- let parent_vtable = self.parent_vtable();
-
- // or_parent_matches will be `|| parent::matches(iid)` if this interface inherits from another
- // interface (except for IUnknown) or will be empty if this is not applicable. This is what allows
- // QueryInterface to work correctly for all interfaces in an inheritance chain, e.g.
- // IFoo3 derives from IFoo2 derives from IFoo.
- //
- // We avoid matching IUnknown because object identity depends on the uniqueness of the IUnknown pointer.
- let or_parent_matches = match parent_vtable.as_ref() {
- Some(parent) if !self.parent_is_iunknown() => quote! (|| <#parent>::matches(iid)),
- _ => quote!(),
- };
-
- let functions = self
- .methods
- .iter()
- .map(|m| {
- let name = &m.name;
- let args = m.gen_args();
- let params = &m
- .args
- .iter()
- .map(|a| {
- let pat = &a.pat;
- quote! { #pat }
- })
- .collect::<Vec<_>>();
- let ret = &m.ret;
-
- let ret = if m.is_result() {
- quote! { -> ::windows_core::HRESULT }
- } else {
- quote! { #ret }
- };
-
- if parent_vtable.is_some() {
- quote! {
- unsafe extern "system" fn #name<
- Identity: ::windows_core::IUnknownImpl,
- const OFFSET: isize
- >(
- this: *mut ::core::ffi::c_void, // <-- This is the COM "this" pointer, which is not the same as &T or &T_Impl.
- #(#args),*
- ) #ret
- where
- Identity : #trait_name
- {
- // This step is essentially a virtual dispatch adjustor thunk. Its purpose is to adjust
- // the "this" pointer from the address used by the COM interface to the root of the
- // MyApp_Impl object. Since a given MyApp_Impl may implement more than one COM interface
- // (and more than one COM interface chain), we need to know how to get from COM's "this"
- // back to &MyApp_Impl. The OFFSET constant gives us the value (in pointer-sized units).
- let this_outer: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity);
-
- // Last, we invoke the implementation function.
- // We use explicit <Impl as IFoo_Impl> so that we can select the correct method
- // for situations where IFoo3 derives from IFoo2 and both declare a method with
- // the same name.
- <Identity as #trait_name>::#name(this_outer, #(#params),*).into()
- }
- }
- } else {
- quote! {
- unsafe extern "system" fn #name<Impl: #trait_name>(this: *mut ::core::ffi::c_void, #(#args),*) #ret {
- let this = (this as *mut *mut ::core::ffi::c_void) as *const ::windows_core::ScopedHeap;
- let this = (*this).this as *const Impl;
- (*this).#name(#(#params),*).into()
- }
- }
- }
- })
- .collect::<Vec<_>>();
-
- if let Some(parent_vtable) = parent_vtable {
- let entries = self
- .methods
- .iter()
- .map(|m| {
- let name = &m.name;
- quote!(#name: #name::<Identity, OFFSET>)
- })
- .collect::<Vec<_>>();
-
- quote! {
- #[repr(C)]
- #[doc(hidden)]
- #vis struct #vtable_name {
- pub base__: #parent_vtable,
- #(#vtable_entries)*
- }
- impl #vtable_name {
- pub const fn new<
- Identity: ::windows_core::IUnknownImpl,
- const OFFSET: isize,
- >() -> Self
- where
- Identity : #trait_name
- {
- #(#functions)*
- Self { base__: #parent_vtable::new::<#parent_vtable_generics>(), #(#entries),* }
- }
-
- #[inline(always)]
- pub fn matches(iid: &::windows_core::GUID) -> bool {
- *iid == <#name as ::windows_core::Interface>::IID
- #or_parent_matches
- }
- }
- }
- } else {
- let entries = self
- .methods
- .iter()
- .map(|m| {
- let name = &m.name;
- quote!(#name: #name::<Impl>)
- })
- .collect::<Vec<_>>();
-
- quote! {
- #[repr(C)]
- #[doc(hidden)]
- #vis struct #vtable_name {
- #(#vtable_entries)*
- }
- impl #vtable_name {
- pub const fn new<Impl: #trait_name>() -> Self {
- #(#functions)*
- Self { #(#entries),* }
- }
- }
- struct #implvtbl_name<T: #trait_name> (::core::marker::PhantomData<T>);
- impl<T: #trait_name> #implvtbl_name<T> {
- const VTABLE: #vtable_name = #vtable_name::new::<T>();
- }
- impl #name {
- fn new<'a, T: #trait_name>(this: &'a T) -> ::windows_core::ScopedInterface<'a, #name> {
- let this = ::windows_core::ScopedHeap { vtable: &#implvtbl_name::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ };
- let this = ::core::mem::ManuallyDrop::new(::windows_core::imp::Box::new(this));
- unsafe { ::windows_core::ScopedInterface::new(::core::mem::transmute(&this.vtable)) }
- }
- }
- }
- }
- }
-
- /// Generates various conversions such as from and to `IUnknown`
- fn gen_conversions(&self) -> proc_macro2::TokenStream {
- let name = &self.name;
- let name_string = format!("{name}");
- quote! {
- impl ::core::convert::From<#name> for ::windows_core::IUnknown {
- fn from(value: #name) -> Self {
- unsafe { ::core::mem::transmute(value) }
- }
- }
- impl ::core::convert::From<&#name> for ::windows_core::IUnknown {
- fn from(value: &#name) -> Self {
- ::core::convert::From::from(::core::clone::Clone::clone(value))
- }
- }
- impl ::core::clone::Clone for #name {
- fn clone(&self) -> Self {
- Self(self.0.clone())
- }
- }
- impl ::core::cmp::PartialEq for #name {
- fn eq(&self, other: &Self) -> bool {
- self.0 == other.0
- }
- }
- impl ::core::cmp::Eq for #name {}
- impl ::core::fmt::Debug for #name {
- fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
- f.debug_tuple(#name_string).field(&::windows_core::Interface::as_raw(self)).finish()
- }
- }
- }
- }
-
- fn parent_type(&self) -> proc_macro2::TokenStream {
- if let Some(parent) = &self.parent {
- quote!(#parent)
- } else {
- quote!(::core::ptr::NonNull<::core::ffi::c_void>)
- }
- }
-
- fn parent_vtable(&self) -> Option<proc_macro2::TokenStream> {
- if let Some((ident, path)) = self.parent_path().split_last() {
- let ident = quote::format_ident!("{}_Vtbl", ident);
- Some(quote! { #(#path::)* #ident })
- } else {
- None
- }
- }
-
- fn parent_is_iunknown(&self) -> bool {
- if let Some(ident) = self.parent_path().last() {
- ident == "IUnknown"
- } else {
- false
- }
- }
-
- fn parent_path(&self) -> Vec<syn::Ident> {
- if let Some(parent) = &self.parent {
- parent
- .segments
- .iter()
- .map(|segment| segment.ident.clone())
- .collect()
- } else {
- vec![]
- }
- }
-
- /// Gets the parent trait constraint which is nothing if the parent is IUnknown
- fn parent_trait_constraint(&self) -> proc_macro2::TokenStream {
- if let Some((ident, path)) = self.parent_path().split_last() {
- if ident != "IUnknown" {
- let ident = quote::format_ident!("{}_Impl", ident);
- return quote! { #(#path::)* #ident };
- }
- }
-
- quote! {}
- }
-}
-
-impl syn::parse::Parse for Interface {
- fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
- let attributes = input.call(syn::Attribute::parse_outer)?;
- let mut docs = Vec::new();
- for attr in attributes.into_iter() {
- let path = attr.path();
- if path.is_ident("doc") {
- docs.push(attr);
- } else {
- return Err(syn::Error::new(path.span(), "Unrecognized attribute "));
- }
- }
-
- let visibility = input.parse::<syn::Visibility>()?;
- _ = input.parse::<syn::Token![unsafe]>()?;
- _ = input.parse::<syn::Token![trait]>()?;
- let name = input.parse::<syn::Ident>()?;
- _ = input.parse::<syn::Token![:]>();
- let parent = input.parse::<syn::Path>().ok();
- let content;
- syn::braced!(content in input);
- let mut methods = Vec::new();
- while !content.is_empty() {
- methods.push(content.parse::<InterfaceMethod>()?);
- }
- Ok(Self {
- visibility,
- methods,
- name,
- parent,
- docs,
- })
- }
-}
-
-/// Parsed interface guid attribute
-///
-/// ```rust,ignore
-/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
-/// //^ parses this
-/// unsafe trait IUIAnimationVariable: IUnknown {
-/// fn GetValue(&self, value: *mut f64) -> HRESULT;
-/// }
-/// ```
-struct Guid(Option<syn::LitStr>);
-
-impl Guid {
- fn to_tokens(&self) -> syn::Result<proc_macro2::TokenStream> {
- fn hex_lit(num: &str) -> syn::LitInt {
- syn::LitInt::new(&format!("0x{num}"), proc_macro2::Span::call_site())
- }
-
- fn ensure_length(
- part: Option<&str>,
- index: usize,
- length: usize,
- span: proc_macro2::Span,
- ) -> syn::Result<String> {
- let part = match part {
- Some(p) => p,
- None => {
- return Err(syn::Error::new(
- span,
- format!("The IID missing part at index {index}"),
- ))
- }
- };
-
- if part.len() != length {
- return Err(syn::Error::new(
- span,
- format!(
- "The IID part at index {} must be {} characters long but was {} characters",
- index,
- length,
- part.len()
- ),
- ));
- }
-
- Ok(part.to_owned())
- }
-
- if let Some(value) = &self.0 {
- let guid_value = value.value();
- let mut delimited = guid_value.split('-').fuse();
- let chunks = [
- ensure_length(delimited.next(), 0, 8, value.span())?,
- ensure_length(delimited.next(), 1, 4, value.span())?,
- ensure_length(delimited.next(), 2, 4, value.span())?,
- ensure_length(delimited.next(), 3, 4, value.span())?,
- ensure_length(delimited.next(), 4, 12, value.span())?,
- ];
-
- let data1 = hex_lit(&chunks[0]);
- let data2 = hex_lit(&chunks[1]);
- let data3 = hex_lit(&chunks[2]);
- let (data4_1, data4_2) = chunks[3].split_at(2);
- let data4_1 = hex_lit(data4_1);
- let data4_2 = hex_lit(data4_2);
- let (data4_3, rest) = chunks[4].split_at(2);
- let data4_3 = hex_lit(data4_3);
-
- let (data4_4, rest) = rest.split_at(2);
- let data4_4 = hex_lit(data4_4);
-
- let (data4_5, rest) = rest.split_at(2);
- let data4_5 = hex_lit(data4_5);
-
- let (data4_6, rest) = rest.split_at(2);
- let data4_6 = hex_lit(data4_6);
-
- let (data4_7, data4_8) = rest.split_at(2);
- let data4_7 = hex_lit(data4_7);
- let data4_8 = hex_lit(data4_8);
- Ok(quote! {
- ::windows_core::GUID {
- data1: #data1,
- data2: #data2,
- data3: #data3,
- data4: [#data4_1, #data4_2, #data4_3, #data4_4, #data4_5, #data4_6, #data4_7, #data4_8]
- }
- })
- } else {
- Ok(quote! {
- ::windows_core::GUID::zeroed()
- })
- }
- }
-}
-
-impl syn::parse::Parse for Guid {
- fn parse(cursor: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
- let string: Option<syn::LitStr> = cursor.parse().ok();
-
- Ok(Self(string))
- }
-}
-
-/// A parsed interface method
-///
-/// ```rust,ignore
-/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
-/// unsafe trait IUIAnimationVariable: IUnknown {
-/// fn GetValue(&self, value: *mut f64) -> HRESULT;
-/// //^ parses this
-/// }
-/// ```
-struct InterfaceMethod {
- pub name: syn::Ident,
- pub visibility: syn::Visibility,
- pub args: Vec<InterfaceMethodArg>,
- pub ret: syn::ReturnType,
- pub docs: Vec<syn::Attribute>,
-}
-
-impl InterfaceMethod {
- fn is_result(&self) -> bool {
- if let syn::ReturnType::Type(_, ty) = &self.ret {
- if let syn::Type::Path(path) = &**ty {
- if let Some(segment) = path.path.segments.last() {
- let ident = segment.ident.to_string();
- if ident == "Result" {
- if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
- if args.args.len() == 1 {
- return true;
- }
- }
- }
- }
- }
- }
-
- false
- }
-
- /// Generates arguments (of the form `$pat: $type`)
- fn gen_args(&self) -> Vec<proc_macro2::TokenStream> {
- self.args
- .iter()
- .map(|a| {
- let pat = &a.pat;
- let ty = &a.ty;
- quote! { #pat: #ty }
- })
- .collect::<Vec<_>>()
- }
-
- fn gen_consume_generics(&self) -> Vec<proc_macro2::TokenStream> {
- self.args
- .iter()
- .enumerate()
- .filter_map(|(generic_index, a)| {
- if let Some((ty, ident)) = a.borrow_type() {
- let generic_ident = quote::format_ident!("P{generic_index}");
- if ident == "Ref" {
- Some(quote! { #generic_ident: ::windows_core::Param<#ty> })
- } else {
- Some(quote! { #generic_ident: ::windows_core::OutParam<#ty> })
- }
- } else {
- None
- }
- })
- .collect::<Vec<_>>()
- }
-
- fn gen_consume_params(&self) -> Vec<proc_macro2::TokenStream> {
- self.args
- .iter()
- .enumerate()
- .map(|(generic_index, a)| {
- let pat = &a.pat;
-
- if a.borrow_type().is_some() {
- let generic_ident = quote::format_ident!("P{generic_index}");
- quote! { #pat: #generic_ident }
- } else {
- let ty = &a.ty;
- quote! { #pat: #ty }
- }
- })
- .collect::<Vec<_>>()
- }
-
- fn gen_consume_args(&self) -> Vec<proc_macro2::TokenStream> {
- self.args
- .iter()
- .map(|a| {
- let pat = &a.pat;
-
- if let Some((_, ident)) = a.borrow_type() {
- if ident == "Ref" {
- quote! { #pat.param().borrow() }
- } else {
- quote! { #pat.borrow_mut() }
- }
- } else {
- quote! { #pat }
- }
- })
- .collect::<Vec<_>>()
- }
-}
-
-impl syn::parse::Parse for InterfaceMethod {
- fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
- let docs = input.call(syn::Attribute::parse_outer)?;
- let visibility = input.parse::<syn::Visibility>()?;
- let method = input.parse::<syn::TraitItemFn>()?;
- unexpected_token!(docs.iter().find(|a| !a.path().is_ident("doc")), "attribute");
- unexpected_token!(method.default, "default method implementation");
- let sig = method.sig;
- unexpected_token!(sig.abi, "abi declaration");
- unexpected_token!(sig.asyncness, "async declaration");
- unexpected_token!(sig.generics.params.iter().next(), "generics declaration");
- unexpected_token!(sig.constness, "const declaration");
- expected_token!(
- sig.receiver(),
- "the method to have &self as its first argument"
- );
- unexpected_token!(sig.variadic, "variadic args");
- let args = sig
- .inputs
- .into_iter()
- .filter_map(|a| match a {
- syn::FnArg::Receiver(_) => None,
- syn::FnArg::Typed(p) => Some(p),
- })
- .map(|p| {
- Ok(InterfaceMethodArg {
- ty: p.ty,
- pat: p.pat,
- })
- })
- .collect::<Result<Vec<InterfaceMethodArg>, syn::Error>>()?;
-
- let ret = sig.output;
- Ok(InterfaceMethod {
- name: sig.ident,
- visibility,
- args,
- ret,
- docs,
- })
- }
-}
-
-/// An argument to an interface method
-struct InterfaceMethodArg {
- /// The type of the argument
- pub ty: Box<syn::Type>,
- /// The name of the argument
- pub pat: Box<syn::Pat>,
-}
-
-impl InterfaceMethodArg {
- fn borrow_type(&self) -> Option<(syn::Type, String)> {
- if let syn::Type::Path(path) = &*self.ty {
- if let Some(segment) = path.path.segments.last() {
- let ident = segment.ident.to_string();
- if matches!(ident.as_str(), "Ref" | "OutRef") {
- if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
- if args.args.len() == 1 {
- if let Some(syn::GenericArgument::Type(ty)) = args.args.first() {
- return Some((ty.clone(), ident));
- }
- }
- }
- }
- }
- }
-
- None
- }
-}