#[macro_export]
macro_rules! generate_from_tuples {
($obj_type:ty, $tuples:expr) => {{
use serde_json::{Map, Value};
fn smart_parse_value(content: &str, field_name: &str) -> Value {
let cleaned = content.trim();
if cleaned.is_empty() || cleaned.eq_ignore_ascii_case("null") || cleaned.eq_ignore_ascii_case("none") {
return Value::Null;
}
if let Ok(json_value) = serde_json::from_str::<Value>(cleaned) {
if let Value::Object(obj) = &json_value {
let field_key = field_name.split('.').last().unwrap_or(field_name);
if obj.len() == 1 && obj.contains_key(field_key) {
return obj[field_key].clone();
}
}
return json_value;
}
if cleaned.eq_ignore_ascii_case("true") {
return Value::Bool(true);
}
if cleaned.eq_ignore_ascii_case("false") {
return Value::Bool(false);
}
if let Some(numeric_value) = parse_numeric_value(cleaned) {
if numeric_value.fract() == 0.0 && numeric_value >= 0.0 && numeric_value <= u64::MAX as f64 {
return Value::Number(serde_json::Number::from(numeric_value as u64));
} else {
return Value::Number(serde_json::Number::from_f64(numeric_value).unwrap_or_else(|| serde_json::Number::from(0)));
}
}
Value::String(cleaned.to_string())
}
fn parse_numeric_value(content: &str) -> Option<f64> {
let mut cleaned = content.to_string();
cleaned = cleaned.replace('$', "");
cleaned = cleaned.replace('€', "");
cleaned = cleaned.replace('£', "");
cleaned = cleaned.replace('¥', "");
cleaned = cleaned.replace('₹', "");
cleaned = cleaned.replace(',', "");
cleaned = cleaned.replace(' ', "");
let is_percentage = cleaned.ends_with('%');
if is_percentage {
cleaned = cleaned.trim_end_matches('%').to_string();
}
if let Ok(mut num) = cleaned.parse::<f64>() {
if is_percentage {
num /= 100.0; }
return Some(num);
}
None
}
fn set_nested_field(json_map: &mut Map<String, Value>, field_path: &str, value: Value) {
let parts: Vec<&str> = field_path.split('.').collect();
if parts.len() == 1 {
json_map.insert(parts[0].to_string(), value);
return;
}
let first_part = parts[0];
let remaining_path = parts[1..].join(".");
let nested_obj = json_map.entry(first_part.to_string())
.or_insert_with(|| Value::Object(Map::new()));
if let Value::Object(nested_map) = nested_obj {
set_nested_field(nested_map, &remaining_path, value);
}
}
let mut json_map = Map::new();
for (field_name, content) in $tuples {
let value = smart_parse_value(&content, &field_name);
set_nested_field(&mut json_map, &field_name, value);
}
let json_value = Value::Object(json_map);
serde_json::from_value::<$obj_type>(json_value).unwrap_or_else(|_| <$obj_type>::default())
}};
}