use core::fmt;
use std::borrow::Borrow;
use std::rc::Rc;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use crate::common::{global_variable_rust_lex, format_string_len};
use crate::serializator::serializator::Structure;
use crate::static_throw_text;
use super::error::StaticSchemeError;
use super::scheme::{VectorSerializType, GenericDataTypes};
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum RustCodeItemDataType
{
Uint(u64),
Int(u64),
Bool,
String,
Struct(String),
Enum(String),
Vector(Box<RustCodeItemDataType>, VectorSerializType),
Range(Box<RustCodeItemDataType>),
RangeInclusive(Box<RustCodeItemDataType>),
AnyType
}
impl fmt::Display for RustCodeItemDataType
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match *self
{
Self::Uint(w) => write!(f, "u{}", w*8),
Self::Int(w) => write!(f, "i{}", w*8),
Self::Bool => write!(f, "bool"),
Self::String => write!(f, "String"),
Self::Struct(ref s) => write!(f, "{}", s),
Self::Enum(ref e) => write!(f, "{}", e),
Self::Vector(ref v, vst) =>
{
match vst
{
VectorSerializType::Array => write!(f, "Vec<{}>", v),
VectorSerializType::Hashset => write!(f, "std::collections::HashSet<{}>", v),
VectorSerializType::Indexset => write!(f, "indexmap::IndexSet<{}>", v)
}
},
Self::Range(ref r) => write!(f, "Range<{}>", r),
Self::RangeInclusive(ref r) => write!(f, "RangeInclusive<{}>", r),
Self::AnyType => write!(f, "{}", RustCode::ANY_TYPE_ENUM)
}
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct RustCodeItemStruct
{
field_name: Option<String>,
field_opt: bool,
field_datatype: RustCodeItemDataType
}
impl fmt::Display for RustCodeItemStruct
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
if self.field_opt == true
{
write!(f, "{}: Option<{}>", self.field_name.as_ref().unwrap_or(&"Anonymous".to_string()), self.field_datatype)
}
else
{
write!(f, "{}: {}", self.field_name.as_ref().unwrap_or(&"Anonymous".to_string()), self.field_datatype)
}
}
}
impl RustCodeItemStruct
{
pub
fn new(field_name: Option<&String>, field_opt: bool, field_datatype: RustCodeItemDataType) -> Self
{
return
Self{ field_name: field_name.map(|m| m.clone()).clone(), field_opt, field_datatype };
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum RustCodeEnumType
{
Empty(String, Option<String>),
Vector(String, Vec<RustCodeItemDataType>, Option<String>),
Fields(String, Vec<RustCodeItemStruct>, Option<String>)
}
impl RustCodeEnumType
{
pub
fn new_anon(title: &String, comment: Option<String>) -> Self
{
return Self::Empty(title.clone(), comment);
}
pub
fn new_vec(title: &String, items: Vec<RustCodeItemDataType>, comment: Option<String>) -> Self
{
return
Self::Vector(title.clone(), items, comment);
}
pub
fn new_fields(title: &String, items: Vec<RustCodeItemStruct>, comment: Option<String>) -> Self
{
return
Self::Fields(title.clone(), items, comment);
}
}
impl fmt::Display for RustCodeEnumType
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match *self
{
RustCodeEnumType::Empty(ref title, ref comment) =>
{
if let Some(com) = comment
{
write!(f, " {}\n", format_string_len(com, 80, "///"))?;
}
write!(f, " {}", title)
},
RustCodeEnumType::Vector(ref title, ref items, ref comment) =>
{
if let Some(com) = comment
{
write!(f, " {}\n", format_string_len(com, 80, "///"))?;
}
write!(f, " {}(", title)?;
for (item, itemno) in items.iter().zip(0..items.len())
{
write!(f, "{}", item)?;
if itemno+1 != items.len()
{
write!(f, ", ")?;
}
}
write!(f, ")")
},
RustCodeEnumType::Fields(ref title, ref fields, ref comment) =>
{
if let Some(com) = comment
{
write!(f, " {}\n", format_string_len(com, 80, "///"))?;
}
write!(f, " {}{{ ", title)?;
for (field, fieldno) in fields.iter().zip(0..fields.len())
{
write!(f, "{}", field)?;
if fieldno+1 != fields.len()
{
write!(f, ", ")?;
}
}
write!(f, " }}")
}
}
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum RustCodeDefineType
{
String(String),
Int(i64),
Uint(u64),
LongInt(i128),
LongUInt(u128),
Bool(bool),
}
impl fmt::Display for RustCodeDefineType
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match *self
{
Self::String(ref s) =>
write!(f, "&'static str = \"{}\"", s),
Self::Int(ref i) =>
write!(f, "i64 = {}", i),
Self::Uint(ref u) =>
write!(f, "u64 = {}", u),
Self::LongInt(ref i) =>
write!(f, "i128 = {}", i),
Self::LongUInt(ref u) =>
write!(f, "u128 = {}", u),
Self::Bool(ref b) =>
write!(f, "bool = {}", b),
}
}
}
impl TryFrom<&GenericDataTypes> for RustCodeDefineType
{
type Error = StaticSchemeError;
fn try_from(value: &GenericDataTypes) -> Result<Self, Self::Error>
{
match *value
{
GenericDataTypes::Boolean(ref b, _) =>
Ok(Self::Bool(*b)),
GenericDataTypes::Int(ref i, _) =>
Ok(Self::Int(*i)),
GenericDataTypes::UInt(ref u, _) =>
Ok(Self::Uint(*u)),
GenericDataTypes::LongInt(ref i, _) =>
Ok(Self::LongInt(*i)),
GenericDataTypes::LongUInt(ref u, _) =>
Ok(Self::LongUInt(*u)),
GenericDataTypes::String(ref s, _) =>
Ok(Self::String(s.clone())),
GenericDataTypes::None =>
static_throw_text!("can not convert generic type: '{}' to \
RustCodeDefineType, unknown type", value),
GenericDataTypes::Symbol(_, li) |
GenericDataTypes::Variable(_, li) |
GenericDataTypes::Entity(_, li) |
GenericDataTypes::Enumerator(_, _, li) |
GenericDataTypes::Vector(_, li) |
GenericDataTypes::Range(_, _, li) |
GenericDataTypes::RangeIncl(_, _, li) |
GenericDataTypes::AnyValWrap(_, li) =>
static_throw_text!("can not convert generic type: '{}' to \
RustCodeDefineType, unknown type, at: '{}'", value, li),
}
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum RustCodeItem
{
Enumerator{ title: String, enum_type: Vec<RustCodeEnumType>, comment: Option<String> },
Struct{ title: String, fields: Vec<RustCodeItemStruct>, is_root: bool, comment: Option<String> },
Define{ title: String, value: RustCodeDefineType},
}
impl fmt::Display for RustCodeItem
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match *self
{
Self::Enumerator{ ref title, ref enum_type, .. } =>
{
write!(f, "pub enum {} \n{{ \n", title)?;
for (enm, enmno)
in enum_type.iter().zip(0..enum_type.len())
{
write!(f, "{}", enm)?;
if enmno+1 != enum_type.len()
{
write!(f, ", \n")?;
}
write!(f, "\n")?;
}
writeln!(f, "}}\n")
},
Self::Struct{ ref title, ref fields, .. } =>
{
write!(f, "pub struct {} \n{{ \n", title)?;
for (field, fieldno)
in fields.iter().zip(0..fields.len())
{
write!(f, " pub {}", field)?;
if fieldno+1 != fields.len()
{
writeln!(f, ",")?;
}
else
{
writeln!(f, "")?;
}
}
writeln!(f, "}}\n")
},
Self::Define{ ref title, ref value } =>
{
writeln!(f, "pub const {}: {};", global_variable_rust_lex(title), value)
}
}
}
}
impl RustCodeItem
{
pub
fn is_enum(&self) -> bool
{
match *self
{
Self::Enumerator { .. } => return true,
Self::Struct { .. } => return false,
Self::Define { .. } => return false,
}
}
pub
fn get_comment(&self) -> Option<&String>
{
match *self
{
Self::Enumerator { ref comment, .. } => return comment.as_ref(),
Self::Struct { ref comment, .. } => return comment.as_ref(),
Self::Define { .. } => return None,
}
}
pub
fn is_define(&self) -> bool
{
return
std::mem::discriminant(self) ==
std::mem::discriminant(
&Self::Define { title: String::new(), value: RustCodeDefineType::Bool(false) }
);
}
pub
fn get_title(&self) -> &str
{
match *self
{
Self::Enumerator{ ref title, .. } => return title.as_str(),
Self::Struct{ ref title, .. } => return title.as_str(),
Self::Define { ref title, .. } => return title.as_str(),
}
}
pub
fn new_struct(strk: Rc<Structure>, items: Vec<RustCodeItemStruct>, is_root: bool) -> Self
{
return
Self::Struct
{
title: strk.get_struct_name().get_name_1().to_string(),
fields: items,
is_root: is_root,
comment: strk.get_comment().map_or(None, |v| Some(v.clone())),
};
}
pub
fn new_enum(title: &str, items: Vec<RustCodeEnumType>, commnent: Option<&String>) -> Self
{
return
Self::Enumerator
{
title: title.to_string(),
enum_type: items,
comment: commnent.map_or(None, |v| Some(v.clone())),
};
}
pub
fn new_define(title: &str, value: RustCodeDefineType) -> Self
{
return
Self::Define { title: title.to_string(), value: value };
}
}
pub struct RustCodeDerivRepl
{
item_title: String,
deriv_items: Vec<String>,
}
impl Hash for RustCodeDerivRepl
{
fn hash<H: Hasher>(&self, state: &mut H)
{
self.item_title.hash(state);
}
}
impl Eq for RustCodeDerivRepl {}
impl PartialEq for RustCodeDerivRepl
{
fn eq(&self, other: &Self) -> bool
{
return
self.item_title == other.item_title;
}
}
impl Borrow<String> for RustCodeDerivRepl
{
fn borrow(&self) -> &String
{
return &self.item_title;
}
}
impl Borrow<str> for RustCodeDerivRepl
{
fn borrow(&self) -> &str
{
return self.item_title.as_str();
}
}
impl RustCodeDerivRepl
{
pub
fn new(item_title: &str, deriv_items: &[&'static str]) -> Self
{
return
Self
{
item_title: item_title.to_string(),
deriv_items: deriv_items.into_iter().map(|d| d.to_string()).collect()
};
}
pub
fn form_derive(&self) -> String
{
return self.deriv_items.join(", ");
}
}
pub struct RustCode
{
items: Vec<RustCodeItem>,
deriv_enum: &'static [&'static str],
deriv_struct: &'static [&'static str],
deriv_repl: HashSet<RustCodeDerivRepl>,
serde_path: &'static str,
serde_crate_path: Option<&'static str>,
common_file_usepath: Option<&'static str>,
is_any_type_present: bool
}
impl fmt::Display for RustCode
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
writeln!(f, "use {};\n", self.serde_path)?;
if self.common_file_usepath.is_some() == true
{
writeln!(f, "use {}::*;\n\n", self.common_file_usepath.as_ref().unwrap())?;
}
for item in self.items.iter()
{
if item.is_define() == false
{
if let Some(com) = item.get_comment()
{
write!(f, "{} \n", format_string_len(com, 80, "///"))?;
}
if let Some(der) = self.deriv_repl.get(item.get_title())
{
writeln!(f, "#[derive({})]", der.form_derive())?;
}
else
{
if item.is_enum() == true
{
writeln!(f, "#[derive({})]", self.deriv_enum.join(", "))?;
}
else
{
writeln!(f, "#[derive({})]", self.deriv_struct.join(", "))?;
}
}
if let Some(ref path) = self.serde_crate_path
{
writeln!(f, "#[serde(crate = \"{}\")]", path)?;
}
}
writeln!(f, "{}", item)?
}
return Ok(());
}
}
impl RustCode
{
pub const SERDE_PATH: &'static str = "serde::{Serialize, Deserialize}";
pub const ANY_TYPE_ENUM: &'static str = "ShmTypeAnyField";
pub const ANY_TYPE_ENUM_STR: &'static str = "String";
pub const ANY_TYPE_ENUM_ENTITY: &'static str = "Entity";
pub const ANY_TYPE_ENUM_VARIABLE: &'static str = "Variable";
pub const ANY_TYPE_ENUM_UINT: &'static str = "UInt";
pub const ANY_TYPE_ENUM_LONGUINT: &'static str = "LongUInt";
pub const ANY_TYPE_ENUM_INT: &'static str = "Int";
pub const ANY_TYPE_ENUM_LONGINT: &'static str = "LongInt";
pub const ANY_TYPE_ENUM_BOOL: &'static str = "Bool";
pub
fn new(deriv_enum: &'static [&'static str], deriv_struct: &'static [&'static str]) -> Self
{
return
Self
{
items: Vec::new(),
deriv_enum: deriv_enum,
deriv_struct: deriv_struct,
deriv_repl: HashSet::new(),
serde_path: Self::SERDE_PATH,
serde_crate_path: None,
common_file_usepath: None,
is_any_type_present: false,
};
}
pub
fn overide_serde_path(&mut self, ser_path: &'static str)
{
self.serde_path = ser_path;
}
pub
fn overide_serde_crate_path(&mut self, ser_crate_path: &'static str)
{
self.serde_crate_path = Some(ser_crate_path);
}
pub
fn add_derive_override(&mut self, item: RustCodeDerivRepl)
{
self.deriv_repl.insert(item);
}
pub(crate)
fn add_item(&mut self, item: RustCodeItem)
{
for i in self.items.iter()
{
if i.get_title() == item.get_title()
{
return;
}
}
self.items.push(item);
return;
}
pub(crate)
fn set_field_any(&mut self, int_width: u64)
{
if self.is_any_type_present == false
{
self.is_any_type_present = true;
self.add_item(
RustCodeItem::new_enum(
Self::ANY_TYPE_ENUM,
vec![
RustCodeEnumType::new_vec(
&Self::ANY_TYPE_ENUM_INT.to_string(),
vec![RustCodeItemDataType::Int(int_width)],
Some("An integer data type".to_string())
),
RustCodeEnumType::new_vec(
&Self::ANY_TYPE_ENUM_UINT.to_string(),
vec![RustCodeItemDataType::Uint(int_width)],
Some("An unsigned integer type".to_string())
),
RustCodeEnumType::new_vec(
&Self::ANY_TYPE_ENUM_LONGINT.to_string(),
vec![RustCodeItemDataType::Int(int_width)],
Some("An integer data type".to_string())
),
RustCodeEnumType::new_vec(
&Self::ANY_TYPE_ENUM_LONGUINT.to_string(),
vec![RustCodeItemDataType::Uint(int_width)],
Some("An unsigned integer type".to_string())
),
RustCodeEnumType::new_vec(
&Self::ANY_TYPE_ENUM_BOOL.to_string(),
vec![RustCodeItemDataType::Bool],
Some("A boolean type".to_string())
),
RustCodeEnumType::new_vec(
&Self::ANY_TYPE_ENUM_STR.to_string(),
vec![RustCodeItemDataType::String],
Some("A string type".to_string())
),
RustCodeEnumType::new_vec(
&Self::ANY_TYPE_ENUM_ENTITY.to_string(),
vec![RustCodeItemDataType::String],
Some("An entity type".to_string())
),
RustCodeEnumType::new_vec(
&Self::ANY_TYPE_ENUM_VARIABLE.to_string(),
vec![RustCodeItemDataType::String],
Some("A variable type".to_string())
),
],
Some(&"An enum for the auto type".to_string())
)
)
}
}
}
impl RustCode
{
pub
fn search_common(
common_file_usepath: &'static str,
mut items: Vec<&mut RustCode>,
deriv_enum: &'static [&'static str],
deriv_struct: &'static [&'static str]
) -> Option<RustCode>
{
let mut hash_items: HashSet<&RustCodeItem> = HashSet::new();
let mut intersections: HashSet<RustCodeItem> = HashSet::new();
for itm in items.iter()
{
let inner: HashSet<&RustCodeItem> =
itm.items.iter().map(|n| n).collect();
if hash_items.len() > 0
{
let intersection: HashSet<RustCodeItem> =
hash_items.intersection(&inner).map(|n| (*n).clone()).collect();
intersections.extend(intersection);
}
hash_items.extend(inner);
}
for itm in items.iter_mut()
{
let len = itm.items.len();
itm.items.retain(|it|
{
for intrs in intersections.iter()
{
if intrs == it
{
return false;
}
}
return true;
}
);
if itm.items.len() < len
{
itm.common_file_usepath = Some(common_file_usepath);
}
}
if intersections.len() > 0
{
let mut commons = RustCode::new(deriv_enum, deriv_struct);
commons.items.extend(intersections);
return Some(commons);
}
else
{
return None;
}
}
}