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}