use quote::{quote, ToTokens};
use syn::{
parse_quote, punctuated::Punctuated, FieldsNamed, FnArg, Generics, Ident, ImplItem, ItemImpl,
ItemStruct, Visibility, parse_str, GenericParam};
use crate::helpers::{
full_base_struct_name, get_mut_guard_name, get_ref_guard_name, to_token_stream, filter_generics,
};
pub fn generation_help_strutures_and_impls(wrapper: &ItemStruct) -> proc_macro2::TokenStream {
let mut wsn = wrapper.ident.to_string();
let mut bsn = full_base_struct_name(wsn.clone());
let bfn = crate::helpers::BASE_FIELD_NAME.to_string();
let mut generics = "".to_string();
let mut filted_generics = "".to_string();
let mut impl_generics = "".to_string();
if wrapper.generics.params.len() > 0 {
filted_generics = crate::helpers::filter_generics(&wrapper
.generics)
.params
.clone()
.into_token_stream()
.to_string();
generics = wrapper
.generics
.params
.clone()
.into_token_stream()
.to_string();
impl_generics = format!("<{generics}>");
bsn = format!("{bsn}<{filted_generics}>");
wsn = format!("{wsn}<{filted_generics}>");
}
let ref_guard_name = get_ref_guard_name(&wrapper.ident.to_string());
let mut_guard_name = get_mut_guard_name(&wrapper.ident.to_string());
let wsn = to_token_stream(wsn);
let bsn = to_token_stream(bsn);
let bfn = to_token_stream(bfn);
let generics = to_token_stream(generics);
let full_ref_guard_name = to_token_stream(format!("{ref_guard_name}<'a,TField,{generics}>"));
let filter_ref_guard_name = to_token_stream(format!("{ref_guard_name}<'a,TField,{filted_generics}>",));
let full_mut_guard_name = to_token_stream(format!("{mut_guard_name}<'a,TField,{generics}>"));
let filter_mut_guard_name = to_token_stream(format!("{mut_guard_name}<'a,TField,{filted_generics}>",));
let impl_generics = to_token_stream(impl_generics);
quote::quote! {
impl #impl_generics #wsn{
pub fn extract(&self) -> #bsn {
self.clone().into()
}
}
impl #impl_generics From<#wsn> for #bsn {
fn from(wrapper: #wsn) -> Self {
let guard = wrapper.#bfn.write().unwrap();
let ptr = &*guard as *const #bsn;
let reply = unsafe { std::ptr::read(ptr) };
drop(guard);
return reply;
}
}
impl<'a,#generics> From<#bsn> for #wsn{
fn from(#bfn: #bsn) -> Self {
return Self {
#bfn: Arc::new(RwLock::new(#bfn))
};
}
}
impl #impl_generics PartialEq for #wsn{
fn eq(&self, other: &Self) -> bool {
let ptr_number = self.#bfn.as_ref() as *const RwLock<#bsn> as usize;
let other_ptr_number = other.#bfn.as_ref() as *const RwLock<#bsn> as usize;
return ptr_number == other_ptr_number;
}
}
impl #impl_generics Clone for #wsn{
fn clone(&self) -> Self {
return Self { #bfn: self.#bfn.clone() };
}
}
unsafe impl #impl_generics Send for #wsn{}
unsafe impl #impl_generics Sync for #wsn{}
impl #impl_generics #wsn{
fn into_vec_wrapper(bases : Vec<#bsn>) -> Vec<#wsn>{
bases.into_iter().map(|b| b.into()).collect()
}
fn into_vec_base(multiples : Vec<#wsn>) -> Vec<#bsn>{
multiples.iter().map(|w| (*w).clone().into()).collect()
}
}
pub struct #full_ref_guard_name{
_guard : RwLockReadGuard<'a,#bsn>,
reference : &'a TField,
}
impl<'a,TField,#generics> #filter_ref_guard_name{
fn new( ptr : *const TField, guard : RwLockReadGuard<'a,#bsn>)->Self{
let reference = unsafe {&*ptr};
return Self {_guard : guard , reference };
}
}
impl<'a, TField,#generics> Deref for #filter_ref_guard_name {
type Target = TField;
fn deref(&self) -> &Self::Target {
return self.reference;
}
}
pub struct #full_mut_guard_name{
_guard : RwLockWriteGuard<'a,#bsn>,
reference : &'a TField,
reference_mutable : &'a mut TField,
}
impl<'a,TField,#generics> #filter_mut_guard_name{
fn new( ptr : *mut TField, guard : RwLockWriteGuard<'a,#bsn>)->Self{
let reference = unsafe {&*ptr};
let reference_mutable = unsafe {&mut *ptr};
return Self {_guard : guard , reference,reference_mutable };
}
}
impl<'a, TField,#generics> Deref for #filter_mut_guard_name {
type Target = TField;
fn deref(&self) -> &Self::Target {
return self.reference;
}
}
impl<'a, TField,#generics> DerefMut for #filter_mut_guard_name {
fn deref_mut(&mut self) -> &mut Self::Target {
return self.reference_mutable;
}
}
}
}
pub fn generation_access_fields_for_wrapper(
original_ident_struct: Ident,
fields_named: FieldsNamed,
generics: Generics,
is_reader: bool,
) -> ItemImpl {
let filted_generics = filter_generics(&generics);
let mut impl_items = vec![];
let mut_guard_name = to_token_stream(get_mut_guard_name(&original_ident_struct.to_string()));
let ref_guard_name = to_token_stream(get_ref_guard_name(&original_ident_struct.to_string()));
let bsn = to_token_stream(full_base_struct_name(original_ident_struct.clone()));
let mut params = Punctuated::<FnArg, syn::Token![,]>::new();
let mut instance_fields = Punctuated::<syn::FieldValue, syn::Token![,]>::new();
let bfn = to_token_stream(crate::helpers::BASE_FIELD_NAME);
for field in fields_named.named.iter() {
let vis = field.vis.clone();
let mut mut_vis = field.vis.clone();
let ident = field.ident.clone().unwrap();
let mut_ident_method = to_token_stream(format!("{ident}_mut"));
let ref_ident_method = to_token_stream(format!("{ident}"));
if field.attrs.iter().find(|attr| attr.path().is_ident(crate::helpers::ONLY_READ)).is_some(){
mut_vis = Visibility::Inherited;
}
let return_type = field.ty.clone();
let mut guard_generics = filted_generics.clone();
#[allow(unused_assignments)]
let mut guard_generics_ts = filted_generics.to_token_stream();
match parse_str::<GenericParam>(&return_type.to_token_stream().to_string()) {
Ok(value) => {
guard_generics.params.insert(0,value);
guard_generics_ts = guard_generics.to_token_stream();
},
Err(_) => {
if guard_generics.params.len() > 0{
let mut guard_generics_str = guard_generics.to_token_stream().to_string();
guard_generics_str = (&guard_generics_str[1..guard_generics_str.len()-1]).to_string();
guard_generics_str = format!("<{},{guard_generics_str}>",return_type.to_token_stream().to_string());
guard_generics_ts = to_token_stream(&guard_generics_str);
}else{
let guard_generics_str =format!("<{}>",return_type.to_token_stream().to_string());
guard_generics_ts = to_token_stream(&guard_generics_str);
}
},
}
if !is_reader {
let impl_item_mut = quote::quote! {
#mut_vis fn #mut_ident_method(&mut self) -> #mut_guard_name #guard_generics_ts{
let mut guard = self.#bfn.write().unwrap();
let value = &mut guard. #ident;
let value = (value as *const #return_type) as *mut #return_type;
return #mut_guard_name::new(value, guard);
}
};
let impl_item_mut: ImplItem = parse_quote!(#impl_item_mut);
impl_items.push(impl_item_mut);
}
let impl_item_ref: ImplItem = parse_quote! {
#vis fn #ref_ident_method(&self) -> #ref_guard_name #guard_generics_ts{
let guard = self.#bfn.read().unwrap();
let value = &guard. #ident;
let value = value as *const #return_type;
return #ref_guard_name::new(value, guard);
}
};
impl_items.push(impl_item_ref);
params.push(parse_quote!(#ident: #return_type));
instance_fields.push(parse_quote!(#ident));
}
let builder_generics = if generics.params.len() > 0{
Some(quote!(:: #filted_generics))
}else {None};
let impl_item_builder: ImplItem = parse_quote! {
fn builder(#params) -> Self{
return #bsn #builder_generics{#instance_fields}.into();
}
};
impl_items.push(impl_item_builder);
let wsn = to_token_stream(format!(
"{}{}",
original_ident_struct,
filted_generics.to_token_stream().to_string()
));
let item_impl: ItemImpl = parse_quote! {
impl #generics #wsn{
#(#impl_items)*
}
};
item_impl
}