add AccessLevel stuff to charactersheet trait

This commit is contained in:
Rusty Striker 2024-10-12 15:07:07 +03:00
parent 0eaffc9a8f
commit 473161674f
Signed by: RustyStriker
GPG key ID: 87E4D691632DFF15
5 changed files with 77 additions and 32 deletions

View file

@ -1,8 +1,8 @@
use proc_macro2::{Delimiter, Group, Span, TokenStream};
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{parse_macro_input, DeriveInput, Ident};
use syn::{parse_macro_input, Attribute, DeriveInput, Ident};
#[proc_macro_derive(CharacterSheet, attributes(Input, InputExpr, Field, FieldExpr, Seperator))]
#[proc_macro_derive(CharacterSheet, attributes(Input, InputExpr, Field, FieldExpr, Seperator, Access, AccessSet))]
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput);
let mut output = quote! {
@ -49,13 +49,21 @@ fn get_type_ident_set(ty: &syn::Type) -> Option<Ident> {
_ => panic!("Invalid data type"),
}
}
fn get_access_level(attrs: &Vec<Attribute>, ident: &str) -> Ident {
attrs.iter()
.find(|a| a.path.is_ident(ident))
.map(|a| a.parse_args().unwrap_or(None))
.flatten()
.unwrap_or(Ident::new(&"Owner", Span::call_site()))
}
fn impl_inputs(data: &syn::Data) -> TokenStream {
let mut output = TokenStream::new();
output.extend(quote! {
fn inputs(&self) -> Vec<(String, EntryType)>
fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)>
});
let mut items = TokenStream::new();
let mut count = 0_usize;
if let syn::Data::Struct(ds) = data {
if let syn::Fields::Named(fs) = &ds.fields {
for f in &fs.named {
@ -64,13 +72,17 @@ fn impl_inputs(data: &syn::Data) -> TokenStream {
if let Some(attr) = attr {
let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`");
let exp: Option<&syn::Attribute> = f.attrs.iter().find(|a| a.path.is_ident("InputExpr"));
let access = get_access_level(&f.attrs, "AccessSet");
count += 1;
if let Some(attr) = exp {
let exp: syn::Meta = attr.parse_meta().expect("Failed to parse MetaList!");
if let syn::Meta::List(l) = exp {
let from_input = &l.nested[1];
items.extend(quote! {
(#arg.to_string(), self.#from_input()),
})
if AccessLevel::#access.has_access(access) {
v.push((#arg.to_string(), self.#from_input()));
}
});
}
else {
panic!("Failed parsing InputExpr attribute, expected `(&mut self, EntryType), (&self) -> EntryType`");
@ -79,15 +91,18 @@ fn impl_inputs(data: &syn::Data) -> TokenStream {
else {
let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name));
items.extend(quote! {
(#arg.to_string(), EntryType::#t(self.#name.clone())),
if AccessLevel::#access.has_access(access) {
v.push((#arg.to_string(), EntryType::#t(self.#name.clone())));
}
});
}
}
}
}
}
let mut vec = quote! { Vec::from };
vec.append(Group::new(Delimiter::Parenthesis, Group::new(Delimiter::Bracket, items).to_token_stream()));
let mut vec = quote! { let mut v = Vec::with_capacity(#count); };
vec.extend(items);
vec.extend(quote! { v });
output.append(Group::new(Delimiter::Brace, vec));
output
@ -159,13 +174,14 @@ fn impl_fields(data: &syn::Data) -> TokenStream {
fn impl_get(data: &syn::Data) -> TokenStream {
let mut output = TokenStream::new();
output.extend(quote! {
fn get(&self, entry: &str) -> Option<EntryType>
fn get(&self, entry: &str, access: AccessLevel) -> Option<EntryType>
});
let mut match_hands = TokenStream::new();
if let syn::Data::Struct(ds) = data {
if let syn::Fields::Named(fs) = &ds.fields {
for f in &fs.named {
let name = f.ident.clone().unwrap();
let access = get_access_level(&f.attrs, "Access");
let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input"));
if let Some(attr) = input_attr {
let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`");
@ -175,7 +191,7 @@ fn impl_get(data: &syn::Data) -> TokenStream {
if let syn::Meta::List(l) = exp {
let from_input = &l.nested[1];
match_hands.extend(quote! {
#arg => Some(self.#from_input()),
#arg => if AccessLevel::#access.has_access(access) { Some(self.#from_input()) } else { None },
});
}
else {
@ -185,7 +201,7 @@ fn impl_get(data: &syn::Data) -> TokenStream {
else {
let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name));
match_hands.extend(quote! {
#arg => Some(EntryType::#t(self.#name.clone())),
#arg => if AccessLevel::#access.has_access(access) { Some(EntryType::#t(self.#name.clone())) } else { None },
});
}
}
@ -197,13 +213,13 @@ fn impl_get(data: &syn::Data) -> TokenStream {
if let Some(exp) = field_expr {
let exp: syn::Expr = exp.parse_args().expect("Invalid expression");
match_hands.extend(quote! {
#arg => Some(EntryType::Number(#exp)),
#arg => if AccessLevel::#access.has_access(access) { Some(EntryType::Number(#exp)) } else { None },
})
}
else {
// No expression, guess we just push this and nothing special (should prob be an input but mehhh)
match_hands.extend(quote! {
#arg => Some(EntryType::#t(self.#name.clone())),
#arg => if AccessLevel::#access.has_access(access) { Some(EntryType::#t(self.#name.clone())) } else { None },
});
}
}
@ -221,7 +237,7 @@ fn impl_get(data: &syn::Data) -> TokenStream {
fn impl_set(data: &syn::Data) -> TokenStream {
let mut output = TokenStream::new();
output.extend(quote! {
fn set(&mut self, entry: &str, value: EntryType)
fn set(&mut self, entry: &str, value: EntryType, access: AccessLevel)
});
let mut match_hands = TokenStream::new();
@ -230,6 +246,7 @@ fn impl_set(data: &syn::Data) -> TokenStream {
for f in &fs.named {
let name = f.ident.clone().unwrap();
let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input"));
let access = get_access_level(&f.attrs, "AccessSet");
if let Some(attr) = input_attr {
let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`");
let exp = f.attrs.iter().find(|a| a.path.is_ident("InputExpr"));
@ -238,7 +255,7 @@ fn impl_set(data: &syn::Data) -> TokenStream {
if let syn::Meta::List(l) = exp {
let to_input = &l.nested[0];
match_hands.extend(quote! {
#arg => self.#to_input(value),
#arg => if AccessLevel::#access.has_access(access) { self.#to_input(value) },
});
}
else {
@ -248,7 +265,7 @@ fn impl_set(data: &syn::Data) -> TokenStream {
else {
let t = get_type_ident_set(&f.ty).expect(&format!("Invalid type for input: {}", name));
match_hands.extend(quote! {
#arg => self.#name = value.#t(),
#arg => if AccessLevel::#access.has_access(access) { self.#name = value.#t() },
});
}
}
@ -266,17 +283,20 @@ fn impl_set(data: &syn::Data) -> TokenStream {
fn impl_display(data: &syn::Data) -> TokenStream {
let mut output = TokenStream::new();
output.extend(quote! {
fn display(&self) -> Vec<Option<(String, EntryType)>>
fn display(&self, access: AccessLevel) -> Vec<Option<(String, EntryType)>>
});
let mut items = TokenStream::new();
let mut count = 0_usize;
if let syn::Data::Struct(ds) = data {
if let syn::Fields::Named(fs) = &ds.fields {
for f in &fs.named {
let name = f.ident.clone().unwrap();
if f.attrs.iter().any(|a| a.path.is_ident("Seperator")) {
items.extend(quote! { None, })
items.extend(quote! { v.push(None); })
}
let access = get_access_level(&f.attrs, "Access");
count += 1;
let input_attr = f.attrs.iter().find(|a| a.path.is_ident("Input"));
if let Some(attr) = input_attr {
let arg: syn::LitStr = attr.parse_args().expect("No arguments supplied for Input attribute, usage: `Input(\"Name\")`");
@ -286,7 +306,9 @@ fn impl_display(data: &syn::Data) -> TokenStream {
if let syn::Meta::List(l) = exp {
let from_input = &l.nested[1];
items.extend(quote! {
Some((#arg.to_string(), self.#from_input())),
if AccessLevel::#access.has_access(access) {
v.push(Some((#arg.to_string(), self.#from_input())));
}
})
}
else {
@ -296,7 +318,9 @@ fn impl_display(data: &syn::Data) -> TokenStream {
else {
let t = get_type_ident(&f.ty).expect(&format!("Invalid type for input: {}", name));
items.extend(quote! {
Some((#arg.to_string(), EntryType::#t(self.#name.clone()))),
if AccessLevel::#access.has_access(access) {
Some((#arg.to_string(), EntryType::#t(self.#name.clone())));
}
});
}
}
@ -308,13 +332,17 @@ fn impl_display(data: &syn::Data) -> TokenStream {
if let Some(exp) = field_expr {
let exp: syn::Expr = exp.parse_args().expect("Invalid expression");
items.extend(quote! {
Some((#arg.to_string(), EntryType::Number(#exp))),
if AccessLevel::#access.has_access(access) {
Some((#arg.to_string(), EntryType::Number(#exp)));
}
})
}
else {
// No expression, guess we just push this and nothing special (should prob be an input but mehhh)
items.extend(quote! {
Some((#arg.to_string(), EntryType::#t(self.#name.clone()))),
if AccessLevel::#access.has_access(access) {
Some((#arg.to_string(), EntryType::#t(self.#name.clone())));
}
});
}
@ -322,8 +350,9 @@ fn impl_display(data: &syn::Data) -> TokenStream {
}
}
}
let mut vec = quote! { Vec::from };
vec.append(Group::new(Delimiter::Parenthesis, Group::new(Delimiter::Bracket, items).to_token_stream()));
let mut vec = quote! { let mut v = Vec::with_capacity(#count); };
vec.extend( items);
vec.extend(quote! { v });
output.append(Group::new(Delimiter::Brace, vec));
output