use std::{fmt, mem, rc::Rc, cell::RefCell};
use crate::
{
serializator::serializator::{FieldDecl, StructName},
static_scheme::
{
scheme::{ArgDataType, GenericDataTypes},
generator::RustCode
},
scheme_composer::schm_comp_map::CompMapProcArgsRangeIncl
};
use super::{schm_comp_map::CompMapProcArgsRange, error::SchemeComposerRes, schm_field_line::LineField};
#[derive(Debug, Clone)]
pub enum TemplateArgs
{
String(String),
UInt(u64),
Int(i64),
LongUInt(u128),
LongInt(i128),
Bool(bool),
Vector(Vec<TemplateArgs>),
Structure(StructTemplate),
Enumerator(StructEnumTemplate),
None,
}
impl fmt::Display for TemplateArgs
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match *self
{
TemplateArgs::String(ref s) => write!(f, "{}", s),
TemplateArgs::UInt(ref u) => write!(f, "{}", u),
TemplateArgs::Int(ref i) => write!(f, "{}", i),
TemplateArgs::LongUInt(ref u) => write!(f, "{}", u),
TemplateArgs::LongInt(ref i) => write!(f, "{}", i),
TemplateArgs::Bool(b) => write!(f, "{}", b),
TemplateArgs::Vector(ref v) =>
write!(f, "{}", v.iter().map(|vv| vv.to_string()).collect::<Vec<String>>().join(" ")),
TemplateArgs::Structure(ref s) => write!(f, "{}", s),
TemplateArgs::Enumerator(ref e) => write!(f, "{}", e),
TemplateArgs::None => write!(f, "None"),
}
}
}
impl PartialEq<GenericDataTypes> for TemplateArgs
{
fn eq(&self, other: &GenericDataTypes) -> bool
{
match (self, other)
{
(TemplateArgs::String(ref l), GenericDataTypes::String(ref r, _)) =>
{
return l == r;
},
(TemplateArgs::UInt(ref l), GenericDataTypes::UInt(ref r, _)) =>
{
return l == r;
},
(TemplateArgs::Int(ref l), GenericDataTypes::Int(ref r, _)) =>
{
return l == r;
},
(TemplateArgs::LongInt(ref l), GenericDataTypes::LongInt(ref r, _)) =>
{
return l == r;
},
(TemplateArgs::LongUInt(ref l), GenericDataTypes::LongUInt(ref r, _)) =>
{
return l == r;
},
(TemplateArgs::Bool(ref l), GenericDataTypes::Boolean(ref r, _)) =>
{
return l == r;
},
(TemplateArgs::Vector(ref l), GenericDataTypes::Vector(ref r, _)) =>
{
return l.iter().zip(r.iter()).all(|(l, r)| l == r);
},
(_, _) => panic!("can not compare: {} and {}", self, other),
}
}
}
impl TemplateArgs
{
pub
fn as_arg_datatype(&self) -> ArgDataType
{
match *self
{
Self::Bool(_) =>
return ArgDataType::Boolean,
Self::Int(_) =>
return ArgDataType::Int,
Self::UInt(_) =>
return ArgDataType::UInt,
Self::LongInt(_) =>
return ArgDataType::LongInt,
Self::LongUInt(_) =>
return ArgDataType::LongUint,
Self::String(_) =>
return ArgDataType::String,
Self::Vector(_) =>
return ArgDataType::Vector,
_ =>
panic!("can not convert: '{}' to 'ArgDataType'", self)
}
}
pub
fn get_arg_enum(&self) -> SchemeComposerRes<(String, String)>
{
if let Self::Enumerator(s) = self
{
if let StructTemplateEnum::Unit = s.get_enum_item()
{
return Ok((s.get_enum_name().clone(), s.get_enum_item_name().clone()));
}
else
{
comp_throw_text!("must be unit!");
}
}
comp_throw_text!("must be enum!");
}
pub
fn get_string(&self) -> Option<&str>
{
if let Self::String(ref s) = self
{
return Some(s.as_str());
}
return None;
}
pub
fn get_longint(&self) -> Option<i128>
{
if let Self::LongInt(i) = self
{
return Some(*i);
}
return None;
}
pub
fn get_int(&self) -> Option<i64>
{
if let Self::Int(i) = self
{
return Some(*i);
}
return None;
}
pub
fn get_longuint(&self) -> Option<u128>
{
if let Self::LongUInt(u) = self
{
return Some(*u);
}
return None;
}
pub
fn get_uint(&self) -> Option<u64>
{
if let Self::UInt(u) = self
{
return Some(*u);
}
return None;
}
pub
fn get_bool(&self) -> Option<bool>
{
if let Self::Bool(b) = self
{
return Some(*b);
}
return None;
}
pub
fn get_vec(&self) -> Option<&[TemplateArgs]>
{
if let Self::Vector(v) = self
{
return Some(v.as_slice());
}
return None;
}
pub
fn get_enum_anytype(&self) -> SchemeComposerRes<(&String, &TemplateArgs)>
{
if let Self::Enumerator(enm) = self
{
if enm.get_enum_name() != RustCode::ANY_TYPE_ENUM
{
map_comp_throw_text!("expected enum name: '{}'", enm.get_enum_name());
}
match enm.get_enum_item()
{
StructTemplateEnum::TupleList(ref v) =>
{
if v.len() != 1
{
comp_throw_text!("expected 1 arg in TupleList in enum: '{}', item: '{}, len: '{}",
enm.get_enum_name(), enm.get_enum_item_name(), v.len());
}
return Ok((enm.get_enum_item_name(), v.get(0).unwrap()));
},
_ =>
comp_throw_text!("expected TupleList in enum: '{}', item: '{}",
enm.get_enum_name(), enm.get_enum_item_name())
}
}
else
{
comp_throw_text!("expected enum '{}'", RustCode::ANY_TYPE_ENUM);
}
}
pub
fn get_struct_range(&self, dt: ArgDataType) -> SchemeComposerRes<CompMapProcArgsRange>
{
if let Self::Structure(s) = self
{
if s.get_name_safe() != "Range"
{
map_comp_throw_text!("can not get range, not range: '{}'", s.get_name_safe());
}
let fields = s.get_fields();
let start =
fields.get(0)
.unwrap();
let end =
fields.get(1)
.unwrap();
if start.get_name().as_str() != "start"
{
comp_throw_text!("struct name: '{}', field expected start!", s.get_name_safe());
}
else if end.get_name().as_str() != "end"
{
comp_throw_text!("struct name: '{}', field expected end!", s.get_name_safe());
}
match dt
{
ArgDataType::Int =>
{
return Ok(
CompMapProcArgsRange::Signed(
start.get_arg().get_int().unwrap(),
end.get_arg().get_int().unwrap(),
)
);
},
ArgDataType::UInt =>
{
return Ok(
CompMapProcArgsRange::Unsigned(
start.get_arg().get_uint().unwrap(),
end.get_arg().get_uint().unwrap(),
)
);
},
_ =>
comp_throw_text!("struct name: '{}', expected int or uint!", s.get_name_safe())
}
}
comp_throw_text!("not a structure!");
}
pub
fn get_struct_range_incl(&self, dt: ArgDataType) -> SchemeComposerRes<CompMapProcArgsRangeIncl>
{
if let Self::Structure(s) = self
{
if s.get_name_safe() != "RangeInclusive"
{
panic!("can not get range, not range: '{}'", s.get_name_safe());
}
let fields = s.get_fields();
let start =
fields.get(0)
.unwrap();
let end =
fields.get(1)
.unwrap();
if start.get_name().as_str() != "start"
{
comp_throw_text!("field expected start!");
}
else if end.get_name().as_str() != "end"
{
comp_throw_text!("field expected end!");
}
match dt
{
ArgDataType::Int =>
{
return Ok(
CompMapProcArgsRangeIncl::Signed(
start.get_arg().get_int().unwrap(),
end.get_arg().get_int().unwrap(),
)
);
},
ArgDataType::UInt =>
{
return Ok(
CompMapProcArgsRangeIncl::Unsigned(
start.get_arg().get_uint().unwrap(),
end.get_arg().get_uint().unwrap(),
)
);
},
_ =>
comp_throw_text!("expected int or uint!")
}
}
comp_throw_text!("not a struct!");
}
}
impl TemplateArgs
{
pub
fn new_arg_bool(b: bool) -> Self
{
return TemplateArgs::Bool(b);
}
pub
fn new_arg_uint(u: u64) -> Self
{
return TemplateArgs::UInt(u);
}
pub
fn new_arg_int(i: i64) -> Self
{
return TemplateArgs::Int(i);
}
pub
fn new_arg_longuint(u: u128) -> Self
{
return TemplateArgs::LongUInt(u);
}
pub
fn new_arg_longint(i: i128) -> Self
{
return TemplateArgs::LongInt(i);
}
pub
fn new_arg_string(s: &str) -> Self
{
return TemplateArgs::String(s.to_string());
}
pub
fn new_arg_vector(v: Vec<TemplateArgs>) -> Self
{
return TemplateArgs::Vector(v);
}
pub
fn new_arg_struct(s: StructTemplate) -> Self
{
return TemplateArgs::Structure(s);
}
pub
fn new_arg_enum(e: StructEnumTemplate) -> Self
{
return TemplateArgs::Enumerator(e);
}
pub
fn new_arg_none() -> Self
{
return TemplateArgs::None;
}
pub
fn is_none(&self) -> bool
{
return
mem::discriminant(self) == mem::discriminant(&Self::None);
}
pub
fn is_vector(&self) -> bool
{
return
mem::discriminant(self) == mem::discriminant(&TemplateArgs::Vector(Vec::new()));
}
}
#[derive(Debug, Clone)]
pub struct StructTemplateData
{
field_name: String,
field_data: TemplateArgs,
}
impl fmt::Display for StructTemplateData
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "-> fielf_name: {}, data: {}", self.field_name, self.field_data)
}
}
impl PartialEq<str> for StructTemplateData
{
fn eq(&self, other: &str) -> bool
{
return self.field_name.as_str() == other;
}
}
impl StructTemplateData
{
pub
fn new_field(field_name: &str, field_data: TemplateArgs) -> Self
{
return
Self
{
field_name: field_name.to_string(),
field_data: field_data
};
}
pub
fn get_name(&self) -> &String
{
return &self.field_name;
}
pub
fn get_arg(&self) -> &TemplateArgs
{
return &self.field_data;
}
}
#[derive(Debug, Clone)]
pub struct StructTemplate
{
name: Option<String>,
struct_fields: Vec<Rc<StructTemplateData>>
}
impl fmt::Display for StructTemplate
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "\nstruct name: {}, fields: {}",
self.name.as_ref().unwrap_or(&"N/A".to_string()),
self.struct_fields
.iter()
.map(|v| format!("{}", v))
.collect::<Vec<String>>().join(" ")
)
}
}
impl StructTemplate
{
pub
fn new(name: &str, len: usize) -> Self
{
return
Self
{
name: Some(name.to_string()),
struct_fields: Vec::with_capacity(len)
};
}
pub
fn new_anon(len: usize) -> Self
{
return Self{ name: None, struct_fields: Vec::with_capacity(len) };
}
pub
fn push_value(&mut self, field_name: &str, cmpa: TemplateArgs)
{
self.struct_fields.push(
Rc::new(
StructTemplateData
{
field_name: field_name.to_string(),
field_data: cmpa,
}
)
);
}
pub
fn collect_fields_by_fielddecl(
&self,
fld_decls: &[Rc<FieldDecl>],
lf: Rc<RefCell<LineField>>,
cur_wrk_path: &[String]
) -> Vec<(Rc<StructTemplateData>, Rc<FieldDecl>)>
{
let mut stds: Vec<(Rc<StructTemplateData>, Rc<FieldDecl>)> =
Vec::with_capacity(fld_decls.len());
'outer: for rfield in fld_decls
{
for lfield in self.get_struct_fields_iter()
{
if lfield.as_ref() == rfield.get_field_name_safe()
{
stds.push((lfield.clone(), rfield.clone()));
continue 'outer;
}
}
let l = lf.as_ref().borrow();
if let Some(cfield) = l.get_item(rfield.as_ref(), cur_wrk_path)
{
stds.push((cfield.0.clone(), cfield.1.clone()));
}
else
{
panic!("can not find field! {}||| {:?}", rfield.as_ref(), cur_wrk_path);
}
}
if fld_decls.len() != stds.len()
{
panic!("some fields was not found: collect_fields_by_fielddecl");
}
return stds;
}
pub
fn get_name(&self) -> Option<&String>
{
return self.name.as_ref();
}
pub
fn get_name_safe(&self) -> &str
{
return self.name.as_ref().map_or(StructName::ANONYMOUS, |v|v.as_str());
}
pub
fn get_struct_fields_len(&self) -> usize
{
return self.struct_fields.len();
}
pub
fn get_struct_fields_iter(&self) -> std::slice::Iter<'_, Rc<StructTemplateData>>
{
return self.struct_fields.iter();
}
pub
fn get_fields(&self) -> &[Rc<StructTemplateData>]
{
return self.struct_fields.as_slice()
}
}
#[derive(Debug, Clone)]
pub enum StructTemplateEnum
{
Unit,
TupleList(Vec<TemplateArgs>),
TupleStruct(StructTemplate)
}
impl fmt::Display for StructTemplateEnum
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match *self
{
StructTemplateEnum::Unit =>
writeln!(f, "-> unit"),
StructTemplateEnum::TupleList(ref args) =>
writeln!(f, "-> list: {}", args.iter().map(|v| format!("{}", v)).collect::<Vec<String>>().join(" ")),
StructTemplateEnum::TupleStruct(ref sttp) =>
writeln!(f, "-> struct: {}", sttp)
}
}
}
impl StructTemplateEnum
{
pub
fn push_value(&mut self, field_name: Option<&str>, cmpa: TemplateArgs)
{
match *self
{
StructTemplateEnum::Unit =>
{
panic!("asserion error: can not 'push_value' in 'Unit' for enum \
{:?} {}", field_name, cmpa);
},
StructTemplateEnum::TupleList(ref mut e_cmpa) =>
{
e_cmpa.push(cmpa);
},
StructTemplateEnum::TupleStruct(ref mut e_cmpa) =>
{
e_cmpa.push_value(field_name.unwrap(), cmpa);
},
}
}
}
#[derive(Debug, Clone)]
pub struct StructEnumTemplate
{
enum_name: String,
enum_item_name: String,
enum_item: StructTemplateEnum,
}
impl fmt::Display for StructEnumTemplate
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
writeln!(f, "Enum: {}, item: {} {}", self.enum_name,
self.enum_item_name, self.enum_item)
}
}
impl StructEnumTemplate
{
pub
fn new_tuple_struct(name: &str, variant_name: &str, len: usize) -> Self
{
return
Self
{
enum_name: name.to_string(),
enum_item_name: variant_name.to_string(),
enum_item:
StructTemplateEnum::TupleStruct(
StructTemplate::new_anon(len)
)
};
}
pub
fn new_unit(name: &str, variant_name: &str) -> Self
{
return
Self
{
enum_name: name.to_string(),
enum_item_name: variant_name.to_string(),
enum_item:
StructTemplateEnum::Unit
};
}
pub
fn new_tuple_variant(name: &str, variant_name: &str, len: usize) -> Self
{
return
Self
{
enum_name: name.to_string(),
enum_item_name: variant_name.to_string(),
enum_item:
StructTemplateEnum::TupleList(
Vec::with_capacity(len)
)
};
}
pub
fn push_value(&mut self, field_name: Option<&str>, cmpa: TemplateArgs)
{
self.enum_item.push_value(field_name, cmpa);
}
pub
fn get_enum_name(&self) -> &String
{
return &self.enum_name;
}
pub
fn get_enum_item_name(&self) -> &String
{
return &self.enum_item_name;
}
pub
fn get_enum_item(&self) -> &StructTemplateEnum
{
return &self.enum_item;
}
}
#[derive(Debug, Clone)]
pub enum Template
{
Uninit,
Structure( StructTemplate ),
Enum( StructEnumTemplate ),
AnonSequence( Vec<TemplateArgs> ),
}
impl fmt::Display for Template
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match *self
{
Template::Uninit => write!(f, "uninit!"),
Template::Structure(ref s) => writeln!(f, "{}", s),
Template::Enum(ref e) => writeln!(f, "{}", e),
Template::AnonSequence(ref seq) =>
writeln!(f, "{}", seq.iter().map(|v| format!("{}", v)).collect::<Vec<String>>().join("\n")),
}
}
}
impl Template
{
pub
fn push_value(&mut self, field_name: Option<&str>, cmpa: TemplateArgs)
{
match *self
{
Self::Structure(ref mut s) =>
{
s.push_value(field_name.unwrap(), cmpa);
},
Self::Enum(ref mut en) =>
{
en.push_value(field_name, cmpa);
},
Self::AnonSequence(ref mut ans) =>
{
ans.push(cmpa);
},
Self::Uninit =>
{
panic!("impossible!");
}
}
}
pub
fn push_struct(&mut self, field_name: Option<&str>, sttp: StructTemplate)
{
match *self
{
Self::Structure(ref mut s) =>
{
s.struct_fields.push(
Rc::new(
StructTemplateData::new_field(
field_name.unwrap(),
TemplateArgs::Structure(sttp)
)
)
);
},
Self::Enum(ref mut e) =>
{
e.push_value(field_name, TemplateArgs::Structure(sttp));
},
Self::AnonSequence(ref mut ans) =>
{
ans.push(TemplateArgs::new_arg_struct(sttp));
},
Self::Uninit =>
{
panic!("impossible");
}
}
}
pub
fn push_enum(&mut self, field_name: Option<&str>, set: StructEnumTemplate)
{
match *self
{
Self::Structure(ref mut s) =>
{
s.struct_fields.push(
Rc::new(
StructTemplateData::new_field(
field_name.unwrap(),
TemplateArgs::Enumerator(set)
)
)
);
},
Self::Enum(ref mut e) =>
{
e.push_value(field_name, TemplateArgs::Enumerator(set));
},
Self::AnonSequence(ref mut ans) =>
{
ans.push(TemplateArgs::new_arg_enum(set));
},
Self::Uninit =>
{
panic!("impossible");
}
}
}
pub
fn push_anon_seq(&mut self, field_name: Option<&str>, seq: Vec<TemplateArgs>)
{
match *self
{
Self::Structure(ref mut s) =>
{
s.push_value(field_name.unwrap(), TemplateArgs::new_arg_vector(seq));
},
Self::Enum(ref mut en) =>
{
en.push_value(field_name, TemplateArgs::new_arg_vector(seq));
},
Self::AnonSequence(ref mut ans) =>
{
ans.push(TemplateArgs::new_arg_vector(seq));
},
Self::Uninit =>
{
panic!("impossible!");
}
}
}
}
#[derive(Debug, Clone)]
pub enum StructReturnType
{
Value(TemplateArgs),
Template(Template),
}