1use crate::methodinfo::ComArg;
2use crate::prelude::*;
3use crate::tyhandlers::{self, Direction, ModelTypeSystem, TypeContext};
4use crate::utils;
5use proc_macro2::Span;
6use syn::Type;
7
8pub trait ReturnHandler: ::std::fmt::Debug
10{
11 fn type_system(&self) -> ModelTypeSystem;
13
14 fn rust_ty(&self) -> Type;
16
17 fn return_type_span(&self) -> Span;
19
20 fn is_infallible(&self) -> bool;
22
23 fn com_ty(&self) -> Type
25 {
26 tyhandlers::get_ty_handler(&self.rust_ty(), TypeContext::new(self.type_system()))
27 .com_ty(self.return_type_span())
28 }
29
30 fn com_to_rust_return(&self, _result: &Ident) -> TokenStream
33 {
34 quote!()
35 }
36
37 fn rust_to_com_return(&self, _result: &Ident) -> TokenStream
40 {
41 quote!()
42 }
43
44 fn com_out_args(&self) -> Vec<ComArg>
46 {
47 vec![]
48 }
49}
50
51#[derive(Debug)]
53struct VoidHandler(Span);
54impl ReturnHandler for VoidHandler
55{
56 fn rust_ty(&self) -> Type
57 {
58 utils::unit_ty(self.0)
59 }
60
61 fn com_ty(&self) -> Type
62 {
63 syn::parse2(quote_spanned!(self.0 => ())).unwrap()
64 }
65
66 fn type_system(&self) -> ModelTypeSystem
68 {
69 ModelTypeSystem::Automation
70 }
71
72 fn return_type_span(&self) -> Span
74 {
75 self.0
76 }
77
78 fn is_infallible(&self) -> bool
79 {
80 true
81 }
82}
83
84#[derive(Debug)]
86struct ReturnOnlyHandler(Type, ModelTypeSystem, Span);
87impl ReturnHandler for ReturnOnlyHandler
88{
89 fn type_system(&self) -> ModelTypeSystem
90 {
91 self.1
92 }
93
94 fn rust_ty(&self) -> Type
95 {
96 self.0.clone()
97 }
98
99 fn return_type_span(&self) -> Span
100 {
101 self.2
102 }
103
104 fn com_to_rust_return(&self, result: &Ident) -> TokenStream
105 {
106 tyhandlers::get_ty_handler(&self.rust_ty(), TypeContext::new(self.1)).com_to_rust(
107 result,
108 self.2,
109 Direction::Retval,
110 true,
111 )
112 }
113
114 fn rust_to_com_return(&self, result: &Ident) -> TokenStream
115 {
116 tyhandlers::get_ty_handler(&self.rust_ty(), TypeContext::new(self.1)).rust_to_com(
117 result,
118 self.2,
119 Direction::Retval,
120 true,
121 )
122 }
123
124 fn com_out_args(&self) -> Vec<ComArg>
125 {
126 vec![]
127 }
128
129 fn is_infallible(&self) -> bool
130 {
131 true
132 }
133}
134
135#[derive(Debug)]
138struct ErrorResultHandler
139{
140 retval_ty: Type,
141 return_ty: Type,
142 span: Span,
143 type_system: ModelTypeSystem,
144}
145
146impl ReturnHandler for ErrorResultHandler
147{
148 fn type_system(&self) -> ModelTypeSystem
149 {
150 self.type_system
151 }
152 fn rust_ty(&self) -> Type
153 {
154 self.return_ty.clone()
155 }
156 fn return_type_span(&self) -> Span
157 {
158 self.span
159 }
160 fn com_ty(&self) -> Type
161 {
162 let ts = self.type_system.as_typesystem_type(self.span);
163 syn::parse2(quote_spanned!(self.span=>
164 < intercom::raw::HRESULT as
165 intercom::type_system::ExternType< #ts >>
166 ::ForeignType ))
167 .unwrap()
168 }
169
170 fn com_to_rust_return(&self, result: &Ident) -> TokenStream
171 {
172 let (temp_values, ok_values) =
176 get_rust_ok_values(self.com_out_args(), self.is_infallible());
177 let ok_values = if ok_values.len() != 1 {
178 quote!( ( #( #ok_values ),* ) )
179 } else {
180 quote!( #( #ok_values )* )
181 };
182
183 quote!(
186 if #result == intercom::raw::S_OK || #result == intercom::raw::S_FALSE {
188 #( #temp_values; )*
189 Ok( #ok_values )
190 } else {
191 return Err( intercom::load_error(
192 self,
193 &__intercom_iid,
194 #result ) );
195 }
196 )
197 }
198
199 fn rust_to_com_return(&self, result: &Ident) -> TokenStream
200 {
201 let ok_idents = self
204 .com_out_args()
205 .iter()
206 .enumerate()
207 .map(|(idx, _)| Ident::new(&format!("v{}", idx + 1), Span::call_site()))
208 .collect::<Vec<_>>();
209
210 let ok_pattern = {
214 let rok_idents = &ok_idents;
217 match self.retval_ty {
218 Type::Tuple(_) => quote!( ( #( #rok_idents ),* ) ),
219
220 _ => quote!( #( #rok_idents )* ),
222 }
223 };
224
225 let (temp_writes, ok_writes, err_writes) = write_out_values(
226 &ok_idents,
227 self.com_out_args(),
228 self.is_infallible(),
229 self.span,
230 self.type_system,
231 );
232 quote!(
233 match #result.and_then(|#ok_pattern| {
234 #( #temp_writes; )*
236
237 #( #ok_writes; )*
239 Ok( intercom::raw::S_OK )
240 }) {
241 Ok( s ) => s,
242 Err( e ) => {
243 #( #err_writes );*;
244 intercom::store_error( e ).hresult
245 },
246 }
247 )
248 }
249
250 fn com_out_args(&self) -> Vec<ComArg>
251 {
252 get_out_args_for_result(&self.retval_ty, self.span, self.type_system)
253 }
254
255 fn is_infallible(&self) -> bool
256 {
257 false
258 }
259}
260
261fn get_out_args_for_result(
262 retval_ty: &Type,
263 span: Span,
264 type_system: ModelTypeSystem,
265) -> Vec<ComArg>
266{
267 match *retval_ty {
268 Type::Tuple(ref t) => t
270 .elems
271 .iter()
272 .enumerate()
273 .map(|(idx, ty)| {
274 ComArg::new(
275 Ident::new(&format!("__out{}", idx + 1), span),
276 ty.clone(),
277 span,
278 Direction::Out,
279 type_system,
280 )
281 })
282 .collect::<Vec<_>>(),
283 _ => vec![ComArg::new(
284 Ident::new("__out", span),
285 retval_ty.clone(),
286 span,
287 Direction::Retval,
288 type_system,
289 )],
290 }
291}
292
293fn write_out_values(
294 idents: &[Ident],
295 out_args: Vec<ComArg>,
296 infallible: bool,
297 span: Span,
298 ts: ModelTypeSystem,
299) -> (Vec<TokenStream>, Vec<TokenStream>, Vec<TokenStream>)
300{
301 let ts = ts.as_typesystem_type(span);
302 let mut temp_tokens = vec![];
303 let mut ok_tokens = vec![];
304 let mut err_tokens = vec![];
305 for (ident, out_arg) in idents.iter().zip(out_args) {
306 let arg_name = out_arg.name;
307 let temp_name = Ident::new(&format!("__{}_guard", arg_name), span);
308 let ty = out_arg.ty;
309 let ok_value = out_arg
310 .handler
311 .rust_to_com(ident, span, Direction::Out, infallible);
312 let err_value = out_arg.handler.default_value();
313
314 temp_tokens.push(quote!( let #temp_name = intercom::type_system::OutputGuard::<#ts, #ty>::wrap( #ok_value ) ));
315 ok_tokens.push(quote!( *#arg_name = #temp_name.consume() ));
316 err_tokens.push(quote!( *#arg_name = #err_value ));
317 }
318
319 (temp_tokens, ok_tokens, err_tokens)
320}
321
322fn get_rust_ok_values(
324 out_args: Vec<ComArg>,
325 infallible: bool,
326) -> (Vec<TokenStream>, Vec<TokenStream>)
327{
328 let mut temp_tokens = vec![];
329 let mut ok_tokens = vec![];
330 for out_arg in out_args {
331 let value =
332 out_arg
333 .handler
334 .com_to_rust(&out_arg.name, out_arg.span, Direction::Retval, infallible);
335 let temp_name = Ident::new(&format!("__{}_guard", out_arg.name), out_arg.span);
336 let unwrap = match infallible {
337 true => quote!(),
338 false => quote!(?),
339 };
340
341 temp_tokens.push(quote!(let #temp_name = #value));
342 ok_tokens.push(quote!(#temp_name#unwrap));
343 }
344 (temp_tokens, ok_tokens)
345}
346
347pub fn get_return_handler(
349 retval_ty: &Option<Type>,
350 return_ty: &Option<Type>,
351 span: Span,
352 type_system: ModelTypeSystem,
353) -> Result<Box<dyn ReturnHandler>, &'static str>
354{
355 Ok(match (retval_ty, return_ty) {
356 (&None, &None) => Box::new(VoidHandler(span)),
357 (&None, &Some(ref ty)) => Box::new(ReturnOnlyHandler(ty.clone(), type_system, span)),
358 (&Some(ref rv), &Some(ref rt)) => Box::new(ErrorResultHandler {
359 retval_ty: rv.clone(),
360 return_ty: rt.clone(),
361 span,
362 type_system,
363 }),
364
365 _ => return Err("Unsupported return type configuration"),
369 })
370}