Something went wrong. Try again.
Buttplug sex toy control library
Something went wrong. Try again.
6.9 kB · 219 lines
Rust
at dev
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220// Buttplug Rust Source Code File - See https://buttplug.io for more info.//// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved.//// Licensed under the BSD 3-Clause license. See LICENSE file in the project root// for full license information.
extern crate proc_macro;
use proc_macro::TokenStream;use quote::quote;
#[proc_macro_derive(ButtplugMessage)]pub fn buttplug_message_derive(input: TokenStream) -> TokenStream { // Construct a representation of Rust code as a syntax tree // that we can manipulate let ast = syn::parse(input).expect("Failure will cause compile failure.");
// Build the trait implementation impl_buttplug_message_macro(&ast)}
fn impl_buttplug_message_macro(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident;
match ast.data { syn::Data::Enum(ref e) => { let idents = e.variants.iter().map(|x| x.ident.clone()); let idents2 = idents.clone(); let r#gen = quote! { impl ButtplugMessage for #name { fn id(&self) -> u32 { match self { #( #name::#idents(ref msg) => msg.id(),)*
} } fn set_id(&mut self, id: u32) { match self { #( #name::#idents2(ref mut msg) => msg.set_id(id),)* } } } }; r#gen.into() } syn::Data::Struct(_) => { let r#gen = quote! { impl ButtplugMessage for #name { fn id(&self) -> u32 { self.id }
fn set_id(&mut self, id: u32) { self.id = id; } } }; r#gen.into() } _ => panic!("Derivation only works on structs and enums"), }}
#[proc_macro_derive(ButtplugDeviceMessage)]pub fn buttplug_device_message_derive(input: TokenStream) -> TokenStream { // Construct a representation of Rust code as a syntax tree // that we can manipulate let ast = syn::parse(input).expect("Failure will cause compile failure.");
let mut tokens = impl_buttplug_message_macro(&ast); tokens.extend(impl_buttplug_device_message_macro(&ast)); tokens}
fn impl_buttplug_device_message_macro(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; match ast.data { syn::Data::Enum(ref e) => { let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect(); let r#gen = quote! { impl ButtplugDeviceMessage for #name { fn device_index(&self) -> u32 { match self { #( #name::#idents(ref msg) => msg.device_index(),)*
} } fn set_device_index(&mut self, id: u32) { match self { #( #name::#idents(ref mut msg) => msg.set_device_index(id),)* } } } }; r#gen.into() } syn::Data::Struct(_) => { let r#gen = quote! { impl ButtplugDeviceMessage for #name { fn device_index(&self) -> u32 { self.device_index }
fn set_device_index(&mut self, id: u32) { self.device_index = id; } } }; r#gen.into() } _ => panic!("Derivation only works on structs and enums"), }}
#[proc_macro_derive(ButtplugMessageValidator)]pub fn buttplug_message_validator_derive(input: TokenStream) -> TokenStream { // Construct a representation of Rust code as a syntax tree // that we can manipulate let ast = syn::parse(input).expect("Failure will cause compile failure.");
// Build the trait implementation impl_buttplug_message_validator_macro(&ast)}
fn impl_buttplug_message_validator_macro(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident;
match &ast.data { syn::Data::Enum(e) => { let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect(); let r#gen = quote! { impl ButtplugMessageValidator for #name { fn is_valid(&self) -> Result<(), ButtplugMessageError> { match self { #( #name::#idents(msg) => msg.is_valid(), )* } } } }; r#gen.into() } syn::Data::Struct(_) => { let r#gen = quote! { impl ButtplugMessageValidator for #name { } }; r#gen.into() } _ => panic!("Derivation only works on structs and enums"), }}
#[proc_macro_derive(ButtplugMessageFinalizer)]pub fn buttplug_message_finalizer_derive(input: TokenStream) -> TokenStream { // Construct a representation of Rust code as a syntax tree // that we can manipulate let ast = syn::parse(input).expect("Failure will cause compile failure.");
// Build the trait implementation impl_buttplug_message_finalizer_macro(&ast)}
fn impl_buttplug_message_finalizer_macro(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident;
match &ast.data { syn::Data::Enum(_) => { let r#gen = quote! { impl ButtplugMessageFinalizer for #name {} }; r#gen.into() } syn::Data::Struct(_) => { let r#gen = quote! { impl ButtplugMessageFinalizer for #name {} }; r#gen.into() } _ => panic!("Derivation only works on structs and enums"), }}
#[proc_macro_derive(FromSpecificButtplugMessage)]pub fn from_specific_buttplug_message_derive(input: TokenStream) -> TokenStream { // Construct a representation of Rust code as a syntax tree // that we can manipulate let ast = syn::parse(input).expect("Failure will cause compile failure.");
impl_from_specific_buttplug_message_derive_macro(&ast)}
fn impl_from_specific_buttplug_message_derive_macro(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; if let syn::Data::Enum(ref e) = ast.data { let idents: Vec<_> = e.variants.iter().map(|x| x.ident.clone()).collect(); // Unlike try_from, where we expect all of our field identifiers to match, we may have different // identifiers and field types when implementing from_specific. Therefore we need to parallel // iterate our field identifiers and the identifier of the first member. This means we're locked // to an enum style of field name([unnamed type]), but we're the only ones who use this macro, // and on structs that almost never change, so hopefully leaving this comment will be enough. let mut fields: Vec<_> = vec![]; for var in e.variants.iter() { for field in var.fields.iter() { fields.push(field.ty.clone()); } } let r#gen = quote! { #(impl From<#fields> for #name { fn from(msg: #fields) -> #name { #name::#idents(msg) } })* }; r#gen.into() } else { panic!("FromButtplugMessageUnion only works on structs"); }}