Buttplug sex toy control library
at buttplug-6.1.0 284 lines 9.2 kB view raw
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(TryFromButtplugClientMessage)] 155pub fn try_from_buttplug_client_message_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 impl_try_from_buttplug_client_message_derive_macro(&ast) 161} 162 163fn impl_try_from_buttplug_client_message_derive_macro(ast: &syn::DeriveInput) -> TokenStream { 164 let name = &ast.ident; 165 if let syn::Data::Enum(ref e) = ast.data { 166 let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect(); 167 let gen = quote! { 168 impl TryFrom<ButtplugClientMessage> for #name { 169 type Error = &'static str; 170 171 fn try_from(msg: ButtplugClientMessage) -> Result<Self, &'static str> { 172 match msg { 173 #( ButtplugClientMessage::#idents(msg) => Ok(#name::#idents(msg)),)* 174 _ => Err("ButtplugClientMessage cannot be converted to #name") 175 } 176 } 177 } 178 179 impl From<#name> for ButtplugClientMessage { 180 fn from(msg: #name) -> ButtplugClientMessage { 181 match msg { 182 #( #name::#idents(msg) => ButtplugClientMessage::#idents(msg),)* 183 } 184 } 185 } 186 }; 187 gen.into() 188 } else { 189 panic!("TryFromButtplugClientMessage only works on structs"); 190 } 191} 192 193#[proc_macro_derive(TryFromButtplugServerMessage)] 194pub fn try_from_buttplug_out_message_derive(input: TokenStream) -> TokenStream { 195 // Construct a representation of Rust code as a syntax tree 196 // that we can manipulate 197 let ast = syn::parse(input).expect("Failure will cause compile failure."); 198 199 impl_try_from_buttplug_server_message_derive_macro(&ast) 200} 201 202fn impl_try_from_buttplug_server_message_derive_macro(ast: &syn::DeriveInput) -> TokenStream { 203 let name = &ast.ident; 204 if let syn::Data::Enum(ref e) = ast.data { 205 let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect(); 206 let gen = quote! { 207 impl TryFrom<ButtplugServerMessage> for #name { 208 type Error = ButtplugMessageError; 209 210 fn try_from(msg: ButtplugServerMessage) -> Result<Self, ButtplugMessageError> { 211 match msg { 212 #( ButtplugServerMessage::#idents(msg) => Ok(#name::#idents(msg.into())),)* 213 _ => Err(ButtplugMessageError::MessageConversionError("ButtplugServerMessage cannot be converted to #name".to_owned())) 214 } 215 } 216 } 217 }; 218 gen.into() 219 } else { 220 panic!("TryFromButtplugServerMessage only works on structs"); 221 } 222} 223 224#[proc_macro_derive(FromSpecificButtplugMessage)] 225pub fn from_specific_buttplug_message_derive(input: TokenStream) -> TokenStream { 226 // Construct a representation of Rust code as a syntax tree 227 // that we can manipulate 228 let ast = syn::parse(input).expect("Failure will cause compile failure."); 229 230 impl_from_specific_buttplug_message_derive_macro(&ast) 231} 232 233fn impl_from_specific_buttplug_message_derive_macro(ast: &syn::DeriveInput) -> TokenStream { 234 let name = &ast.ident; 235 if let syn::Data::Enum(ref e) = ast.data { 236 let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect(); 237 let gen = quote! { 238 #(impl From<#idents> for #name { 239 fn from(msg: #idents) -> #name { 240 #name::#idents(msg) 241 } 242 })* 243 }; 244 gen.into() 245 } else { 246 panic!("FromButtplugMessageUnion only works on structs"); 247 } 248} 249 250#[proc_macro_derive(ButtplugClientMessageType)] 251pub fn buttplug_client_message_type_derive(input: TokenStream) -> TokenStream { 252 // Construct a representation of Rust code as a syntax tree 253 // that we can manipulate 254 let ast = syn::parse(input).expect("Failure will cause compile failure."); 255 256 // Build the trait implementation 257 impl_buttplug_client_message_type_macro(&ast) 258} 259 260fn impl_buttplug_client_message_type_macro(ast: &syn::DeriveInput) -> TokenStream { 261 let name = &ast.ident; 262 let gen = quote! { 263 impl ButtplugClientMessageType for #name {} 264 }; 265 gen.into() 266} 267 268#[proc_macro_derive(ButtplugServerMessageType)] 269pub fn buttplug_server_message_type_derive(input: TokenStream) -> TokenStream { 270 // Construct a representation of Rust code as a syntax tree 271 // that we can manipulate 272 let ast = syn::parse(input).expect("Failure will cause compile failure."); 273 274 // Build the trait implementation 275 impl_buttplug_server_message_type_macro(&ast) 276} 277 278fn impl_buttplug_server_message_type_macro(ast: &syn::DeriveInput) -> TokenStream { 279 let name = &ast.ident; 280 let gen = quote! { 281 impl ButtplugServerMessageType for #name {} 282 }; 283 gen.into() 284}