dust/src/value.rs

202 lines
5.4 KiB
Rust
Raw Normal View History

2024-02-25 18:49:26 +00:00
use std::{
2024-02-25 19:26:22 +00:00
cmp::Ordering,
2024-02-28 23:36:47 +00:00
collections::BTreeMap,
2024-03-06 20:36:58 +00:00
fmt::{self, Display, Formatter},
2024-02-25 18:49:26 +00:00
ops::Range,
sync::{Arc, OnceLock},
};
2024-03-06 22:32:31 +00:00
use crate::{
abstract_tree::{Identifier, Type},
error::ValidationError,
};
2024-02-25 18:49:26 +00:00
pub static NONE: OnceLock<Value> = OnceLock::new();
2024-03-06 20:36:58 +00:00
fn get_none<'a>() -> &'a Value {
NONE.get_or_init(|| {
Value(Arc::new(ValueInner::Enum(
Identifier::new("Option"),
Identifier::new("None"),
)))
})
}
2024-02-25 18:49:26 +00:00
#[derive(Clone, Debug, PartialEq)]
pub struct Value(Arc<ValueInner>);
impl Value {
pub fn inner(&self) -> &Arc<ValueInner> {
&self.0
}
2024-03-02 00:15:03 +00:00
pub fn none() -> Self {
2024-03-06 20:36:58 +00:00
get_none().clone()
2024-03-02 00:15:03 +00:00
}
2024-02-25 18:49:26 +00:00
pub fn boolean(boolean: bool) -> Self {
Value(Arc::new(ValueInner::Boolean(boolean)))
}
pub fn float(float: f64) -> Self {
Value(Arc::new(ValueInner::Float(float)))
}
pub fn integer(integer: i64) -> Self {
Value(Arc::new(ValueInner::Integer(integer)))
}
2024-02-26 21:27:01 +00:00
pub fn list(list: Vec<Value>) -> Self {
2024-02-25 18:49:26 +00:00
Value(Arc::new(ValueInner::List(list)))
}
2024-02-28 23:36:47 +00:00
pub fn map(map: BTreeMap<Identifier, Value>) -> Self {
Value(Arc::new(ValueInner::Map(map)))
}
2024-02-25 18:49:26 +00:00
pub fn range(range: Range<i64>) -> Self {
Value(Arc::new(ValueInner::Range(range)))
}
pub fn string<T: ToString>(string: T) -> Self {
Value(Arc::new(ValueInner::String(string.to_string())))
}
2024-02-28 23:36:47 +00:00
pub fn r#enum(name: Identifier, variant: Identifier) -> Self {
Value(Arc::new(ValueInner::Enum(name, variant)))
2024-02-25 18:49:26 +00:00
}
2024-02-25 19:26:22 +00:00
2024-03-06 22:32:31 +00:00
pub fn r#type(&self) -> Type {
match self.0.as_ref() {
ValueInner::Boolean(_) => Type::Boolean,
ValueInner::Float(_) => Type::Float,
ValueInner::Integer(_) => Type::Integer,
ValueInner::List(values) => {
let mut types = Vec::with_capacity(values.len());
for value in values {
types.push(value.r#type());
}
Type::ListExact(types)
}
ValueInner::Map(_) => Type::Map,
ValueInner::Range(_) => Type::Range,
ValueInner::String(_) => Type::String,
ValueInner::Enum(name, _) => Type::Custom(name.clone()),
}
}
pub fn as_boolean(&self) -> Result<bool, ValidationError> {
2024-02-25 19:26:22 +00:00
if let ValueInner::Boolean(boolean) = self.0.as_ref() {
return Ok(*boolean);
}
Err(ValidationError::ExpectedBoolean)
2024-02-25 19:26:22 +00:00
}
2024-03-06 20:36:58 +00:00
2024-03-07 11:33:54 +00:00
pub fn as_number(&self) -> Result<bool, ValidationError> {
if let ValueInner::Boolean(boolean) = self.0.as_ref() {
return Ok(*boolean);
}
Err(ValidationError::ExpectedBoolean)
}
2024-03-06 20:36:58 +00:00
pub fn is_none(&self) -> bool {
self == get_none()
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use ValueInner::*;
match self.inner().as_ref() {
Boolean(boolean) => write!(f, "{boolean}"),
Float(float) => write!(f, "{float}"),
Integer(integer) => write!(f, "{integer}"),
List(_) => todo!(),
Map(_) => todo!(),
Range(_) => todo!(),
String(_) => todo!(),
Enum(_, _) => todo!(),
}
}
2024-02-25 19:26:22 +00:00
}
impl Eq for Value {}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Value {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.as_ref().cmp(other.0.as_ref())
}
2024-02-25 18:49:26 +00:00
}
#[derive(Clone, Debug, PartialEq)]
pub enum ValueInner {
Boolean(bool),
Float(f64),
Integer(i64),
2024-02-26 21:27:01 +00:00
List(Vec<Value>),
2024-02-28 23:36:47 +00:00
Map(BTreeMap<Identifier, Value>),
2024-02-25 18:49:26 +00:00
Range(Range<i64>),
String(String),
2024-02-28 23:36:47 +00:00
Enum(Identifier, Identifier),
2024-02-25 18:49:26 +00:00
}
2024-02-25 19:26:22 +00:00
impl Eq for ValueInner {}
impl PartialOrd for ValueInner {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ValueInner {
fn cmp(&self, other: &Self) -> Ordering {
use ValueInner::*;
match (self, other) {
(Boolean(left), Boolean(right)) => left.cmp(right),
(Boolean(_), _) => Ordering::Greater,
(Float(left), Float(right)) => left.total_cmp(right),
(Float(_), _) => Ordering::Greater,
(Integer(left), Integer(right)) => left.cmp(right),
(Integer(_), _) => Ordering::Greater,
(List(left), List(right)) => left.cmp(right),
(List(_), _) => Ordering::Greater,
2024-02-28 23:36:47 +00:00
(Map(left), Map(right)) => left.cmp(right),
(Map(_), _) => Ordering::Greater,
2024-02-25 19:26:22 +00:00
(Range(left), Range(right)) => {
let start_cmp = left.start.cmp(&right.start);
if start_cmp.is_eq() {
left.end.cmp(&right.end)
} else {
start_cmp
}
}
(Range(_), _) => Ordering::Greater,
(String(left), String(right)) => left.cmp(right),
(String(_), _) => Ordering::Greater,
2024-02-28 23:36:47 +00:00
(Enum(name_left, variant_left), Enum(name_right, variant_right)) => {
let name_cmp = name_left.cmp(name_right);
if name_cmp.is_eq() {
variant_left.cmp(variant_right)
} else {
name_cmp
}
}
(Enum(..), _) => Ordering::Greater,
2024-02-25 19:26:22 +00:00
}
}
}