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