use proc_macro2::Span;
use quote::{
quote,
ToTokens
};
use syn::{
parse::{
ParseStream,
Parse
},
Result,
DeriveInput,
Ident,
Data::{
Struct,
Enum,
Union
},
DataStruct,
FieldsNamed
};
use super::StructField;
pub struct Object{
name: Option<Ident>,
struct_fields: Vec<StructField>,
}
impl Object{
pub fn new() -> Self{
Self::default()
}
pub fn handle_input(&mut self, input: DeriveInput) {
self.handle_object_name(&input);
self.handle_object_data(&input);
}
fn handle_object_name(&mut self, input: &DeriveInput){
self.name = Some(input.ident.clone());
}
fn handle_object_data(&mut self, input: &DeriveInput){
let struct_fields: Vec<StructField> = match &input.data {
Struct(struct_object) => Self::handle_struct_object(struct_object),
Enum(_enum_object) => Vec::new(),
Union(_union_object) => Vec::new(),
};
self.struct_fields = struct_fields;
}
fn handle_struct_object(input: &DataStruct) -> Vec<StructField>{
match &input.fields{
syn::Fields::Named(named_fields) => Self::handle_named_fields(named_fields),
syn::Fields::Unnamed(_) => Vec::new(),
syn::Fields::Unit => Vec::new(),
}
}
fn handle_named_fields(named_fields: &FieldsNamed) -> Vec<StructField> {
let mut struct_fields: Vec<StructField> = Vec::new();
for field in &named_fields.named{
let struct_field = StructField::parse(field);
match struct_field{
Some(struct_field) => struct_fields.push(struct_field),
None => (),
}
};
struct_fields
}
}
impl Parse for Object {
fn parse(input: ParseStream) -> Result<Self> {
let parsed: DeriveInput = input.parse()?;
let mut object = Object::new();
object.handle_input(parsed);
Ok(object)
}
}
impl ToTokens for Object{
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let name = self.name.as_ref().unwrap();
let fields= Ident::new("__regi_n", Span::call_site());
let struct_fields_iter = self.struct_fields.iter().map(|struct_field|{
let name = struct_field.name.to_string();
quote!{
#fields.push(format!("\"{}\":\"{}\"", #name, &self.#struct_field));
}
});
tokens.extend(
quote!{
impl #name{
fn get_fields(&self) -> std::vec::Vec::<String>{
let mut #fields: std::vec::Vec::<String> = std::vec::Vec::new();
#(#struct_fields_iter)*;
#fields
}
}
impl Object for &#name{
fn stringify(&self) -> String{
let string = format!("{{{}}}", self.get_fields().join(","));
string
}
}
impl Object for #name{
fn stringify(&self) -> String{
let string = format!("{{{}}}", self.get_fields().join(","));
string
}
}
})
}
}
impl Default for Object{
fn default() -> Self {
Self {
name: None,
struct_fields: Vec::new()
}
}
}