use std::usize;
use crate::models::meta::metas_to_display;
use crate::models::utils::indent_literal;
use crate::models::{Entity, EntityAccept, VisitEntity};
use serde::Deserialize;
use std::fmt::Display;
use super::meta::{metas_to_literal, Meta};
#[derive(Clone, Debug, Deserialize)]
pub enum DataType {
Boolean,
Character,
String,
Byte,
UnsignedByte,
Short,
UnsignedShort,
Integer,
UnsignedInteger,
Size,
UnsignedSize,
Long,
UnsignedLong,
LongLong,
UnsignedLongLong,
Float,
Double,
PathBuf,
Count32,
Averagef32,
Date,
DateTime,
Duration,
LocalTime,
UtcTime,
Period,
Timestamp,
Object(String),
ExternalObject(String),
Booleans,
Characters,
Strings,
Bytes,
UnsignedBytes,
Shorts,
UnsignedShorts,
Integers,
UnsignedIntegers,
Sizes,
UnsignedSizes,
Longs,
UnsignedLongs,
LongLongs,
UnsignedLongLongs,
Floats,
Doubles,
PathBufs,
Count32s,
Averagef32s,
Objects(String),
ExternalObjects(String),
Box {
ty: Box<DataType>,
},
Option {
ty: Box<DataType>,
},
Vec {
ty: Box<DataType>,
},
Array {
ty: Box<DataType>,
len: usize,
},
Tuple {
tys: Vec<DataType>,
},
HashMap {
kty: Box<DataType>,
vty: Box<DataType>,
},
HashSet {
ty: Box<DataType>,
},
Pair {
lty: Box<DataType>,
rty: Box<DataType>,
},
Tuples {
tys: Vec<DataType>,
},
Pairs {
lty: Box<DataType>,
rty: Box<DataType>,
},
}
pub fn data_ty_to_literal(ty: &DataType) -> String {
match ty {
DataType::Boolean => "bool".to_owned(),
DataType::Character => "char".to_owned(),
DataType::String => "String".to_owned(),
DataType::Byte => "i8".to_owned(),
DataType::UnsignedByte => "u8".to_owned(),
DataType::Short => "i16".to_owned(),
DataType::UnsignedShort => "u16".to_owned(),
DataType::Integer => "i32".to_owned(),
DataType::UnsignedInteger => "u32".to_owned(),
DataType::Size => "isize".to_owned(),
DataType::UnsignedSize => "usize".to_owned(),
DataType::Long => "i64".to_owned(),
DataType::UnsignedLong => "u64".to_owned(),
DataType::LongLong => "i128".to_owned(),
DataType::UnsignedLongLong => "u128".to_owned(),
DataType::Float => "f32".to_owned(),
DataType::Double => "f64".to_owned(),
DataType::PathBuf => "std::path::PathBuf".to_owned(),
DataType::Count32 => "Count32".to_owned(),
DataType::Averagef32 => "Averagef32".to_owned(),
DataType::Date => "chrono::NaiveDate".to_owned(),
DataType::DateTime => "chrono::NaiveDateTime".to_owned(),
DataType::Duration => "chrono::Duration".to_owned(),
DataType::LocalTime => "chrono::DateTime<chrono::Local>".to_owned(),
DataType::UtcTime => "chrono::DateTime<chrono::Utc>".to_owned(),
DataType::Period => "pipebase::common::Period".to_owned(),
DataType::Timestamp => "pipebase::common::Timestamp".to_owned(),
DataType::Object(object) => object.to_owned(),
DataType::ExternalObject(object) => object.to_owned(),
DataType::Booleans => {
let ty_lit = data_ty_to_literal(&DataType::Boolean);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Characters => {
let ty_lit = data_ty_to_literal(&DataType::Character);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Strings => {
let ty_lit = data_ty_to_literal(&DataType::String);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Bytes => {
let ty_lit = data_ty_to_literal(&DataType::Byte);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::UnsignedBytes => {
let ty_lit = data_ty_to_literal(&DataType::UnsignedByte);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Shorts => {
let ty_lit = data_ty_to_literal(&DataType::Short);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::UnsignedShorts => {
let ty_lit = data_ty_to_literal(&DataType::UnsignedShort);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Integers => {
let ty_lit = data_ty_to_literal(&DataType::Integer);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::UnsignedIntegers => {
let ty_lit = data_ty_to_literal(&DataType::UnsignedInteger);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Sizes => {
let ty_lit = data_ty_to_literal(&DataType::Size);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::UnsignedSizes => {
let ty_lit = data_ty_to_literal(&DataType::UnsignedSize);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Longs => {
let ty_lit = data_ty_to_literal(&DataType::Long);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::UnsignedLongs => {
let ty_lit = data_ty_to_literal(&DataType::UnsignedLong);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::LongLongs => {
let ty_lit = data_ty_to_literal(&DataType::LongLong);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::UnsignedLongLongs => {
let ty_lit = data_ty_to_literal(&DataType::UnsignedLongLong);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Floats => {
let ty_lit = data_ty_to_literal(&DataType::Float);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Doubles => {
let ty_lit = data_ty_to_literal(&DataType::Double);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::PathBufs => {
let ty_lit = data_ty_to_literal(&DataType::PathBuf);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Count32s => {
let ty_lit = data_ty_to_literal(&DataType::Count32);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Averagef32s => {
let ty_lit = data_ty_to_literal(&DataType::Averagef32);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Objects(object) => {
let ty_lit = data_ty_to_literal(&DataType::Object(object.to_owned()));
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::ExternalObjects(object) => {
let ty_lit = data_ty_to_literal(&DataType::ExternalObject(object.to_owned()));
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Box { ty } => {
let ty_lit = data_ty_to_literal(ty);
format!("Box<{}>", ty_lit)
}
DataType::Option { ty } => {
let ty_lit = data_ty_to_literal(ty);
format!("Option<{}>", ty_lit)
}
DataType::Vec { ty } => {
let ty_lit = data_ty_to_literal(ty);
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Array { ty, len } => {
let ty_lit = data_ty_to_literal(ty);
format!("[{}; {}]", ty_lit, len)
}
DataType::Tuple { tys } => {
let tys: Vec<String> = tys.iter().map(data_ty_to_literal).collect();
format!("({})", tys.join(", "))
}
DataType::HashMap { kty, vty } => {
let kty = data_ty_to_literal(kty);
let vty = data_ty_to_literal(vty);
format!("std::collections::HashMap<{}, {}>", kty, vty)
}
DataType::HashSet { ty } => {
let ty_lit = data_ty_to_literal(ty);
format!("std::collections::HashSet<{}>", ty_lit)
}
DataType::Pair { lty, rty } => {
let lty = data_ty_to_literal(lty);
let rty = data_ty_to_literal(rty);
format!("Pair<{}, {}>", lty, rty)
}
DataType::Tuples { tys } => {
let ty_lit = data_ty_to_literal(&DataType::Tuple {
tys: tys.to_owned(),
});
format!("std::vec::Vec<{}>", ty_lit)
}
DataType::Pairs { lty, rty } => {
let ty_lit = data_ty_to_literal(&DataType::Pair {
lty: lty.to_owned(),
rty: rty.to_owned(),
});
format!("std::vec::Vec<{}>", ty_lit)
}
}
}
#[derive(Clone, Debug, Deserialize)]
pub struct DataField {
name: Option<String>,
ty: DataType,
metas: Option<Vec<Meta>>,
is_public: Option<bool>,
}
impl DataField {
pub fn init(&mut self) {
if self.is_public.is_none() {
self.is_public = Some(true);
}
if self.metas.is_none() {
self.metas = Some(Vec::new())
}
}
pub fn get_data_type_literal(&self, indent: usize) -> String {
let ty_lit = data_ty_to_literal(&self.ty);
let indent_lit = indent_literal(indent);
format!("{}{}", indent_lit, ty_lit)
}
pub fn get_metas_literal(&self, indent: usize) -> Option<String> {
let metas = self.metas.as_ref().expect("field metas not inited");
Some(metas_to_literal(metas, indent))
}
pub fn get_pub_literal(&self) -> String {
let is_public = match self.is_public {
Some(is_public) => is_public,
None => return "pub ".to_owned(),
};
match is_public {
true => "pub ".to_owned(),
false => "".to_owned(),
}
}
pub fn display(&self) -> (String, String, String) {
let name_display = match self.name {
Some(ref name) => name.to_owned(),
None => String::new(),
};
let type_display = self.get_data_type_literal(0);
let metas_display = match self.metas {
Some(ref metas) => metas_to_display(metas),
None => String::new(),
};
(name_display, type_display, metas_display)
}
}
impl Entity for DataField {
fn get_id(&self) -> String {
match self.name {
Some(ref name) => name.to_owned(),
None => String::new(),
}
}
fn list_dependency(&self) -> Vec<String> {
match self.ty.to_owned() {
DataType::Object(object) => vec![object],
_ => vec![],
}
}
fn to_literal(&self, indent: usize) -> String {
let name = match self.name.to_owned() {
Some(name) => name,
None => return self.get_data_type_literal(indent),
};
let indent_lit = indent_literal(indent);
let metas_lit = self.get_metas_literal(indent);
let pub_lit = self.get_pub_literal();
let literal = format!(
"{}{}{}: {}",
indent_lit,
pub_lit,
name,
self.get_data_type_literal(0)
);
match metas_lit {
None => literal,
Some(metas_lit) => format!("{}\n{}", metas_lit, literal),
}
}
}
impl<V: VisitEntity<DataField>> EntityAccept<V> for DataField {}
#[derive(Debug, Deserialize, Clone)]
pub struct Object {
ty: String,
metas: Option<Vec<Meta>>,
fields: Vec<DataField>,
}
impl Object {
pub fn new(ty: String, metas: Vec<Meta>, fields: Vec<DataField>) -> Self {
Object {
ty,
metas: Some(metas),
fields: fields
.into_iter()
.map(|mut f| {
f.init();
f
})
.collect(),
}
}
pub fn init(&mut self) {
if self.metas.is_none() {
self.metas = Some(Vec::new())
}
for field in self.fields.as_mut_slice() {
field.init();
}
}
pub fn get_metas_literal(&self, indent: usize) -> Option<String> {
let metas = self.metas.as_ref().expect("object metas not inited");
Some(metas_to_literal(metas, indent))
}
pub fn get_fields(&self) -> &Vec<DataField> {
&self.fields
}
}
impl Entity for Object {
fn get_id(&self) -> String {
self.ty.to_owned()
}
fn list_dependency(&self) -> Vec<String> {
self.fields
.iter()
.flat_map(|field| field.list_dependency())
.collect()
}
fn to_literal(&self, indent: usize) -> String {
let field_lits: Vec<String> = self
.fields
.iter()
.map(|field| field.to_literal(indent + 1))
.collect();
let field_lits = field_lits.join(",\n");
let indent_lit = indent_literal(indent);
let struct_lit = format!(
"{}pub struct {} {{\n{}\n{}}}",
indent_lit, &self.ty, field_lits, indent_lit
);
let metas_lit = self.get_metas_literal(indent);
let metas_lit = match metas_lit {
None => return struct_lit,
Some(metas_lit) => metas_lit,
};
format!("{}\n{}", metas_lit, struct_lit)
}
}
impl<V: VisitEntity<Object>> EntityAccept<V> for Object {}
impl Display for Object {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Type: {}", self.ty)?;
if let Some(ref metas) = self.metas {
writeln!(f, "Type Metas: {}", metas_to_display(metas))?
}
writeln!(f, "Fields:")?;
let mut displays: Vec<(String, String, String)> = vec![(
OBJECY_DISPLAY_HEADER_NAME.to_owned(),
OBJECY_DISPLAY_HEADER_TYPE.to_owned(),
OBJECY_DISPLAY_HEADER_METAS.to_owned(),
)];
let mut name_width = OBJECY_DISPLAY_HEADER_NAME.len();
let mut ty_width = OBJECY_DISPLAY_HEADER_TYPE.len();
let mut metas_width = OBJECY_DISPLAY_HEADER_METAS.len();
for field in &self.fields {
let (name, ty, metas) = field.display();
name_width = name_width.max(name.len());
ty_width = ty_width.max(ty.len());
metas_width = metas_width.max(metas.len());
displays.push((name, ty, metas));
}
for (name, ty, metas) in displays {
writeln!(
f,
"{name:>nw$} {ty:>tw$} {metas:>mw$}",
name = name,
nw = name_width,
ty = ty,
tw = ty_width,
metas = metas,
mw = metas_width
)?;
}
write!(f, "")
}
}
const OBJECY_DISPLAY_HEADER_NAME: &str = "Name";
const OBJECY_DISPLAY_HEADER_TYPE: &str = "Type";
const OBJECY_DISPLAY_HEADER_METAS: &str = "Metas";