181 lines
5.3 KiB
Rust
181 lines
5.3 KiB
Rust
//! Primitive types for property type validators
|
|
|
|
use serde_json::Value;
|
|
use std::{convert::TryFrom, fmt, ops::BitOrAssign};
|
|
|
|
/// For faster error handling in "type" keyword validator we have this enum, to match
|
|
/// with it instead of a string.
|
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
|
#[allow(missing_docs)]
|
|
pub enum PrimitiveType {
|
|
Array,
|
|
Boolean,
|
|
Integer,
|
|
Null,
|
|
Number,
|
|
Object,
|
|
String,
|
|
}
|
|
|
|
impl fmt::Display for PrimitiveType {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
PrimitiveType::Array => f.write_str("array"),
|
|
PrimitiveType::Boolean => f.write_str("boolean"),
|
|
PrimitiveType::Integer => f.write_str("integer"),
|
|
PrimitiveType::Null => f.write_str("null"),
|
|
PrimitiveType::Number => f.write_str("number"),
|
|
PrimitiveType::Object => f.write_str("object"),
|
|
PrimitiveType::String => f.write_str("string"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&str> for PrimitiveType {
|
|
type Error = ();
|
|
|
|
#[inline]
|
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
|
match value {
|
|
"array" => Ok(PrimitiveType::Array),
|
|
"boolean" => Ok(PrimitiveType::Boolean),
|
|
"integer" => Ok(PrimitiveType::Integer),
|
|
"null" => Ok(PrimitiveType::Null),
|
|
"number" => Ok(PrimitiveType::Number),
|
|
"object" => Ok(PrimitiveType::Object),
|
|
"string" => Ok(PrimitiveType::String),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&Value> for PrimitiveType {
|
|
fn from(instance: &Value) -> Self {
|
|
match instance {
|
|
Value::Null => PrimitiveType::Null,
|
|
Value::Bool(_) => PrimitiveType::Boolean,
|
|
Value::Number(_) => PrimitiveType::Number,
|
|
Value::String(_) => PrimitiveType::String,
|
|
Value::Array(_) => PrimitiveType::Array,
|
|
Value::Object(_) => PrimitiveType::Object,
|
|
}
|
|
}
|
|
}
|
|
|
|
const fn primitive_type_to_bit_map_representation(primitive_type: PrimitiveType) -> u8 {
|
|
match primitive_type {
|
|
PrimitiveType::Array => 1,
|
|
PrimitiveType::Boolean => 2,
|
|
PrimitiveType::Integer => 4,
|
|
PrimitiveType::Null => 8,
|
|
PrimitiveType::Number => 16,
|
|
PrimitiveType::Object => 32,
|
|
PrimitiveType::String => 64,
|
|
}
|
|
}
|
|
|
|
fn bit_map_representation_primitive_type(bit_representation: u8) -> PrimitiveType {
|
|
match bit_representation {
|
|
1 => PrimitiveType::Array,
|
|
2 => PrimitiveType::Boolean,
|
|
4 => PrimitiveType::Integer,
|
|
8 => PrimitiveType::Null,
|
|
16 => PrimitiveType::Number,
|
|
32 => PrimitiveType::Object,
|
|
64 => PrimitiveType::String,
|
|
_ => unreachable!("This should never be possible"),
|
|
}
|
|
}
|
|
|
|
/// Compact representation of multiple `PrimitiveType`
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct PrimitiveTypesBitMap {
|
|
inner: u8,
|
|
}
|
|
impl PrimitiveTypesBitMap {
|
|
pub(crate) const fn new() -> Self {
|
|
Self { inner: 0 }
|
|
}
|
|
|
|
#[inline]
|
|
pub(crate) const fn add_type(mut self, primitive_type: PrimitiveType) -> Self {
|
|
self.inner |= primitive_type_to_bit_map_representation(primitive_type);
|
|
self
|
|
}
|
|
|
|
pub(crate) const fn contains_type(self, primitive_type: PrimitiveType) -> bool {
|
|
primitive_type_to_bit_map_representation(primitive_type) & self.inner != 0
|
|
}
|
|
}
|
|
impl BitOrAssign<PrimitiveType> for PrimitiveTypesBitMap {
|
|
#[inline]
|
|
fn bitor_assign(&mut self, rhs: PrimitiveType) {
|
|
*self = self.add_type(rhs);
|
|
}
|
|
}
|
|
impl IntoIterator for PrimitiveTypesBitMap {
|
|
type Item = PrimitiveType;
|
|
type IntoIter = PrimitiveTypesBitMapIterator;
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
PrimitiveTypesBitMapIterator {
|
|
idx: 0,
|
|
bit_map: self,
|
|
}
|
|
}
|
|
}
|
|
#[cfg(test)]
|
|
impl From<Vec<PrimitiveType>> for PrimitiveTypesBitMap {
|
|
fn from(value: Vec<PrimitiveType>) -> Self {
|
|
let mut result = Self::new();
|
|
for primitive_type in value {
|
|
result |= primitive_type;
|
|
}
|
|
result
|
|
}
|
|
}
|
|
|
|
/// Iterator over all `PrimitiveType` present in a `PrimitiveTypesBitMap`
|
|
#[derive(Debug)]
|
|
pub struct PrimitiveTypesBitMapIterator {
|
|
idx: u8,
|
|
bit_map: PrimitiveTypesBitMap,
|
|
}
|
|
impl Iterator for PrimitiveTypesBitMapIterator {
|
|
type Item = PrimitiveType;
|
|
#[allow(clippy::arithmetic_side_effects)]
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.idx <= 7 {
|
|
let bit_value = 1 << self.idx;
|
|
self.idx += 1;
|
|
if self.bit_map.inner & bit_value != 0 {
|
|
return Some(bit_map_representation_primitive_type(bit_value));
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_multiple_types() {
|
|
let mut types = PrimitiveTypesBitMap::new();
|
|
types |= PrimitiveType::Null;
|
|
types |= PrimitiveType::String;
|
|
types |= PrimitiveType::Array;
|
|
assert!(types.contains_type(PrimitiveType::Null));
|
|
assert!(types.contains_type(PrimitiveType::String));
|
|
assert!(types.contains_type(PrimitiveType::Array));
|
|
assert_eq!(
|
|
types.into_iter().collect::<Vec<PrimitiveType>>(),
|
|
vec![
|
|
PrimitiveType::Array,
|
|
PrimitiveType::Null,
|
|
PrimitiveType::String
|
|
]
|
|
)
|
|
}
|
|
}
|