1use proc_macro::TokenStream;
12use quote::{format_ident, quote, ToTokens};
13use syn::spanned::Spanned;
14use syn::{parse_macro_input, Error, FnArg, ItemFn, Pat, ReturnType};
15
16#[proc_macro_attribute]
32pub fn server_procedure(_attr: TokenStream, item: TokenStream) -> TokenStream {
33 let input = parse_macro_input!(item as ItemFn);
35
36 let name = format_ident!("{}", input.sig.ident.to_string());
38
39 if input.sig.inputs.len() != 1 {
41 return Error::new(
42 input.sig.inputs.span(),
43 "doors should take a single Request as input",
44 )
45 .to_compile_error()
46 .into();
47 }
48
49 let arg = &input.sig.inputs[0];
51 let (arg_ident, arg_type) = match arg {
52 FnArg::Receiver(_) => {
53 return Error::new(
54 arg.span(),
55 "only standalone functions supported",
56 )
57 .to_compile_error()
58 .into();
59 }
60
61 FnArg::Typed(pt) => {
62 let p = match &*pt.pat {
63 Pat::Ident(i) => i.ident.to_string(),
64
65 _ => {
66 return Error::new(
67 arg.span(),
68 "only identifier arguments supported",
69 )
70 .to_compile_error()
71 .into()
72 }
73 };
74 (format_ident!("{}", p), *pt.ty.clone())
75 }
76 };
77
78 let return_type = match input.sig.output {
80 ReturnType::Default => ReturnType::Default.to_token_stream(),
81 ReturnType::Type(_, t) => (*t).to_token_stream(),
82 };
83
84 let blk = input.block;
86
87 let q = quote! {
89
90 extern "C" fn #name(
91 cookie: *const std::os::raw::c_void,
92 argp: *const std::os::raw::c_char,
93 arg_size: usize,
94 dp: *const doors::illumos::door_h::door_desc_t,
95 n_desc: std::os::raw::c_uint,
96 ) {
97
98 let f = || -> #return_type {
99 let #arg_ident: #arg_type = doors::server::Request {
100 data: unsafe {
101 std::slice::from_raw_parts::<u8>(
102 argp as *const u8,
103 arg_size
104 )
105 },
106 descriptors: unsafe {
107 std::slice::from_raw_parts(
108 dp,
109 n_desc.try_into().unwrap()
110 )
111 },
112 cookie: cookie as u64
113 };
114 #blk
115 };
116
117 let mut response = f();
118 match response.data {
119 Some(data) => unsafe {
120 doors::illumos::door_h::door_return(
121 data.as_ref().as_ptr() as *const std::os::raw::c_char,
122 data.as_ref().len(),
123 response.descriptors.as_ptr(),
124 response.num_descriptors,
125 )
126 },
127 None => unsafe {
128 doors::illumos::door_h::door_return(
129 std::ptr::null() as *const std::os::raw::c_char,
130 0,
131 response.descriptors.as_ptr(),
132 response.num_descriptors,
133 )
134 }
135 }
136
137 }
138
139 };
140
141 TokenStream::from(q)
142}