1 #[allow(unused_imports)]
2 #[allow(deprecated)]
3 use std::ascii::AsciiExt;
4 use std::iter;
5
6 use proc_macro2::{Ident, Literal, Span, TokenStream};
7 use quote::ToTokens;
8
9 use protocol::*;
10 use util::*;
11 use Side;
12
to_doc_attr(text: &str) -> TokenStream13 pub(crate) fn to_doc_attr(text: &str) -> TokenStream {
14 let text = text
15 .lines()
16 .map(|line| line.trim())
17 .collect::<Vec<_>>()
18 .join("\n");
19 let text = text.trim();
20
21 quote!(#[doc = #text])
22 }
23
description_to_doc_attr(&(ref short, ref long): &(String, String)) -> TokenStream24 pub(crate) fn description_to_doc_attr(&(ref short, ref long): &(String, String)) -> TokenStream {
25 to_doc_attr(&format!("{}\n\n{}", short, long))
26 }
27
28 impl ToTokens for Enum {
to_tokens(&self, tokens: &mut TokenStream)29 fn to_tokens(&self, tokens: &mut TokenStream) {
30 let enum_decl;
31 let enum_impl;
32
33 let doc_attr = self.description.as_ref().map(description_to_doc_attr);
34 let ident = Ident::new(&snake_to_camel(&self.name), Span::call_site());
35
36 if self.bitfield {
37 let entries = self.entries.iter().map(|entry| {
38 let doc_attr = entry
39 .description
40 .as_ref()
41 .map(description_to_doc_attr)
42 .or_else(|| entry.summary.as_ref().map(|s| to_doc_attr(s)));
43
44 let prefix = if entry.name.chars().next().unwrap().is_numeric() {
45 "_"
46 } else {
47 ""
48 };
49 let ident = Ident::new(
50 &format!("{}{}", prefix, snake_to_camel(&entry.name)),
51 Span::call_site(),
52 );
53
54 let value = Literal::u32_unsuffixed(entry.value);
55
56 quote! {
57 #doc_attr
58 const #ident = #value;
59 }
60 });
61
62 enum_decl = quote! {
63 bitflags! {
64 #doc_attr
65 pub struct #ident: u32 {
66 #(#entries)*
67 }
68 }
69 };
70 enum_impl = quote! {
71 impl #ident {
72 pub fn from_raw(n: u32) -> Option<#ident> {
73 Some(#ident::from_bits_truncate(n))
74 }
75
76 pub fn to_raw(&self) -> u32 {
77 self.bits()
78 }
79 }
80 };
81 } else {
82 let variants = self.entries.iter().map(|entry| {
83 let doc_attr = entry
84 .description
85 .as_ref()
86 .map(description_to_doc_attr)
87 .or_else(|| entry.summary.as_ref().map(|s| to_doc_attr(s)));
88
89 let prefix = if entry.name.chars().next().unwrap().is_numeric() {
90 "_"
91 } else {
92 ""
93 };
94 let variant = Ident::new(
95 &format!("{}{}", prefix, snake_to_camel(&entry.name)),
96 Span::call_site(),
97 );
98
99 let value = Literal::u32_unsuffixed(entry.value);
100
101 quote! {
102 #doc_attr
103 #variant = #value
104 }
105 });
106
107 enum_decl = quote! {
108 #doc_attr
109 #[repr(u32)]
110 #[derive(Copy, Clone, Debug, PartialEq)]
111 pub enum #ident {
112 #(#variants,)*
113 }
114 };
115
116 let match_arms = self.entries.iter().map(|entry| {
117 let value = Literal::u32_unsuffixed(entry.value);
118
119 let prefix = if entry.name.chars().next().unwrap().is_numeric() {
120 "_"
121 } else {
122 ""
123 };
124 let variant = Ident::new(
125 &format!("{}{}", prefix, snake_to_camel(&entry.name)),
126 Span::call_site(),
127 );
128
129 quote! {
130 #value => Some(#ident::#variant)
131 }
132 });
133
134 enum_impl = quote! {
135 impl #ident {
136 pub fn from_raw(n: u32) -> Option<#ident> {
137 match n {
138 #(#match_arms,)*
139 _ => Option::None
140 }
141 }
142
143 pub fn to_raw(&self) -> u32 {
144 *self as u32
145 }
146 }
147 };
148 }
149
150 enum_decl.to_tokens(tokens);
151 enum_impl.to_tokens(tokens);
152 }
153 }
154
gen_since_constants(requests: &[Message], events: &[Message]) -> TokenStream155 pub(crate) fn gen_since_constants(requests: &[Message], events: &[Message]) -> TokenStream {
156 let req_constants = requests.iter().map(|msg| {
157 let cstname = Ident::new(
158 &format!("REQ_{}_SINCE", msg.name.to_ascii_uppercase()),
159 Span::call_site(),
160 );
161 let since = msg.since;
162 quote! {
163 /// The minimal object version supporting this request
164 pub const #cstname: u16 = #since;
165 }
166 });
167 let evt_constants = events.iter().map(|msg| {
168 let cstname = Ident::new(
169 &format!("EVT_{}_SINCE", msg.name.to_ascii_uppercase()),
170 Span::call_site(),
171 );
172 let since = msg.since;
173 quote! {
174 /// The minimal object version supporting this event
175 pub const #cstname: u16 = #since;
176 }
177 });
178
179 quote! {
180 #(#req_constants)*
181 #(#evt_constants)*
182 }
183 }
184
gen_messagegroup( name: &Ident, side: Side, receiver: bool, messages: &[Message], addon: Option<TokenStream>, ) -> TokenStream185 pub(crate) fn gen_messagegroup(
186 name: &Ident,
187 side: Side,
188 receiver: bool,
189 messages: &[Message],
190 addon: Option<TokenStream>,
191 ) -> TokenStream {
192 let variants = messages.iter().map(|msg| {
193 let mut docs = String::new();
194 if let Some((ref short, ref long)) = msg.description {
195 docs += &format!("{}\n\n{}\n", short, long.trim());
196 }
197 if let Some(Type::Destructor) = msg.typ {
198 docs += &format!(
199 "\nThis is a destructor, once {} this object cannot be used any longer.",
200 if receiver { "received" } else { "sent" },
201 );
202 }
203 if msg.since > 1 {
204 docs += &format!("\nOnly available since version {} of the interface", msg.since);
205 }
206
207 let doc_attr = to_doc_attr(&docs);
208 let msg_name = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
209 let msg_variant_decl = if msg.args.is_empty() {
210 msg_name.into_token_stream()
211 } else {
212 let fields = msg.args.iter().map(|arg| {
213 let field_name = Ident::new(&arg.name, Span::call_site());
214 let field_type_inner = if let Some(ref enu) = arg.enum_ {
215 dotted_to_relname(enu)
216 } else {
217 match arg.typ {
218 Type::Uint => quote!(u32),
219 Type::Int => quote!(i32),
220 Type::Fixed => quote!(f64),
221 Type::String => quote!(String),
222 Type::Array => quote!(Vec<u8>),
223 Type::Fd => quote!(::std::os::unix::io::RawFd),
224 Type::Object => {
225 let object_name = side.object_name();
226 if let Some(ref iface) = arg.interface {
227 let iface_mod = Ident::new(&iface, Span::call_site());
228 let iface_type = Ident::new(&snake_to_camel(iface), Span::call_site());
229 quote!(#object_name<super::#iface_mod::#iface_type>)
230 } else {
231 quote!(#object_name<AnonymousObject>)
232 }
233 }
234 Type::NewId => {
235 let prefix = if receiver { "New" } else { "" };
236 let object_name =
237 Ident::new(&format!("{}{}", prefix, side.object_name()), Span::call_site());
238 if let Some(ref iface) = arg.interface {
239 let iface_mod = Ident::new(&iface, Span::call_site());
240 let iface_type = Ident::new(&snake_to_camel(iface), Span::call_site());
241 quote!(#object_name<super::#iface_mod::#iface_type>)
242 } else {
243 // bind-like function
244 quote!((String, u32, #object_name<AnonymousObject>))
245 }
246 }
247 Type::Destructor => panic!("An argument cannot have type \"destructor\"."),
248 }
249 };
250
251 let field_type = if arg.allow_null {
252 quote!(Option<#field_type_inner>)
253 } else {
254 field_type_inner.into_token_stream()
255 };
256
257 quote! {
258 #field_name: #field_type
259 }
260 });
261
262 quote! {
263 #msg_name {
264 #(#fields,)*
265 }
266 }
267 };
268
269 quote! {
270 #doc_attr
271 #msg_variant_decl
272 }
273 });
274
275 let message_array_values = messages.iter().map(|msg| {
276 let name_value = &msg.name;
277 let since_value = Literal::u16_unsuffixed(msg.since);
278 let signature_values = msg.args.iter().map(|arg| {
279 let common_type = arg.typ.common_type();
280 quote!(super::ArgumentType::#common_type)
281 });
282
283 quote! {
284 super::MessageDesc {
285 name: #name_value,
286 since: #since_value,
287 signature: &[
288 #(#signature_values,)*
289 ],
290 }
291 }
292 });
293
294 let map_type = if side == Side::Client {
295 quote!(ProxyMap)
296 } else {
297 quote!(ResourceMap)
298 };
299
300 // Can't be a closure because closures are never Copy / Clone in rustc < 1.26.0, and we supports 1.21.0
301 fn map_fn((ref msg, ref name): (&Message, &Ident)) -> TokenStream {
302 let msg_type = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
303 let msg_type_qualified = quote!(#name::#msg_type);
304
305 if msg.args.is_empty() {
306 msg_type_qualified
307 } else {
308 quote!(#msg_type_qualified { .. })
309 }
310 };
311
312 let message_match_patterns = messages.iter().zip(iter::repeat(name)).map(map_fn);
313
314 let mut is_destructor_match_arms = messages
315 .iter()
316 .zip(message_match_patterns.clone())
317 .filter(|&(msg, _)| msg.typ == Some(Type::Destructor))
318 .map(|(_, pattern)| quote!(#pattern => true))
319 .collect::<Vec<_>>();
320
321 if messages.len() > is_destructor_match_arms.len() {
322 is_destructor_match_arms.push(quote!(_ => false));
323 }
324
325 let opcode_match_arms = message_match_patterns.enumerate().map(|(opcode, pattern)| {
326 let value = Literal::u16_unsuffixed(opcode as u16);
327 quote!(#pattern => #value)
328 });
329
330 let child_match_arms = messages
331 .iter()
332 .enumerate()
333 .filter_map(|(opcode, msg)| {
334 let mut it = msg.args.iter().filter_map(|a| {
335 if a.typ == Type::NewId {
336 a.interface.as_ref()
337 } else {
338 None
339 }
340 });
341
342 it.next().map(|new_iface| {
343 assert!(
344 it.next().is_none(),
345 "Got a message with more than one new_id in {}.{}",
346 name,
347 msg.name
348 );
349
350 let pattern = Literal::u16_unsuffixed(opcode as u16);
351 let new_iface_mod = Ident::new(new_iface, Span::call_site());
352 let new_iface_type = Ident::new(&snake_to_camel(new_iface), Span::call_site());
353
354 quote! {
355 #pattern => Some(Object::from_interface::<super::#new_iface_mod::#new_iface_type>(
356 version,
357 meta.child(),
358 ))
359 }
360 })
361 })
362 .chain(iter::once(quote!(_ => None)));
363
364 let from_raw_body = if receiver {
365 let match_arms = messages
366 .iter()
367 .enumerate()
368 .map(|(opcode, msg)| {
369 let pattern = Literal::u16_unsuffixed(opcode as u16);
370 let msg_type = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
371 let msg_type_qualified = quote!(#name::#msg_type);
372
373 let block = if msg.args.is_empty() {
374 quote!(Ok(#msg_type_qualified))
375 } else {
376 let fields = msg.args.iter().map(|arg| {
377 let field_name = Ident::new(&arg.name, Span::call_site());
378 let some_code_path = match arg.typ {
379 Type::Int => {
380 if let Some(ref enu) = arg.enum_ {
381 let enum_ident = dotted_to_relname(enu);
382 quote!(#enum_ident::from_raw(val as u32).ok_or(())?)
383 } else {
384 quote!(val)
385 }
386 }
387 Type::Uint => {
388 if let Some(ref enu) = arg.enum_ {
389 let enum_ident = dotted_to_relname(enu);
390 quote!(#enum_ident::from_raw(val).ok_or(())?)
391 } else {
392 quote!(val)
393 }
394 }
395 Type::Fixed => quote!((val as f64) / 256.),
396 Type::Array => {
397 if arg.allow_null {
398 quote!(if val.len() == 0 { None } else { Some(val) })
399 } else {
400 quote!(val)
401 }
402 }
403 Type::String => {
404 let string_conversion = quote! {
405 let s = String::from_utf8(val.into_bytes())
406 .unwrap_or_else(|e| String::from_utf8_lossy(&e.into_bytes()).into());
407 };
408
409 if arg.allow_null {
410 quote! {
411 #string_conversion
412 if s.len() == 0 { None } else { Some(s) }
413 }
414 } else {
415 quote! {
416 #string_conversion
417 s
418 }
419 }
420 }
421 Type::Fd => quote!(val),
422 Type::Object => {
423 let map_lookup = quote!(map.get(val).ok_or(())?);
424 if arg.allow_null {
425 quote!(if val == 0 { None } else { Some(#map_lookup) })
426 } else {
427 map_lookup
428 }
429 }
430 Type::NewId => {
431 let map_lookup = quote!(map.get_new(val).ok_or(())?);
432 if arg.allow_null {
433 quote!(if val == 0 { None } else { Some(#map_lookup) })
434 } else {
435 map_lookup
436 }
437 }
438 Type::Destructor => panic!("An argument cannot have type destructor!"),
439 };
440
441 let common_type = arg.typ.common_type();
442
443 quote! {
444 #field_name: {
445 if let Some(Argument::#common_type(val)) = args.next() {
446 #some_code_path
447 } else {
448 return Err(());
449 }
450 }
451 }
452 });
453
454 quote! {
455 {
456 let mut args = msg.args.into_iter();
457
458 Ok(#msg_type_qualified {
459 #(#fields,)*
460 })
461 }
462 }
463 };
464
465 quote!(#pattern => #block)
466 })
467 .chain(iter::once(quote!(_ => Err(()))));
468
469 quote! {
470 match msg.opcode {
471 #(#match_arms,)*
472 }
473 }
474 } else {
475 let panic_message = format!("{}::from_raw can not be used {:?}-side.", name, side);
476 quote!(panic!(#panic_message))
477 };
478
479 let into_raw_body = if receiver {
480 let panic_message = format!("{}::into_raw can not be used {:?}-side.", name, side);
481 quote!(panic!(#panic_message))
482 } else {
483 let match_arms = messages.iter().enumerate().map(|(opcode, msg)| {
484 let msg_type = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
485 let msg_type_qualified = quote!(#name::#msg_type);
486
487 let pattern = if msg.args.is_empty() {
488 msg_type_qualified
489 } else {
490 let fields = msg
491 .args
492 .iter()
493 .map(|arg| Ident::new(&arg.name, Span::call_site()));
494 quote!(#msg_type_qualified { #(#fields),* })
495 };
496
497 let opcode_value = Literal::u16_unsuffixed(opcode as u16);
498 let args_values = msg.args.iter().map(|arg| {
499 let arg_ident = Ident::new(&arg.name, Span::call_site());
500 match arg.typ {
501 Type::Int => {
502 if arg.enum_.is_some() {
503 quote!(Argument::Int(#arg_ident.to_raw() as i32))
504 } else {
505 quote!(Argument::Int(#arg_ident))
506 }
507 }
508 Type::Uint => {
509 if arg.enum_.is_some() {
510 quote!(Argument::Uint(#arg_ident.to_raw()))
511 } else {
512 quote!(Argument::Uint(#arg_ident))
513 }
514 }
515 Type::Fixed => quote!(Argument::Fixed((#arg_ident * 256.) as i32)),
516 Type::String => {
517 if arg.allow_null {
518 quote! {
519 Argument::Str(unsafe {
520 ::std::ffi::CString::from_vec_unchecked(
521 #arg_ident.map(Into::into).unwrap_or_else(Vec::new),
522 )
523 })
524 }
525 } else {
526 quote! {
527 Argument::Str(unsafe {
528 ::std::ffi::CString::from_vec_unchecked(#arg_ident.into())
529 })
530 }
531 }
532 }
533 Type::Array => {
534 if arg.allow_null {
535 quote!(Argument::Array(#arg_ident.unwrap_or_else(Vec::new)))
536 } else {
537 quote!(Argument::Array(#arg_ident))
538 }
539 }
540 Type::Fd => quote!(Argument::Fd(#arg_ident)),
541 Type::NewId => {
542 if arg.interface.is_some() {
543 quote!(Argument::NewId(#arg_ident.id()))
544 } else {
545 quote! {
546 Argument::Str(unsafe {
547 ::std::ffi::CString::from_vec_unchecked(#arg_ident.0.into())
548 }),
549 Argument::Uint(#arg_ident.1),
550 Argument::NewId(#arg_ident.2.id())
551 }
552 }
553 }
554 Type::Object => {
555 if arg.allow_null {
556 quote!(Argument::Object(#arg_ident.map(|o| o.id()).unwrap_or(0)))
557 } else {
558 quote!(Argument::Object(#arg_ident.id()))
559 }
560 }
561 Type::Destructor => panic!("An argument cannot have type Destructor"),
562 }
563 });
564
565 quote!(#pattern => Message {
566 sender_id: sender_id,
567 opcode: #opcode_value,
568 args: vec![
569 #(#args_values,)*
570 ],
571 })
572 });
573
574 quote! {
575 match self {
576 #(#match_arms,)*
577 }
578 }
579 };
580
581 quote! {
582 pub enum #name {
583 #(#variants,)*
584 }
585
586 impl super::MessageGroup for #name {
587 const MESSAGES: &'static [super::MessageDesc] = &[
588 #(#message_array_values,)*
589 ];
590
591 type Map = super::#map_type;
592
593 fn is_destructor(&self) -> bool {
594 match *self {
595 #(#is_destructor_match_arms,)*
596 }
597 }
598
599 fn opcode(&self) -> u16 {
600 match *self {
601 #(#opcode_match_arms,)*
602 }
603 }
604
605 fn child<Meta: ObjectMetadata>(opcode: u16, version: u32, meta: &Meta) -> Option<Object<Meta>> {
606 match opcode {
607 #(#child_match_arms,)*
608 }
609 }
610
611 fn from_raw(msg: Message, map: &mut Self::Map) -> Result<Self, ()> {
612 #from_raw_body
613 }
614
615 fn into_raw(self, sender_id: u32) -> Message {
616 #into_raw_body
617 }
618
619 #addon
620 }
621 }
622 }
623
gen_interface( name: &Ident, low_name: &str, version: u32, addon: Option<TokenStream>, ) -> TokenStream624 pub(crate) fn gen_interface(
625 name: &Ident,
626 low_name: &str,
627 version: u32,
628 addon: Option<TokenStream>,
629 ) -> TokenStream {
630 let version_lit = Literal::u32_unsuffixed(version);
631
632 quote! {
633 pub struct #name;
634
635 impl Interface for #name {
636 type Request = Request;
637 type Event = Event;
638 const NAME: &'static str = #low_name;
639 const VERSION: u32 = #version_lit;
640
641 #addon
642 }
643 }
644 }
645
method_prototype<'a>(iname: &Ident, msg: &'a Message) -> (TokenStream, Option<&'a Arg>)646 pub fn method_prototype<'a>(iname: &Ident, msg: &'a Message) -> (TokenStream, Option<&'a Arg>) {
647 let mut it = msg.args.iter().filter(|arg| arg.typ == Type::NewId);
648 let newid = it.next();
649 assert!(
650 newid.is_none() || it.next().is_none(),
651 "Request {}.{} returns more than one new_id",
652 iname,
653 msg.name
654 );
655
656 let fn_name = Ident::new(
657 &format!("{}{}", if is_keyword(&msg.name) { "_" } else { "" }, msg.name),
658 Span::call_site(),
659 );
660
661 let mut args = Vec::new();
662
663 let generics = if let Some(arg) = newid {
664 if arg.interface.is_none() {
665 args.push(quote!(version: u32));
666 Some(quote!(T: Interface, F))
667 } else {
668 Some(quote!(F))
669 }
670 } else {
671 None
672 };
673
674 args.extend(msg.args.iter().filter_map(|arg| {
675 let arg_type_inner = if let Some(ref name) = arg.enum_ {
676 dotted_to_relname(name)
677 } else {
678 match arg.typ {
679 Type::Object => arg
680 .interface
681 .as_ref()
682 .map(|iface| {
683 let iface_mod = Ident::new(iface, Span::call_site());
684 let iface_type = Ident::new(&snake_to_camel(iface), Span::call_site());
685 quote!(&Proxy<super::#iface_mod::#iface_type>)
686 })
687 .unwrap_or(quote!(&Proxy<super::AnonymousObject>)),
688 Type::NewId => {
689 // client-side, the return-type handles that
690 return None;
691 }
692 _ => arg.typ.rust_type(),
693 }
694 };
695
696 let arg_name = Ident::new(
697 &format!("{}{}", if is_keyword(&arg.name) { "_" } else { "" }, arg.name),
698 Span::call_site(),
699 );
700
701 let arg_type = if arg.allow_null {
702 quote!(Option<#arg_type_inner>)
703 } else {
704 arg_type_inner
705 };
706
707 Some(quote!(#arg_name: #arg_type))
708 }));
709
710 if newid.is_some() {
711 args.push(quote!(implementor: F));
712 }
713
714 let (return_type, where_bounds) = if let Some(arg) = newid {
715 match arg.interface {
716 Some(ref iface) => {
717 let iface_mod = Ident::new(&iface, Span::call_site());
718 let iface_type = Ident::new(&snake_to_camel(&iface), Span::call_site());
719
720 (
721 quote!(Result<Proxy<super::#iface_mod::#iface_type>, ()>),
722 Some(quote! {
723 where F: FnOnce(
724 NewProxy<super::#iface_mod::#iface_type>,
725 ) -> Proxy<super::#iface_mod::#iface_type>
726 }),
727 )
728 }
729 None => (
730 quote!(Result<Proxy<T>, ()>),
731 Some(quote!(where F: FnOnce(NewProxy<T>) -> Proxy<T>)),
732 ),
733 }
734 } else {
735 (quote!(()), None)
736 };
737
738 let prototype = quote! {
739 fn #fn_name#(<#generics>)*(&self, #(#args),*) -> #return_type #where_bounds
740 };
741
742 (prototype, newid)
743 }
744
gen_client_methods(name: &Ident, messages: &[Message]) -> TokenStream745 pub(crate) fn gen_client_methods(name: &Ident, messages: &[Message]) -> TokenStream {
746 let methods = messages.iter().map(|msg| {
747 let mut docs = String::new();
748 if let Some((ref short, ref long)) = msg.description {
749 docs += &format!("{}\n\n{}\n", short, long);
750 }
751 if let Some(Type::Destructor) = msg.typ {
752 docs += "\nThis is a destructor, you cannot send requests to this object any longer once this method is called.";
753 }
754 if msg.since > 1 {
755 docs += &format!("\nOnly available since version {} of the interface.", msg.since);
756 }
757
758 let doc_attr = to_doc_attr(&docs);
759 let (proto, _) = method_prototype(name, &msg);
760
761 quote! {
762 #doc_attr
763 #proto;
764 }
765 });
766
767 let method_impls = messages.iter().map(|msg| {
768 let msg_name = Ident::new(&snake_to_camel(&msg.name), Span::call_site());
769 let (proto, return_type) = method_prototype(name, &msg);
770
771 let msg_init = if msg.args.is_empty() {
772 TokenStream::new()
773 } else {
774 let args = msg.args.iter().map(|arg| {
775 let arg_name = Ident::new(&arg.name, Span::call_site());
776 let arg_value = match arg.typ {
777 Type::NewId => {
778 if arg.interface.is_some() {
779 quote!(self.child_placeholder())
780 } else {
781 quote!((T::NAME.into(), version, self.child_placeholder()))
782 }
783 }
784 Type::Object => {
785 if arg.allow_null {
786 quote!(#arg_name.map(|o| o.clone()))
787 } else {
788 quote!(#arg_name.clone())
789 }
790 }
791 _ => quote!(#arg_name),
792 };
793
794 quote!(#arg_name: #arg_value)
795 });
796
797 quote!({ #(#args),* })
798 };
799
800 let send_stmt = match return_type {
801 Some(ret_type) if ret_type.interface.is_none() => {
802 quote!(self.send_constructor(msg, implementor, Some(version)))
803 }
804 Some(_) => quote!(self.send_constructor(msg, implementor, None)),
805 None => quote! {
806 self.send(msg);
807 },
808 };
809
810 quote! {
811 #proto {
812 let msg = Request::#msg_name #msg_init;
813 #send_stmt
814 }
815 }
816 });
817
818 quote! {
819 pub trait RequestsTrait {
820 #(#methods)*
821 }
822
823 impl RequestsTrait for Proxy<#name> {
824 #(#method_impls)*
825 }
826 }
827 }
828