Buttplug sex toy control library
1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5
6#[proc_macro_derive(ButtplugMessage)]
7pub fn buttplug_message_derive(input: TokenStream) -> TokenStream {
8 // Construct a representation of Rust code as a syntax tree
9 // that we can manipulate
10 let ast = syn::parse(input).expect("Failure will cause compile failure.");
11
12 // Build the trait implementation
13 impl_buttplug_message_macro(&ast)
14}
15
16fn impl_buttplug_message_macro(ast: &syn::DeriveInput) -> TokenStream {
17 let name = &ast.ident;
18
19 match ast.data {
20 syn::Data::Enum(ref e) => {
21 let idents = e.variants.iter().map(|x| x.ident.clone());
22 let idents2 = idents.clone();
23 let gen = quote! {
24 impl ButtplugMessage for #name {
25 fn id(&self) -> u32 {
26 match self {
27 #( #name::#idents(ref msg) => msg.id(),)*
28
29 }
30 }
31 fn set_id(&mut self, id: u32) {
32 match self {
33 #( #name::#idents2(ref mut msg) => msg.set_id(id),)*
34 }
35 }
36 }
37 };
38 gen.into()
39 }
40 syn::Data::Struct(_) => {
41 let gen = quote! {
42 impl ButtplugMessage for #name {
43 fn id(&self) -> u32 {
44 self.id
45 }
46
47 fn set_id(&mut self, id: u32) {
48 self.id = id;
49 }
50 }
51 };
52 gen.into()
53 }
54 _ => panic!("Derivation only works on structs and enums"),
55 }
56}
57
58#[proc_macro_derive(ButtplugDeviceMessage)]
59pub fn buttplug_device_message_derive(input: TokenStream) -> TokenStream {
60 // Construct a representation of Rust code as a syntax tree
61 // that we can manipulate
62 let ast = syn::parse(input).expect("Failure will cause compile failure.");
63
64 let mut tokens = impl_buttplug_message_macro(&ast);
65 tokens.extend(impl_buttplug_device_message_macro(&ast));
66 tokens
67}
68
69fn impl_buttplug_device_message_macro(ast: &syn::DeriveInput) -> TokenStream {
70 let name = &ast.ident;
71 match ast.data {
72 syn::Data::Enum(ref e) => {
73 let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect();
74 let gen = quote! {
75 impl ButtplugDeviceMessage for #name {
76 fn device_index(&self) -> u32 {
77 match self {
78 #( #name::#idents(ref msg) => msg.device_index(),)*
79
80 }
81 }
82 fn set_device_index(&mut self, id: u32) {
83 match self {
84 #( #name::#idents(ref mut msg) => msg.set_device_index(id),)*
85 }
86 }
87 }
88 };
89 gen.into()
90 }
91 syn::Data::Struct(_) => {
92 let gen = quote! {
93 impl ButtplugDeviceMessage for #name {
94 fn device_index(&self) -> u32 {
95 self.device_index
96 }
97
98 fn set_device_index(&mut self, id: u32) {
99 self.device_index = id;
100 }
101 }
102 };
103 gen.into()
104 }
105 _ => panic!("Derivation only works on structs and enums"),
106 }
107}
108
109#[proc_macro_derive(ButtplugMessageValidator)]
110pub fn buttplug_message_validator_derive(input: TokenStream) -> TokenStream {
111 // Construct a representation of Rust code as a syntax tree
112 // that we can manipulate
113 let ast = syn::parse(input).expect("Failure will cause compile failure.");
114
115 // Build the trait implementation
116 impl_buttplug_message_validator_macro(&ast)
117}
118
119fn impl_buttplug_message_validator_macro(ast: &syn::DeriveInput) -> TokenStream {
120 let name = &ast.ident;
121
122 match &ast.data {
123 syn::Data::Enum(e) => {
124 let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect();
125 let gen = quote! {
126 impl ButtplugMessageValidator for #name {
127 fn is_valid(&self) -> Result<(), ButtplugMessageError> {
128 match self {
129 #( #name::#idents(msg) => msg.is_valid(), )*
130 }
131 }
132 }
133 };
134 gen.into()
135 }
136 syn::Data::Struct(_) => {
137 let gen = quote! {
138 impl ButtplugMessageValidator for #name {
139 }
140 };
141 gen.into()
142 }
143 _ => panic!("Derivation only works on structs and enums"),
144 }
145}
146
147#[proc_macro_derive(TryFromButtplugClientMessage)]
148pub fn try_from_buttplug_client_message_derive(input: TokenStream) -> TokenStream {
149 // Construct a representation of Rust code as a syntax tree
150 // that we can manipulate
151 let ast = syn::parse(input).expect("Failure will cause compile failure.");
152
153 impl_try_from_buttplug_client_message_derive_macro(&ast)
154}
155
156fn impl_try_from_buttplug_client_message_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
157 let name = &ast.ident;
158 if let syn::Data::Enum(ref e) = ast.data {
159 let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect();
160 let gen = quote! {
161 impl TryFrom<ButtplugClientMessage> for #name {
162 type Error = &'static str;
163
164 fn try_from(msg: ButtplugClientMessage) -> Result<Self, &'static str> {
165 match msg {
166 #( ButtplugClientMessage::#idents(msg) => Ok(#name::#idents(msg)),)*
167 _ => Err("ButtplugClientMessage cannot be converted to #name")
168 }
169 }
170 }
171
172 impl From<#name> for ButtplugClientMessage {
173 fn from(msg: #name) -> ButtplugClientMessage {
174 match msg {
175 #( #name::#idents(msg) => ButtplugClientMessage::#idents(msg),)*
176 }
177 }
178 }
179 };
180 gen.into()
181 } else {
182 panic!("TryFromButtplugClientMessage only works on structs");
183 }
184}
185
186#[proc_macro_derive(TryFromButtplugServerMessage)]
187pub fn try_from_buttplug_out_message_derive(input: TokenStream) -> TokenStream {
188 // Construct a representation of Rust code as a syntax tree
189 // that we can manipulate
190 let ast = syn::parse(input).expect("Failure will cause compile failure.");
191
192 impl_try_from_buttplug_server_message_derive_macro(&ast)
193}
194
195fn impl_try_from_buttplug_server_message_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
196 let name = &ast.ident;
197 if let syn::Data::Enum(ref e) = ast.data {
198 let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect();
199 let gen = quote! {
200 impl TryFrom<ButtplugServerMessage> for #name {
201 type Error = ButtplugMessageError;
202
203 fn try_from(msg: ButtplugServerMessage) -> Result<Self, ButtplugMessageError> {
204 match msg {
205 #( ButtplugServerMessage::#idents(msg) => Ok(#name::#idents(msg.into())),)*
206 _ => Err(ButtplugMessageError::MessageConversionError("ButtplugServerMessage cannot be converted to #name".to_owned()))
207 }
208 }
209 }
210 };
211 gen.into()
212 } else {
213 panic!("TryFromButtplugServerMessage only works on structs");
214 }
215}
216
217#[proc_macro_derive(FromSpecificButtplugMessage)]
218pub fn from_specific_buttplug_message_derive(input: TokenStream) -> TokenStream {
219 // Construct a representation of Rust code as a syntax tree
220 // that we can manipulate
221 let ast = syn::parse(input).expect("Failure will cause compile failure.");
222
223 impl_from_specific_buttplug_message_derive_macro(&ast)
224}
225
226fn impl_from_specific_buttplug_message_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
227 let name = &ast.ident;
228 if let syn::Data::Enum(ref e) = ast.data {
229 let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect();
230 let gen = quote! {
231 #(impl From<#idents> for #name {
232 fn from(msg: #idents) -> #name {
233 #name::#idents(msg)
234 }
235 })*
236 };
237 gen.into()
238 } else {
239 panic!("FromButtplugMessageUnion only works on structs");
240 }
241}
242
243#[proc_macro_derive(ButtplugClientMessageType)]
244pub fn buttplug_client_message_type_derive(input: TokenStream) -> TokenStream {
245 // Construct a representation of Rust code as a syntax tree
246 // that we can manipulate
247 let ast = syn::parse(input).expect("Failure will cause compile failure.");
248
249 // Build the trait implementation
250 impl_buttplug_client_message_type_macro(&ast)
251}
252
253fn impl_buttplug_client_message_type_macro(ast: &syn::DeriveInput) -> TokenStream {
254 let name = &ast.ident;
255 let gen = quote! {
256 impl ButtplugClientMessageType for #name {}
257 };
258 gen.into()
259}
260
261#[proc_macro_derive(ButtplugServerMessageType)]
262pub fn buttplug_server_message_type_derive(input: TokenStream) -> TokenStream {
263 // Construct a representation of Rust code as a syntax tree
264 // that we can manipulate
265 let ast = syn::parse(input).expect("Failure will cause compile failure.");
266
267 // Build the trait implementation
268 impl_buttplug_server_message_type_macro(&ast)
269}
270
271fn impl_buttplug_server_message_type_macro(ast: &syn::DeriveInput) -> TokenStream {
272 let name = &ast.ident;
273 let gen = quote! {
274 impl ButtplugServerMessageType for #name {}
275 };
276 gen.into()
277}
278
279#[proc_macro_derive(ButtplugProtocolProperties)]
280pub fn buttplug_protocol_properties_derive(input: TokenStream) -> TokenStream {
281 // Construct a representation of Rust code as a syntax tree
282 // that we can manipulate
283 let ast = syn::parse(input).expect("Failure will cause compile failure.");
284
285 // Build the trait implementation
286 impl_buttplug_protocol_properties_macro(&ast)
287}
288
289fn impl_buttplug_protocol_properties_macro(ast: &syn::DeriveInput) -> TokenStream {
290 let name = &ast.ident;
291 let gen = quote! {
292 impl ButtplugProtocolProperties for #name {
293 fn name(&self) -> &str {
294 &self.name
295 }
296
297 fn message_attributes(&self) -> DeviceMessageAttributesMap {
298 self.message_attributes.clone()
299 }
300
301 fn stop_commands(&self) -> Vec<ButtplugDeviceCommandMessageUnion> {
302 self.stop_commands.clone()
303 }
304 }
305 };
306 gen.into()
307}