1use proc_macro2::TokenStream;
4use quote::{format_ident, quote};
5
6pub(crate) fn native_borrow_checks<'a>(
10 args: impl IntoIterator<Item = (usize, String, &'a syn::Type)>,
11 argv: &syn::Ident,
12 targets: Option<&[syn::Ident]>,
13) -> TokenStream {
14 let mut values = Vec::new();
15 let mut metadata = Vec::new();
16 for (index, name, ty) in args {
17 if crate::type_inspect::self_ref_mutability(ty).is_some() {
18 continue;
19 }
20 values.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&argv, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "add");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&index, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
});
_s
}quote! { (*#argv.add(#index), #name) });
21 if let Some(targets) = targets {
22 let target = &targets[index];
23 metadata.push(
24 if crate::type_inspect::is_rooted_view(ty)
25 || crate::type_inspect::is_rooted_reference(ty)
26 {
27 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&target, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "rooted_native_borrow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote! { #target.rooted_native_borrow() }
28 } else {
29 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&target, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "native_borrow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote! { #target.native_borrow() }
30 },
31 );
32 continue;
33 }
34 metadata.push(
35 if crate::type_inspect::is_rooted_view(ty)
36 || crate::type_inspect::is_rooted_reference(ty)
37 {
38 let ty = crate::type_inspect::erase_lifetimes(ty);
39 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TryFromRoot");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'_");
::quote::__private::push_shr(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "NATIVE_BORROW");
_s
}quote! { <#ty as ::miniextendr_api::TryFromRoot<'_>>::NATIVE_BORROW }
40 } else {
41 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TryFromSexp");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "NATIVE_BORROW");
_s
}quote! { <#ty as ::miniextendr_api::TryFromSexp>::NATIVE_BORROW }
42 },
43 );
44 }
45 if values.is_empty() {
46 return TokenStream::new();
47 }
48 let borrows = syn::Ident::new(
49 "__miniextendr_native_borrows",
50 proc_macro2::Span::mixed_site(),
51 );
52 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&borrows, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut metadata, i) = metadata.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let metadata =
match metadata.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&metadata, &mut _s);
}
}
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "if");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_r");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "borrow");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "needs_check");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_and(&mut _s);
::quote::ToTokens::to_tokens(&borrows, &mut _s);
_s
});
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_r");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "borrow");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"assert_no_aliases");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut values, i) = values.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let values =
match values.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&values, &mut _s);
}
}
_s
});
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&borrows, &mut _s);
::quote::__private::push_comma(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
});
_s
});
_s
});
_s
}quote! {{
53 let #borrows = [#(#metadata),*];
54 if ::miniextendr_api::from_r::borrow::needs_check(&#borrows) {
55 unsafe {
58 ::miniextendr_api::from_r::borrow::assert_no_aliases(
59 [#(#values),*], #borrows,
60 );
61 }
62 }
63 }}
64}
65
66pub(crate) fn argument(
71 name: &syn::Ident,
72 diagnostic_name: &str,
73 ty: &syn::Type,
74 impl_ty: &impl quote::ToTokens,
75 index: usize,
76 argv: &syn::Ident,
77 target: Option<&syn::Ident>,
78) -> TokenStream {
79 let target = target.filter(|_| crate::type_inspect::self_ref_mutability(ty).is_none());
80 let input = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&argv, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "add");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&index, &mut _s);
_s
});
_s
});
_s
}quote! { unsafe { *#argv.add(#index) } };
81 let r_name = crate::r_wrapper_builder::normalize_r_arg_string(diagnostic_name);
82 let (setup, binding, mut read_ty, mut conversion, rooted) = if let Some(mutable) =
83 crate::type_inspect::self_ref_mutability(ty)
84 {
85 let handle = handle_ident(name);
86 let mutability = mutable.then(|| {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "mut");
_s
}quote!(mut));
87 let read_ty: syn::Type = ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ExternalPtr");
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&impl_ty, &mut _s);
::quote::__private::push_gt(&mut _s);
_s
})syn::parse_quote!(::miniextendr_api::ExternalPtr<#impl_ty>);
88 let conversion = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&read_ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TryFromSexp");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "try_from_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&input, &mut _s);
_s
});
_s
}quote! {
89 <#read_ty as ::miniextendr_api::TryFromSexp>::try_from_sexp(#input)
90 };
91 (
92 TokenStream::new(),
93 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&mutability, &mut _s);
::quote::ToTokens::to_tokens(&handle, &mut _s);
_s
}quote!(#mutability #handle),
94 read_ty,
95 conversion,
96 false,
97 )
98 } else if crate::type_inspect::is_rooted_view(ty)
99 || crate::type_inspect::is_rooted_reference(ty)
100 {
101 if let Some(stmt) = crate::type_inspect::static_rooted_view_binding(name, ty) {
102 return stmt;
103 }
104 let slot = match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(name)) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__mx_root_{0}", arg))
}),
::quote::__private::Option::Some::<::quote::__private::Span>(proc_macro2::Span::mixed_site())),
}format_ident!(
105 "__mx_root_{}",
106 crate::naming::unraw(name),
107 span = proc_macro2::Span::mixed_site()
108 );
109 let read_ty = crate::type_inspect::erase_lifetimes(ty);
110 let conversion = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&read_ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TryFromRoot");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'_");
::quote::__private::push_shr(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "try_from_root");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&slot, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "rooted");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&argv, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "add");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&index, &mut _s);
_s
});
_s
});
_s
});
_s
});
_s
}quote! {
111 <#read_ty as ::miniextendr_api::TryFromRoot<'_>>::try_from_root(unsafe {
112 #slot.rooted(*#argv.add(#index))
113 })
114 };
115 (
116 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&slot, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "gc_protect");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ProtectScope");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "new");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! { let #slot = unsafe { ::miniextendr_api::gc_protect::ProtectScope::new() }; },
117 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
}quote!(#name),
118 read_ty,
119 conversion,
120 true,
121 )
122 } else {
123 let conversion = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "TryFromSexp");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "try_from_sexp");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&input, &mut _s);
_s
});
_s
}quote! {
124 <#ty as ::miniextendr_api::TryFromSexp>::try_from_sexp(#input)
125 };
126 (
127 TokenStream::new(),
128 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&name, &mut _s);
_s
}quote!(#name),
129 ty.clone(),
130 conversion,
131 false,
132 )
133 };
134 if let Some(target) = target {
135 read_ty = ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_underscore(&mut _s);
_s
})syn::parse_quote!(_);
136 conversion = if rooted {
137 let slot = match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(name)) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__mx_root_{0}", arg))
}),
::quote::__private::Option::Some::<::quote::__private::Span>(proc_macro2::Span::mixed_site())),
}format_ident!(
138 "__mx_root_{}",
139 crate::naming::unraw(name),
140 span = proc_macro2::Span::mixed_site()
141 );
142 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&target, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "rooted");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&slot, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "rooted");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&argv, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "add");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&index, &mut _s);
_s
});
_s
});
_s
});
_s
});
_s
}quote! { #target.rooted(unsafe { #slot.rooted(*#argv.add(#index)) }) }
143 } else {
144 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&target, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "convert");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&input, &mut _s);
_s
});
_s
}quote! { #target.convert(#input) }
145 };
146 }
147 let err_arm = crate::rust_conversion_builder::shim_conversion_err_arm(
148 &r_name,
149 ty,
150 (!rooted).then_some(&read_ty),
151 target.filter(|_| !rooted),
152 );
153 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&setup, &mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&binding, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&read_ty, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "match");
::quote::ToTokens::to_tokens(&conversion, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "result");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Result");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Ok");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "value");
_s
});
::quote::__private::push_fat_arrow(&mut _s);
::quote::__private::push_ident(&mut _s, "value");
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&err_arm, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
154 #setup
155 let #binding: #read_ty = match #conversion {
156 ::core::result::Result::Ok(value) => value,
157 #err_arm
158 };
159 }
160}
161
162pub(crate) fn cell_address(cell: &syn::Ident) -> TokenStream {
166 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&cell, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "as_ptr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "cast_const");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "cast");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ffi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "c_void");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote! { #cell.as_ptr().cast_const().cast::<::core::ffi::c_void>() }
167}
168
169pub(crate) fn receiver_borrow(
173 cell: &syn::Ident,
174 guard: &syn::Ident,
175 self_ref: &syn::Ident,
176 mutable: bool,
177) -> TokenStream {
178 if mutable {
179 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "mut");
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "borrow_value_mut");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&cell, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote! {
180 let mut #guard = ::miniextendr_api::externalptr::borrow_value_mut(#cell);
181 let #self_ref = &mut *#guard;
182 }
183 } else {
184 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "miniextendr_api");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "externalptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "borrow_value");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&cell, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&self_ref, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote! {
185 let #guard = ::miniextendr_api::externalptr::borrow_value(#cell);
186 let #self_ref = &*#guard;
187 }
188 }
189}
190
191pub(crate) fn handle_ident(name: &syn::Ident) -> syn::Ident {
192 match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(name)) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__extptr_{0}", arg))
}),
::quote::__private::Option::Some::<::quote::__private::Span>(proc_macro2::Span::mixed_site())),
}format_ident!(
193 "__extptr_{}",
194 crate::naming::unraw(name),
195 span = proc_macro2::Span::mixed_site()
196 )
197}
198
199pub(crate) fn borrow(name: &syn::Ident, mutable: bool) -> TokenStream {
205 let handle = handle_ident(name);
206 let guard = match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(name)) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__mx_guard_{0}", arg))
}),
::quote::__private::Option::Some::<::quote::__private::Span>(proc_macro2::Span::mixed_site())),
}format_ident!(
207 "__mx_guard_{}",
208 crate::naming::unraw(name),
209 span = proc_macro2::Span::mixed_site()
210 );
211 if mutable {
212 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "mut");
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&handle, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "borrow_mut");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "mut");
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote! {
213 let mut #guard = #handle.borrow_mut();
214 let #name = &mut *#guard;
215 }
216 } else {
217 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&handle, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "borrow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::ToTokens::to_tokens(&guard, &mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote! {
218 let #guard = #handle.borrow();
219 let #name = &*#guard;
220 }
221 }
222}
223
224pub(crate) fn alias_checks(
227 ty: &impl quote::ToTokens,
228 handles: &[(syn::Ident, bool, String)],
229 receiver: Option<(TokenStream, bool)>,
230) -> TokenStream {
231 let mut pointers: Vec<_> = handles
232 .iter()
233 .map(|(handle, mutable, name)| {
234 (
235 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&handle, &mut _s);
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "as_ptr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "cast");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ffi");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "c_void");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote!(#handle.as_ptr().cast::<::core::ffi::c_void>()),
236 *mutable,
237 name.clone(),
238 )
239 })
240 .collect();
241 if let Some((pointer, mutable)) = receiver {
242 pointers.insert(0, (pointer, mutable, "self".to_owned()));
243 }
244 let mut checks = Vec::new();
245 for (index, (left, left_mut, left_name)) in pointers.iter().enumerate() {
246 for (right, right_mut, right_name) in &pointers[index + 1..] {
247 if *left_mut || *right_mut {
248 let message = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("trait arguments \'{0}\' and \'{1}\' alias the same object while one is mutable",
left_name, right_name))
})format!(
249 "trait arguments '{left_name}' and '{right_name}' alias the same object while one is mutable"
250 );
251 checks.push({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "assert");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_bang(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ptr");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "eq");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&left, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&right, &mut _s);
_s
});
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&message, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
}quote! {
252 ::core::assert!(!::core::ptr::eq(#left, #right), #message);
253 });
254 }
255 }
256 }
257 if checks.is_empty() {
258 TokenStream::new()
259 } else {
260 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "if");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mem");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "size_of");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_ne(&mut _s);
::quote::__private::parse(&mut _s, "0");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut checks, i) = checks.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let checks =
match checks.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&checks, &mut _s);
}
}
_s
});
_s
}quote! { if ::core::mem::size_of::<#ty>() != 0 { #(#checks)* } }
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 #[test]
270 fn native_preflight_preserves_argument_positions_around_self_references() {
271 let types: [syn::Type; 3] = [
272 syn::parse_quote!(&Self),
273 syn::parse_quote!((&mut i32, &i32)),
274 syn::parse_quote!(&mut Self),
275 ];
276 let argv = format_ident!("argv");
277 let output = native_borrow_checks(
278 types
279 .iter()
280 .enumerate()
281 .map(|(i, ty)| (i, format!("arg{i}"), ty)),
282 &argv,
283 None,
284 );
285 let expected =
286 quote! { <(&mut i32, &i32) as ::miniextendr_api::TryFromSexp>::NATIVE_BORROW };
287 let output = output.to_string();
288 assert!(output.contains(&expected.to_string()));
289 assert!(output.contains("e! { (*argv.add(1usize), "arg1") }.to_string()));
290 assert!(!output.contains("arg0"));
291 assert!(!output.contains("arg2"));
292 assert!(native_borrow_checks([(0, "other".into(), &types[0])], &argv, None).is_empty());
293 }
294
295 #[test]
296 fn shared_pairs_need_no_guard_but_every_mutable_pair_does() {
297 let handles = vec![
298 (format_ident!("left"), false, "left".into()),
299 (format_ident!("r#type"), false, "type".into()),
300 ];
301 assert!(
302 alias_checks(
303 "e!(Counter),
304 &handles,
305 Some((quote!(data.cast_const()), false))
306 )
307 .is_empty()
308 );
309 let output = alias_checks(
310 "e!(Counter),
311 &handles,
312 Some((quote!(data.cast_const()), true)),
313 )
314 .to_string();
315 assert_eq!(output.matches(":: core :: assert !").count(), 2);
316 assert!(output.contains("'self' and 'left'"));
317 assert!(output.contains("'self' and 'type'"));
318 let mut handles = handles;
319 handles[1].1 = true;
320 let output = alias_checks(
321 "e!(Counter),
322 &handles,
323 Some((quote!(data.cast_const()), true)),
324 )
325 .to_string();
326 assert_eq!(output.matches(":: core :: assert !").count(), 3);
327 assert!(output.contains("'left' and 'type'"));
328 }
329
330 #[test]
331 fn self_arguments_hold_their_borrow_for_the_shim() {
332 let output = borrow(&format_ident!("r#type"), true).to_string();
333 assert!(output.contains("__extptr_type . borrow_mut ()"), "{output}");
334 assert!(
335 output.contains("let r#type = & mut * __mx_guard_type"),
336 "{output}"
337 );
338 let output = borrow(&format_ident!("other"), false).to_string();
339 assert!(output.contains("__extptr_other . borrow ()"), "{output}");
340 assert!(
341 output.contains("let other = & * __mx_guard_other"),
342 "{output}"
343 );
344 }
345}