use crate::context::{State, Update};
use crate::value::Value;
use indexmap::IndexMap;
use regex::Regex;
use std::fmt;
use std::sync::Arc;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub enum Kind {
#[default]
Any,
String,
Number,
Boolean,
Object,
Array,
Null,
NaN,
Function,
Never,
Check,
Regexp,
Integer,
Date,
BigInt,
List,
}
impl Kind {
pub fn as_str(self) -> &'static str {
match self {
Kind::Any => "any",
Kind::String => "string",
Kind::Number => "number",
Kind::Boolean => "boolean",
Kind::Object => "object",
Kind::Array => "array",
Kind::Null => "null",
Kind::NaN => "nan",
Kind::Function => "function",
Kind::Never => "never",
Kind::Check => "check",
Kind::Regexp => "regexp",
Kind::Integer => "integer",
Kind::Date => "date",
Kind::BigInt => "bigint",
Kind::List => "list",
}
}
}
impl Kind {
pub fn from_name(name: &str) -> Option<Kind> {
ALL_KINDS
.iter()
.copied()
.find(|k| k.as_str() == name || k.as_str().eq_ignore_ascii_case(name))
}
}
const ALL_KINDS: [Kind; 16] = [
Kind::Any,
Kind::String,
Kind::Number,
Kind::Boolean,
Kind::Object,
Kind::Array,
Kind::Null,
Kind::NaN,
Kind::Function,
Kind::Never,
Kind::Check,
Kind::Regexp,
Kind::Integer,
Kind::Date,
Kind::BigInt,
Kind::List,
];
impl fmt::Display for Kind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Token {
Any,
String,
Number,
Boolean,
Object,
Array,
Function,
Integer,
Date,
BigInt,
}
impl Token {
pub fn kind(self) -> Kind {
match self {
Token::Any => Kind::Any,
Token::String => Kind::String,
Token::Number => Kind::Number,
Token::Boolean => Kind::Boolean,
Token::Object => Kind::Object,
Token::Array => Kind::Array,
Token::Function => Kind::Function,
Token::Integer => Kind::Integer,
Token::Date => Kind::Date,
Token::BigInt => Kind::BigInt,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum ListMode {
#[default]
None,
One,
Some,
All,
}
pub type ValidatorFn = dyn Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync;
#[derive(Clone)]
pub struct Validator {
pub name: String,
pub func: Arc<ValidatorFn>,
pub args: Vec<Value>,
pub suffix: Option<String>,
pub inner: Option<Arc<crate::isolate::Inner>>,
}
impl fmt::Debug for Validator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Validator({})", self.name)
}
}
#[derive(Clone, Debug, Default)]
pub struct Node {
pub kind: Kind,
pub required: bool,
pub required_set: bool,
pub kind_set: bool,
pub skippable: bool,
pub silent: bool,
pub empty: bool,
pub nullable: bool,
pub has_default: bool,
pub default: Value,
pub literal: Option<Value>,
pub obj_children: IndexMap<String, Node>,
pub obj_rest: Option<Box<Node>>,
pub consumed: std::collections::HashSet<String>,
pub obj_keys: Vec<Arc<str>>,
pub plain: bool,
pub arr_children: Vec<Node>,
pub arr_child: Option<Box<Node>>,
pub arr_rest: Option<Box<Node>>,
pub befores: Vec<Validator>,
pub afters: Vec<Validator>,
pub regexp: Option<Regex>,
pub regexp_src: String,
pub fault_msg: Option<String>,
pub arg_fault: bool,
pub list_mode: ListMode,
pub list: Vec<Node>,
pub disc: Option<crate::discriminated::Disc>,
pub exact_vals: Vec<Value>,
pub has_exact: bool,
pub define_name: Option<String>,
pub refer_name: Option<String>,
pub refer_fill: bool,
pub refer_strict: bool,
pub rename_to: Option<String>,
pub rename_keep: bool,
pub rename_claim: Vec<String>,
pub meta: IndexMap<String, Value>,
}
impl Node {
pub fn of(kind: Kind) -> Node {
Node {
kind,
..Default::default()
}
}
pub fn is_open(&self) -> bool {
self.obj_rest.is_some()
}
pub fn is_ignore(&self) -> bool {
self.silent && self.skippable
}
pub fn zero_for(kind: Kind) -> Value {
match kind {
Kind::String => Value::Str(String::new()),
Kind::Number | Kind::Integer => Value::Num(0.0),
Kind::Boolean => Value::Bool(false),
Kind::Object => Value::Obj(Default::default()),
Kind::Array => Value::Arr(Vec::new()),
_ => Value::Undefined,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kinds_and_tokens_name_themselves() {
let all = [
Kind::Any,
Kind::String,
Kind::Number,
Kind::Boolean,
Kind::Object,
Kind::Array,
Kind::Null,
Kind::NaN,
Kind::Function,
Kind::Never,
Kind::Check,
Kind::Regexp,
Kind::Integer,
Kind::Date,
Kind::BigInt,
Kind::List,
];
let names: Vec<String> = all.iter().map(|k| k.to_string()).collect();
assert_eq!(names.join(","), "any,string,number,boolean,object,array,null,nan,function,never,check,regexp,integer,date,bigint,list");
let tokens = [
Token::Any,
Token::String,
Token::Number,
Token::Boolean,
Token::Object,
Token::Array,
Token::Function,
Token::Integer,
Token::Date,
Token::BigInt,
];
let kinds: Vec<&str> = tokens.iter().map(|t| t.kind().as_str()).collect();
assert_eq!(
kinds.join(","),
"any,string,number,boolean,object,array,function,integer,date,bigint"
);
assert_eq!(Node::default().kind, Kind::Any);
assert_eq!(Node::default().list_mode, ListMode::None);
assert!(!Node::of(Kind::Object).is_open());
let v = Validator {
name: "x".into(),
func: Arc::new(|_, _| true),
args: vec![],
suffix: None,
inner: None,
};
assert_eq!(format!("{:?}", v), "Validator(x)");
assert_eq!(Node::zero_for(Kind::String), Value::Str(String::new()));
assert_eq!(Node::zero_for(Kind::Integer), Value::Num(0.0));
assert_eq!(Node::zero_for(Kind::Boolean), Value::Bool(false));
assert_eq!(Node::zero_for(Kind::Object), Value::Obj(Default::default()));
assert_eq!(Node::zero_for(Kind::Array), Value::Arr(vec![]));
assert_eq!(Node::zero_for(Kind::Date), Value::Undefined);
}
}