mod defs;
mod fabric;
mod generic;
mod origin;
mod types;
pub use defs::Composite;
pub use defs::Primitive;
pub use defs::Referred;
pub use fabric::{TypeAsString, TypeTokenStream, VariableTokenStream};
pub use generic::ExtractGenerics;
pub use origin::OriginType;
pub use types::Extract;
use crate::{context::Context, error::E};
use std::{collections::HashMap, ops::Deref};
pub struct NatureDef {
pub nature: Nature,
pub module: Option<String>,
}
impl NatureDef {
pub fn new(nature: Nature, module: Option<String>) -> Self {
Self { nature, module }
}
pub fn get_mut(&mut self) -> &mut Nature {
&mut self.nature
}
pub fn get(&self) -> &Nature {
&self.nature
}
pub fn extract(&self) -> Nature {
self.nature.clone()
}
}
pub struct Natures(HashMap<String, NatureDef>);
impl Natures {
pub fn new() -> Self {
Natures(HashMap::new())
}
pub fn is_any_bound(natures: &[Nature]) -> bool {
for nature in natures.iter() {
if let Nature::Referred(Referred::Field(_, _, _, binding)) = nature {
if binding.is_some() {
return true;
}
}
}
false
}
pub fn get_fn_args_names(args: &[Nature]) -> Vec<String> {
args.iter()
.filter_map(|arg| {
if let Nature::Referred(Referred::FuncArg(name, _, _, _)) = arg {
Some(name.to_owned())
} else {
None
}
})
.collect::<Vec<String>>()
}
pub fn contains(&self, name: &str) -> bool {
self.0.contains_key(name)
}
pub fn insert(&mut self, name: &str, nature: Nature, module: Option<String>) -> Result<(), E> {
if self.contains(name) {
Err(E::EntityExist(name.to_owned()))
} else {
let _ = self
.0
.insert(name.to_owned(), NatureDef::new(nature, module));
Ok(())
}
}
pub fn get_module_of(&self, name: &str) -> Option<String> {
self.0.get(name).and_then(|n| n.module.clone())
}
pub fn exists_in_module(&self, name: &str, module: &str) -> bool {
self.0
.get(name)
.map(|n| n.module.as_ref().map(|m| m == module).unwrap_or_default())
.unwrap_or_default()
}
pub fn get_mut(
&mut self,
name: &str,
default_nature: Option<Nature>,
default_module: Option<String>,
) -> Option<&mut Nature> {
if let (exists, Some(default_nature)) = (self.0.contains_key(name), default_nature) {
if !exists {
let _ = self.0.insert(
name.to_owned(),
NatureDef::new(default_nature, default_module),
);
}
}
self.0.get_mut(name).map(|n| n.get_mut())
}
pub fn filter(&self, filter: fn(&Nature) -> bool) -> Vec<Nature> {
let mut natures: Vec<Nature> = vec![];
for (_, n) in self.0.iter() {
if filter(n.get()) {
natures.push(n.extract());
}
}
natures
}
pub fn iter(&self) -> impl Iterator<Item = (&String, &Nature)> {
self.0.iter().map(|(k, n)| (k, n.get()))
}
}
#[derive(Clone, Debug)]
pub enum Nature {
Primitive(Primitive),
Referred(Referred),
Composite(Composite),
}
impl Nature {
pub fn get_fn_args_names(&self) -> Result<Vec<String>, E> {
if let Nature::Composite(Composite::Func(_, args, _, _, _)) = self {
Ok(Natures::get_fn_args_names(args))
} else {
Err(E::Parsing("Fail to find arguments of function".to_string()))
}
}
pub fn is_fn_async(&self) -> Result<bool, E> {
if let Nature::Composite(Composite::Func(_, _, _, asyncness, _)) = self {
Ok(*asyncness)
} else {
Err(E::Parsing("Fail to find function".to_string()))
}
}
pub fn bind(&mut self, nature: Nature) -> Result<(), E> {
match self {
Self::Primitive(_) => Err(E::Parsing(String::from("Primitive type cannot be bound"))),
Self::Referred(re) => match re {
Referred::Struct(_, _, natures) => {
natures.push(nature);
Ok(())
}
Referred::TupleStruct(_, _, field) => {
let _ = field.insert(Box::new(nature));
Ok(())
}
Referred::Enum(_, _, natures, ..) => {
natures.push(nature);
Ok(())
}
Referred::EnumVariant(_, _, natures, ..) => {
natures.push(nature);
Ok(())
}
_ => Err(E::NotSupported("Referred".to_owned())),
},
Self::Composite(othr) => match othr {
Composite::HashMap(_, k, v) => {
if k.is_none() {
if let Self::Primitive(p) = nature {
let _ = k.insert(p);
Ok(())
} else {
Err(E::Parsing(String::from(
"HashMap can use as key only Primitive type",
)))
}
} else if v.is_none() {
let _ = v.insert(Box::new(nature));
Ok(())
} else {
Err(E::Parsing(String::from(
"HashMap entity already has been bound",
)))
}
}
Composite::Option(_, o) => {
if o.is_some() {
Err(E::Parsing(String::from(
"Option entity already has been bound",
)))
} else {
let _ = o.insert(Box::new(nature));
Ok(())
}
}
Composite::Result(_, r, e, _, _) => {
if r.is_some() && e.is_some() {
Err(E::Parsing(String::from(
"Result entity already has been bound",
)))
} else if r.is_none() {
let _ = r.insert(Box::new(nature));
Ok(())
} else {
let _ = e.insert(Box::new(nature));
Ok(())
}
}
Composite::Tuple(_, tys) => {
tys.push(nature);
Ok(())
}
Composite::Vec(_, v) => {
if v.is_some() {
Err(E::Parsing(String::from(
"Vec entity already has been bound",
)))
} else {
let _ = v.insert(Box::new(nature));
Ok(())
}
}
_ => Err(E::NotSupported(String::from("Composite"))),
},
}
}
pub fn is_method_constructor(&self) -> bool {
if let Nature::Referred(Referred::Field(_, _, nature, _)) = self {
if let Nature::Composite(Composite::Func(_, _, _, _, constructor)) = nature.deref() {
return *constructor;
}
}
false
}
pub fn is_field_ignored(&self) -> bool {
if let Nature::Referred(Referred::Field(name, context, _, _)) = self {
context.is_ignored(name)
} else {
false
}
}
pub fn check_ignored_fields(&self) -> Result<(), E> {
if let Nature::Referred(Referred::Struct(name, context, fields)) = self {
let ignored = context.ignored_list();
if ignored.is_empty() {
return Ok(());
}
let existed = fields
.iter()
.filter_map(|f| {
if let Nature::Referred(Referred::Field(name, _, _, _)) = f {
Some(name.to_owned())
} else {
None
}
})
.collect::<Vec<String>>();
for n in ignored {
if !existed.iter().any(|name| name == &n) {
return Err(E::Parsing(format!(
"Field in ignored list \"{n}\" isn't found in struct \"{name}\""
)));
}
}
Ok(())
} else {
Ok(())
}
}
pub fn get_context(&self) -> Result<&Context, E> {
Ok(match self {
Self::Primitive(_) => Err(E::Parsing(String::from("Primitives do not have context")))?,
Self::Composite(_composite) => {
Err(E::Parsing(String::from("Composite do not have context")))?
}
Self::Referred(refered) => match refered {
Referred::Enum(_, context, ..) => context,
Referred::EnumVariant(_, context, ..) => context,
Referred::Field(_, context, ..) => context,
Referred::Func(_, context, ..) => context,
Referred::FuncArg(_, context, ..) => context,
Referred::TupleStruct(_, context, ..) => context,
Referred::Struct(_, context, ..) => context,
Referred::Constant(_, context, ..) => context,
Referred::Ref(..) => {
Err(E::Parsing(String::from("Reference do not have context")))?
}
Referred::Generic(..) => {
Err(E::Parsing(String::from("Generic do not have context")))?
}
},
})
}
}