1 use std::cmp;
2 use std::iter::repeat;
3 
4 use proc_macro2::{Ident, Literal, Span, TokenStream};
5 
6 use protocol::*;
7 use util::null_terminated_byte_string_literal;
8 
generate_interfaces_prefix(protocol: &Protocol) -> TokenStream9 pub(crate) fn generate_interfaces_prefix(protocol: &Protocol) -> TokenStream {
10     let longest_nulls = protocol.interfaces.iter().fold(0, |max, interface| {
11         let request_longest_null = interface.requests.iter().fold(0, |max, request| {
12             if request.all_null() {
13                 cmp::max(request.args.len(), max)
14             } else {
15                 max
16             }
17         });
18         let events_longest_null = interface.events.iter().fold(0, |max, event| {
19             if event.all_null() {
20                 cmp::max(event.args.len(), max)
21             } else {
22                 max
23             }
24         });
25         cmp::max(max, cmp::max(request_longest_null, events_longest_null))
26     });
27 
28     let types_null_len = Literal::usize_unsuffixed(longest_nulls);
29 
30     let nulls = repeat(quote!(NULLPTR as *const sys::common::wl_interface)).take(longest_nulls);
31 
32     quote! {
33         use std::os::raw::{c_char, c_void};
34 
35         const NULLPTR: *const c_void = 0 as *const c_void;
36         static mut types_null: [*const sys::common::wl_interface; #types_null_len] = [
37             #(#nulls,)*
38         ];
39     }
40 }
41 
generate_interface(interface: &Interface) -> TokenStream42 pub(crate) fn generate_interface(interface: &Interface) -> TokenStream {
43     let requests = gen_messages(interface, &interface.requests, "requests");
44     let events = gen_messages(interface, &interface.events, "events");
45 
46     let interface_ident = Ident::new(&format!("{}_interface", interface.name), Span::call_site());
47     let name_value = null_terminated_byte_string_literal(&interface.name);
48     let version_value = Literal::i32_unsuffixed(interface.version as i32);
49     let request_count_value = Literal::i32_unsuffixed(interface.requests.len() as i32);
50     let requests_value = if interface.requests.is_empty() {
51         quote!(NULLPTR as *const wl_message)
52     } else {
53         let requests_ident = Ident::new(&format!("{}_requests", interface.name), Span::call_site());
54         quote!(unsafe { &#requests_ident as *const _ })
55     };
56     let event_count_value = Literal::i32_unsuffixed(interface.events.len() as i32);
57     let events_value = if interface.events.is_empty() {
58         quote!(NULLPTR as *const wl_message)
59     } else {
60         let events_ident = Ident::new(&format!("{}_events", interface.name), Span::call_site());
61         quote!(unsafe { &#events_ident as *const _ })
62     };
63 
64     quote!(
65         #requests
66         #events
67 
68         /// C representation of this interface, for interop
69         pub static mut #interface_ident: wl_interface = wl_interface {
70             name: #name_value as *const u8 as *const c_char,
71             version: #version_value,
72             request_count: #request_count_value,
73             requests: #requests_value,
74             event_count: #event_count_value,
75             events: #events_value,
76         };
77     )
78 }
79 
gen_messages(interface: &Interface, messages: &[Message], which: &str) -> TokenStream80 fn gen_messages(interface: &Interface, messages: &[Message], which: &str) -> TokenStream {
81     if messages.is_empty() {
82         return TokenStream::new();
83     }
84 
85     let types_arrays = messages.iter().filter_map(|msg| {
86         if msg.all_null() {
87             None
88         } else {
89             let array_ident = Ident::new(
90                 &format!("{}_{}_{}_types", interface.name, which, msg.name),
91                 Span::call_site(),
92             );
93             let array_len = Literal::usize_unsuffixed(msg.args.len());
94             let array_values = msg.args.iter().map(|arg| match (arg.typ, &arg.interface) {
95                 (Type::Object, &Some(ref inter)) | (Type::NewId, &Some(ref inter)) => {
96                     let module = Ident::new(inter, Span::call_site());
97                     let interface_ident = Ident::new(&format!("{}_interface", inter), Span::call_site());
98                     quote!(unsafe { &super::#module::#interface_ident as *const wl_interface })
99                 }
100                 _ => quote!(NULLPTR as *const wl_interface),
101             });
102 
103             Some(quote! {
104                 static mut #array_ident: [*const wl_interface; #array_len] = [
105                     #(#array_values,)*
106                 ];
107             })
108         }
109     });
110 
111     let message_array_ident = Ident::new(&format!("{}_{}", interface.name, which), Span::call_site());
112     let message_array_len = Literal::usize_unsuffixed(messages.len());
113     let message_array_values = messages.iter().map(|msg| {
114         let name_value = null_terminated_byte_string_literal(&msg.name);
115         let signature_value = Literal::byte_string(&message_signature(msg));
116 
117         let types_ident = if msg.all_null() {
118             Ident::new("types_null", Span::call_site())
119         } else {
120             Ident::new(
121                 &format!("{}_{}_{}_types", interface.name, which, msg.name),
122                 Span::call_site(),
123             )
124         };
125 
126         quote! {
127             wl_message {
128                 name: #name_value as *const u8 as *const c_char,
129                 signature: #signature_value as *const u8 as *const c_char,
130                 types: unsafe { &#types_ident as *const _ },
131             }
132         }
133     });
134 
135     quote! {
136         #(#types_arrays)*
137 
138         /// C-representation of the messages of this interface, for interop
139         pub static mut #message_array_ident: [wl_message; #message_array_len] = [
140             #(#message_array_values,)*
141         ];
142     }
143 }
144 
message_signature(msg: &Message) -> Vec<u8>145 fn message_signature(msg: &Message) -> Vec<u8> {
146     let mut res = Vec::new();
147 
148     if msg.since > 1 {
149         res.extend_from_slice(msg.since.to_string().as_bytes());
150     }
151 
152     for arg in &msg.args {
153         if arg.typ.nullable() && arg.allow_null {
154             res.push(b'?');
155         }
156         match arg.typ {
157             Type::NewId => {
158                 if arg.interface.is_none() {
159                     res.extend_from_slice(b"su");
160                 }
161                 res.push(b'n');
162             }
163             Type::Uint => res.push(b'u'),
164             Type::Fixed => res.push(b'f'),
165             Type::String => res.push(b's'),
166             Type::Object => res.push(b'o'),
167             Type::Array => res.push(b'a'),
168             Type::Fd => res.push(b'h'),
169             Type::Int => res.push(b'i'),
170             _ => {}
171         }
172     }
173 
174     res.push(0);
175     res
176 }
177