use std::collections::HashMap;
use caisin::set;
use heck::{ToSnakeCase, ToUpperCamelCase};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::GenCodeByValue;
pub fn parse_value(name: &str, v: Value) -> Obj {
let mut obj = Obj::default();
obj.name = name.to_string();
obj.typ_name = name.to_upper_camel_case();
match v {
Value::Null => {
obj.is_opt = true;
obj.typ_name = "Value".to_string();
}
Value::Bool(_) => {
obj.typ_name = "bool".to_string();
}
Value::Number(v) => {
if v.is_u64() {
obj.typ_name = "u64".to_string();
}
if v.is_i64() {
obj.typ_name = "i64".to_string();
}
if v.is_f64() {
obj.typ_name = "f64".to_string();
}
}
Value::String(_) => {
obj.typ_name = "String".to_string();
}
Value::Array(vec) => {
obj.is_arr = true;
let mut its = vec![];
for ele in vec {
let item = parse_value(name, ele.clone());
if ele.is_object() {
obj.is_obj = true;
for (_, v) in item.fileds {
its.push(v);
}
} else {
obj.typ_name = item.typ_name;
break;
}
}
obj.combine(its);
}
Value::Object(v) => {
obj.is_obj = true;
for (k, v) in v {
let item = parse_value(&k, v.clone());
obj.add_filed(item);
}
}
}
obj
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Obj {
name: String,
typ_name: String,
is_opt: bool,
is_arr: bool,
is_obj: bool,
fileds: HashMap<String, Obj>,
}
impl GenCodeByValue for Obj {
fn gen(&self) -> String {
let (mut a, b) = self.to_str();
a.push('\n');
a.push_str(&b);
a
}
}
impl Obj {
fn exists(&mut self, f: &Obj) -> bool {
self.fileds.contains_key(&f.name)
}
fn combine(&mut self, fs: Vec<Obj>) {
let mut exists_name = set!();
for ele in fs {
if self.exists(&ele) {
exists_name.insert(ele.name.clone());
}
self.add_filed(ele);
}
for (n, obj) in &mut self.fileds {
if exists_name.contains(n) {
continue;
}
obj.is_opt = true;
}
}
fn add_filed(&mut self, f: Obj) {
match self.fileds.get_mut(&f.name) {
Some(o) => {
if f.is_opt {
o.is_opt = true;
}
}
None => {
self.fileds.insert(f.name.clone(), f);
}
}
}
fn type_str(&self) -> String {
let mut str = String::new();
if self.is_opt {
str.push_str("Option<");
}
if self.is_arr {
str.push_str("Vec<");
}
str.push_str(&self.typ_name);
if self.is_arr {
str.push_str(">");
}
if self.is_opt {
str.push_str(">");
}
str
}
fn to_str(&self) -> (String, String) {
let mut slf = String::new();
slf.push_str(&format!(
"#[derive(Serialize, Deserialize, Debug, Default)]\npub struct {} {{\n",
self.typ_name
));
let mut subs = String::new();
let mut fileds_vec = vec![];
for (name, obj) in &self.fileds {
let lc = name.to_snake_case();
if !name.eq(&lc) || obj.is_opt {
let mut serde_str = String::new();
serde_str.push_str(" #[serde(");
let mut attrs = vec![];
if !name.eq(&lc) || obj.is_opt {
attrs.push(format!(r#"rename = "{}""#, name));
}
if obj.is_opt {
attrs.push(r#"skip_serializing_if = "Option::is_none""#.to_string());
}
fileds_vec.push(format!(" #[serde({})]", attrs.join(", ")));
}
fileds_vec.push(format!(" pub {}: {},", lc, obj.type_str()));
if obj.is_obj {
let (sl, sub) = obj.to_str();
subs.push_str(&sl);
subs.push_str(&sub);
}
}
slf.push_str(&fileds_vec.join("\n"));
slf.push_str("\n}\n");
subs.push_str("\n");
(slf, subs)
}
}