use quote::ToTokens;
use syn::{parse_quote, parse_str, FnArg, ImplItemFn, Pat, ReturnType, Stmt, Type};
use crate::helpers::{
contains_isolated_name, get_mut_guard_name, get_ref_guard_name, BASE_FIELD_NAME,
full_base_struct_name,
};
pub fn method_normalization(method: &mut ImplItemFn, origin_type_name: &str, generics: &str) {
if &method.vis.to_token_stream().to_string() == "pub(super)" {
method.vis = parse_quote!(pub(in super::super));
}
let mut stmts = &mut method.block.stmts;
stmts.clear();
let mut has_receiver = false;
if let Some(receiver) = method.sig.receiver() {
if receiver.mutability.is_some() {
stmts.push(
parse_str(&format!(
"let mut guard = self.{BASE_FIELD_NAME}.write().unwrap();"
))
.unwrap(),
)
} else {
stmts.push(
parse_str(&format!(
"let guard = self.{BASE_FIELD_NAME}.read().unwrap();"
))
.unwrap(),
)
}
has_receiver = true;
}
let mut args = "".to_string();
let len_args = method.sig.inputs.len();
method
.sig
.inputs
.iter_mut()
.enumerate()
.for_each(|(index, fn_arg)| {
if let FnArg::Typed(typed) = fn_arg {
let name_fn_arg = extract_name(&typed.pat, &mut args, index, len_args);
arg_method_normalization(
typed.ty.as_mut(),
&name_fn_arg,
origin_type_name,
stmts,
&method.sig.ident.to_string(),
)
}
});
if has_receiver {
let method_ident_str = method.sig.ident.to_string();
let return_type = &mut method.sig.output;
if let ReturnType::Type(_, type_) = return_type {
return_method_normalization(
type_.as_mut(),
&mut stmts,
&format!("guard.{method_ident_str}({args})"),
origin_type_name,
&method_ident_str,
generics,
);
} else {
stmts.push(parse_str(&format!("guard.{method_ident_str}({args});")).unwrap())
}
} else {
let return_type = &mut method.sig.output;
let method_ident_str = method.sig.ident.to_string();
if let ReturnType::Type(_, type_) = return_type {
return_method_normalization(
type_.as_mut(),
&mut stmts,
&format!("{}::{method_ident_str}({args})",full_base_struct_name(origin_type_name)),
origin_type_name,
&method_ident_str,
generics,
);
} else {
stmts.push(
parse_str(&format!(
"{}::{method_ident_str}({args});",full_base_struct_name(origin_type_name)
))
.unwrap(),
)
}
}
}
pub fn return_method_normalization(
type_: &mut Type,
stmts: &mut Vec<Stmt>,
call_method_str: &str,
original_type_name: &str,
method_name: &str,
generics: &str,
) {
let message_error = &format!(
"The return Type with Self allowed in the {method_name}
function are: Self, &Self, &mut Self,Vec<Self>. Other formats are not supported! Slice "
);
let ref_guard_name = get_ref_guard_name(original_type_name);
let mut_guard_name = get_mut_guard_name(original_type_name);
match type_ {
Type::Path(path) => {
let last_segment = path.path.segments.last_mut().unwrap();
let last_segment_str = last_segment.to_token_stream().to_string();
if contains_isolated_name(&last_segment_str, "Self")
|| contains_isolated_name(&last_segment_str, original_type_name)
{
if last_segment_str == "Vec<Self>"
|| last_segment_str == format!("Vec<{original_type_name}>")
{
stmts.push(parse_str(&format!("let reply = {call_method_str};")).unwrap());
stmts.push(
parse_str(&format!("let reply = Self::into_vec_wrapper(reply);")).unwrap(),
);
stmts.push(parse_str(&format!("return reply;")).unwrap());
} else if last_segment_str == "Self" || last_segment_str == original_type_name {
stmts.push(
parse_str(&format!("let reply = {call_method_str}.into();")).unwrap(),
);
stmts.push(parse_str(&format!("return reply;")).unwrap());
} else {
panic!("{message_error}");
}
} else {
stmts.push(parse_str(&format!("let reply = {call_method_str};")).unwrap());
stmts.push(parse_str(&format!("return reply;")).unwrap());
}
}
Type::Reference(reference) => {
let elem_str = reference.elem.to_token_stream().to_string();
if contains_isolated_name(&elem_str, "Self")
|| contains_isolated_name(&elem_str, original_type_name)
{
if elem_str == "Self" || elem_str == original_type_name {
stmts.push(parse_str(&format!("{call_method_str};")).unwrap());
stmts.push(parse_str(&format!("drop(guard);")).unwrap());
stmts.push(parse_str(&format!("return self;")).unwrap());
} else {
panic!("{message_error}");
}
} else {
if reference.mutability.is_some() {
stmts.push(parse_str(&format!("let value = {call_method_str};")).unwrap());
stmts.push(
parse_str(&format!(
"let value = (value as *const {elem_str}) as *mut {elem_str};"
))
.unwrap(),
);
stmts.push(
parse_str(&format!("return {mut_guard_name}::new(value, guard);")).unwrap(),
);
*type_ = parse_str(&format!("{mut_guard_name}<{elem_str}>")).unwrap()
} else {
stmts.push(parse_str(&format!("let value = {call_method_str};")).unwrap());
stmts.push(
parse_str(&format!("let value = value as *const {elem_str};")).unwrap(),
);
stmts.push(
parse_str(&format!("return {ref_guard_name}::new(value, guard);")).unwrap(),
);
*type_ = parse_str(&format!("{ref_guard_name}<{elem_str},{generics}>")).unwrap()
}
}
}
Type::Slice(slice) => {
let elem_str = slice.elem.to_token_stream().to_string();
if contains_isolated_name(&elem_str, "Self")
|| contains_isolated_name(&elem_str, original_type_name)
{
if elem_str == "Self" || elem_str == original_type_name {
stmts.push(parse_str(&format!("let reply = {call_method_str};")).unwrap());
stmts.push(
parse_str(&format!(
"let reply = Self::into_vec_wrapper(reply.to_vec());"
))
.unwrap(),
);
stmts.push(parse_str(&format!("return reply;")).unwrap());
*type_ = parse_str(&format!("Vec<Self>")).unwrap();
} else {
panic!("{message_error}");
}
} else {
stmts.push(parse_str(&format!("let value = {call_method_str};")).unwrap());
stmts.push(parse_str(&format!("let value = value as *const {elem_str}")).unwrap());
stmts.push(
parse_str(&format!("return {ref_guard_name}::new(value, guard);")).unwrap(),
);
*type_ = parse_str(&format!("{ref_guard_name}<{elem_str},{generics}>")).unwrap()
}
}
_ => {
let type_str = type_.into_token_stream().to_string();
if contains_isolated_name(&type_str, "Self")
|| contains_isolated_name(&type_str, original_type_name)
{
panic!("{message_error}");
} else {
stmts.push(parse_str(&format!("let reply = {call_method_str};")).unwrap());
stmts.push(parse_str(&format!("return reply;")).unwrap());
}
}
}
}
fn arg_method_normalization(
type_: &mut Type,
arg_name: &str,
origin_type_name: &str,
stmts: &mut Vec<Stmt>,
method_name: &str,
) {
let error_message = &format!("The types of parameters with Self allowed in the {method_name} function are: Self, &Self, &mut Self, &[Self], Vec<Self>. Other formats are not supported!");
match type_ {
syn::Type::Path(type_path) => {
let last_path_segment = type_path.path.segments.last().unwrap().clone();
let last_path_segment_str = type_path
.path
.segments
.last()
.unwrap()
.into_token_stream()
.to_string();
if contains_isolated_name(&last_path_segment_str, "Self")
|| contains_isolated_name(&last_path_segment_str, origin_type_name)
{
if last_path_segment.ident.to_string() == "Vec"
&& (last_path_segment.arguments.to_token_stream().to_string() == "Self"
|| last_path_segment.arguments.to_token_stream().to_string()
== origin_type_name)
{
let stmt = parse_str(&format!(
"let {arg_name} = Self::into_vec_{BASE_FIELD_NAME}({arg_name});"
))
.unwrap();
stmts.push(stmt);
} else if last_path_segment_str == "Self"
|| last_path_segment_str == origin_type_name
{
let stmt = parse_str(&format!("let {arg_name} = {arg_name}.into();")).unwrap();
stmts.push(stmt);
} else {
panic!("{error_message}")
}
}
}
syn::Type::Slice(slice) => {
if let Some(approved) =
self_checker(&slice.elem.to_token_stream().to_string(), origin_type_name)
{
if approved {
let stmt = parse_str(&format!(
"let {arg_name} = &Self::into_vec_{BASE_FIELD_NAME}({arg_name}.to_vec());"
))
.unwrap();
stmts.push(stmt);
} else {
panic!("{error_message}")
}
}
}
syn::Type::Reference(reference) => {
if let Some(approved) = self_checker(
&reference.elem.to_token_stream().to_string(),
origin_type_name,
) {
if approved {
let stmt: Stmt;
if reference.mutability.is_some() {
stmt = parse_str(&format!(
"let {arg_name} = &mut {arg_name}.{BASE_FIELD_NAME}.write().unwrap();"
))
.unwrap();
} else {
stmt = parse_str(&format!(
"let {arg_name} = {arg_name}.{BASE_FIELD_NAME}.read().unwrap();"
))
.unwrap();
}
stmts.push(stmt);
} else {
panic!("{error_message}")
}
}
}
_ => {
if contains_isolated_name(&type_.to_token_stream().to_string(), "Self")
|| contains_isolated_name(&type_.to_token_stream().to_string(), origin_type_name)
{
panic!("{error_message}")
}
return;
}
}
}
fn self_checker(element_str: &str, origin_type_name: &str) -> Option<bool> {
if element_str == "Self" || element_str == origin_type_name {
return Some(true);
} else if contains_isolated_name(&element_str, "Self")
|| contains_isolated_name(&element_str, origin_type_name)
{
return Some(false);
}
None
}
fn extract_name(pat: &Pat, args: &mut String, index: usize, len_args: usize) -> String {
let mut args_local = args.clone();
if let Pat::Ident(pat_ident) = pat {
let ident = pat_ident.ident.clone();
args_local += &ident.to_string();
if index < len_args - 1 {
args_local += ",";
}
*args = args_local;
return ident.to_string();
}
return "".into();
}