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