mod vectortype;
pub use vectortype::VectorType;
mod arraytype;
pub use arraytype::ArrayType;
mod tupletype;
pub use tupletype::TupleType;
mod utils;
pub use utils::NestedValueParser;
use super::{RType, RTypeTrait, TypeError};
use regex::Regex;
use std::sync::OnceLock;
pub const VECTOR_REGEX_STR: &'static str = r"^Vec<(.*)>"; pub static VECTOR_REGEX: OnceLock<Regex> = OnceLock::new();
pub const ARRAY_REGEX_STR: &'static str = r"^\[ ?(.+)(?:,|;) ?([\d]+) ?\]";
pub static ARRAY_REGEX: OnceLock<Regex> = OnceLock::new();
pub const TUPLE_REGEX_STR: &'static str = r"^\( ?(.+) ?\)";
pub static TUPLE_REGEX: OnceLock<Regex> = OnceLock::new();
#[derive(Debug, Eq, PartialEq)]
pub enum ContainerType {
Vector(Box<RType>),
Tuple(Vec<Box<RType>>),
Array(Box<RType>, usize),
}
impl RTypeTrait for ContainerType {
fn from_typestr<T: AsRef<str>>(typestr: T) -> Result<Self, super::TypeError> where Self: Sized {
let typestr = typestr.as_ref();
let vec_re = VECTOR_REGEX.get_or_init(|| Regex::new(VECTOR_REGEX_STR).unwrap());
let arr_re = ARRAY_REGEX.get_or_init(|| Regex::new(ARRAY_REGEX_STR).unwrap());
let tuple_re = TUPLE_REGEX.get_or_init(|| Regex::new(TUPLE_REGEX_STR).unwrap());
if let Some(captures) = vec_re.captures(&typestr) {
let inner_type = captures.get(1).unwrap().as_str();
return Ok(ContainerType::Vector(Box::new(RType::from_typestr(inner_type)?)));
}
if let Some(captures) = arr_re.captures(&typestr) {
let inner_type = captures.get(1).unwrap().as_str();
let size = captures.get(2).unwrap().as_str().parse::<usize>().unwrap();
return Ok(ContainerType::Array(Box::new(RType::from_typestr(inner_type)?), size));
}
if let Some(captures) = tuple_re.captures(&typestr) {
let inner_str = captures.get(1).unwrap().as_str();
let types_in_str: Vec<String> = NestedValueParser::parse_nested_str(inner_str, '(', false); let mut tuple_types: Vec<Box<RType>> = vec![];
for inner_type in types_in_str {
let inner_type = inner_type.trim();
tuple_types.push(Box::new(RType::from_typestr(inner_type)?))
}
return Ok(ContainerType::Tuple(tuple_types));
}
Err(TypeError::ContainerTypeUnknown(typestr.to_string()))
}
fn to_typestr(&self) -> String {
match self {
ContainerType::Vector(x) => {
VectorType::wrap_typestr(&x.to_typestr())
},
ContainerType::Array(x, y) => {
ArrayType::wrap_typestr(&x.to_typestr(), y)
},
ContainerType::Tuple(vx) => {
TupleType::wrap_types_with_typefn(vx, |item: &RType| item.to_typestr())
}
}
}
fn to_typestr_no_ref(&self) -> String {
match self {
ContainerType::Vector(x) => {
VectorType::wrap_typestr(&x.to_typestr_no_ref())
},
ContainerType::Array(x, y) => {
ArrayType::wrap_typestr(&x.to_typestr_no_ref(), y)
},
ContainerType::Tuple(vx) => {
TupleType::wrap_types_with_typefn(vx, |item: &RType| item.to_typestr_no_ref())
}
}
}
fn to_typestr_no_life(&self) -> String {
match self {
ContainerType::Vector(x) => {
VectorType::wrap_typestr(&x.to_typestr_no_life())
},
ContainerType::Array(x, y) => {
ArrayType::wrap_typestr(&x.to_typestr_no_life(), y)
},
ContainerType::Tuple(vx) => {
TupleType::wrap_types_with_typefn(vx, |item: &RType| item.to_typestr_no_life())
}
}
}
fn collect_lifetimes(&self, into: &mut Vec<String>) {
match self {
ContainerType::Vector(x) => {
x.collect_lifetimes(into);
},
ContainerType::Array(x, _) => {
x.collect_lifetimes(into);
},
ContainerType::Tuple(vx) => {
for x in vx {
x.collect_lifetimes(into);
}
}
}
}
fn is_const(&self) -> bool {
match self {
ContainerType::Vector(_) => {
false
},
ContainerType::Array(x, _) => {
x.is_const()
},
ContainerType::Tuple(vx) => {
for x in vx {
if !x.is_const() {
return false;
}
}
true
}
}
}
fn value_is_valid(&self, valuestr: &str) -> bool {
match self {
ContainerType::Array(x, y) => {ArrayType::value_is_valid(valuestr, x, y)},
ContainerType::Vector(x) => {VectorType::value_is_valid(valuestr, x)},
ContainerType::Tuple(vx) => {TupleType::value_is_valid(valuestr, vx)},
}
}
fn get_depth(&self, counter: usize) -> usize {
let counter = counter.saturating_add(1);
match self {
Self::Vector(x) => {x.get_depth(counter)},
Self::Array(x, _) => {x.get_depth(counter)},
Self::Tuple(vx) => {
let mut inner_cnt = 0;
for x in vx {
let cnt = x.get_depth(0);
if cnt > inner_cnt {inner_cnt = cnt}
}
counter.saturating_add(inner_cnt)
}
}
}
fn get_breadth(&self, counter: usize) -> usize {
match self {
Self::Array(x, _) => {x.get_breadth(counter)},
Self::Vector(x) => {x.get_breadth(counter)},
Self::Tuple(vx) => {
let mut breadth: usize = counter ; for x in vx {
breadth = breadth.saturating_add(x.get_breadth(0));
}
breadth
}
}
}
fn wrap_valuestr(&self, valuestr: &str) -> String {
match self {
ContainerType::Array(x, _) => {ArrayType::wrap_valuestr(valuestr, x)},
ContainerType::Vector(x) => {VectorType::wrap_valuestr(valuestr, x)},
ContainerType::Tuple(vx) => {TupleType::wrap_valuestr(valuestr, vx)},
}
}
fn can_match_as_key(&self) -> bool {
match self {
ContainerType::Array(x, _) => {x.can_match_as_key()},
ContainerType::Vector(x) => {x.can_match_as_key()},
ContainerType::Tuple(vx) => {
for x in vx {
if !x.can_match_as_key() {
return false
}
}
true
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{NumericType, StringType, SpecialType, Reference};
#[test]
fn test_parse_container_type() {
let input = "Vec< &str>";
let result = ContainerType::from_typestr(input).unwrap();
let expected = ContainerType::Vector(Box::new(RType::String(Reference::Naked,StringType::str)));
assert_eq!(expected, result);
let input = "[usize, 3]";
let result = ContainerType::from_typestr(input).unwrap();
let expected = ContainerType::Array(
Box::new(RType::Numeric(Reference::None,NumericType::usize)), 3
);
assert_eq!(expected, result);
let input = "(usize,usize,enum:MyEnum)";
let result = ContainerType::from_typestr(input).unwrap();
let expected = ContainerType::Tuple( vec![
Box::new(RType::Numeric(Reference::None,NumericType::usize)),
Box::new(RType::Numeric(Reference::None,NumericType::usize)),
Box::new(RType::Special(Reference::None,SpecialType::Enum("MyEnum".to_string())))
]);
assert_eq!(expected, result);
let expected = false;
assert_eq!(expected, result.is_const());
let input = "(Vec<&str>, usize, enum:MyEnum)";
let result = ContainerType::from_typestr(input).unwrap().to_typestr();
let expected = "(Vec<&str>, usize, MyEnum)";
assert_eq!(expected, result);
let input = "(Vec<&'a str>)";
let result = ContainerType::from_typestr(input).unwrap().to_typestr();
let expected = "(Vec<&'a str>)";
assert_eq!(expected, result);
let result = ContainerType::from_typestr(input).unwrap().to_typestr_no_ref();
let expected = "(Vec<str>)";
assert_eq!(expected, result);
let input = "[usize, 3]";
let result = ContainerType::from_typestr(input).unwrap();
let values = "[3,3,3]";
assert!(result.value_is_valid(values));
let values = "[art,3.52,3]";
assert_eq!(false, result.value_is_valid(values));
}
}