123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- use std::{
- any::Any,
- fmt::{Arguments, Formatter},
- };
- use bumpalo::Bump;
- /// Possible values for an attribute
- #[derive(Clone, Copy)]
- pub enum AttributeValue<'a> {
- /// Reference strs, most common
- Text(&'a str),
- /// Basic float values
- Float(f32),
- /// Basic Int values
- Int(i32),
- /// Basic bool values
- Bool(bool),
- /// Everything else
- Any(&'a dyn AnyAttributeValue),
- }
- impl<'a> PartialEq for AttributeValue<'a> {
- fn eq(&self, other: &Self) -> bool {
- match (self, other) {
- (Self::Text(l0), Self::Text(r0)) => l0 == r0,
- (Self::Float(l0), Self::Float(r0)) => l0 == r0,
- (Self::Int(l0), Self::Int(r0)) => l0 == r0,
- (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
- (Self::Any(l0), Self::Any(r0)) => (*l0).cmp_any(*r0),
- _ => false,
- }
- }
- }
- impl std::fmt::Debug for AttributeValue<'_> {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- match self {
- AttributeValue::Text(s) => write!(f, "AttributeValue::Text({:?})", s),
- AttributeValue::Float(v) => write!(f, "AttributeValue::Float({:?})", v),
- AttributeValue::Int(v) => write!(f, "AttributeValue::Int({:?})", v),
- AttributeValue::Bool(b) => write!(f, "AttributeValue::Bool({:?})", b),
- AttributeValue::Any(_) => write!(f, "AttributeValue::Any()"),
- }
- }
- }
- /// A value that can be converted into an attribute value
- pub trait IntoAttributeValue<'a> {
- /// Convert into an attribute value
- fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>;
- }
- impl<'a> IntoAttributeValue<'a> for &'a str {
- fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
- AttributeValue::Text(self)
- }
- }
- impl<'a> IntoAttributeValue<'a> for f32 {
- fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
- AttributeValue::Float(self)
- }
- }
- impl<'a> IntoAttributeValue<'a> for i32 {
- fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
- AttributeValue::Int(self)
- }
- }
- impl<'a> IntoAttributeValue<'a> for bool {
- fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
- AttributeValue::Bool(self)
- }
- }
- impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
- fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> {
- use bumpalo::core_alloc::fmt::Write;
- let mut str_buf = bumpalo::collections::String::new_in(bump);
- str_buf.write_fmt(self).unwrap();
- AttributeValue::Text(str_buf.into_bump_str())
- }
- }
- // todo
- #[allow(missing_docs)]
- impl<'a> AttributeValue<'a> {
- pub fn is_truthy(&self) -> bool {
- match self {
- AttributeValue::Text(t) => *t == "true",
- AttributeValue::Bool(t) => *t,
- _ => false,
- }
- }
- pub fn is_falsy(&self) -> bool {
- match self {
- AttributeValue::Text(t) => *t == "false",
- AttributeValue::Bool(t) => !(*t),
- _ => false,
- }
- }
- }
- /// A trait that allows for comparing two values of the same type through the Any trait
- ///
- /// Defaults to false if the types are not the same
- ///
- /// This is an implicit trait, so any value that is 'static and PartialEq can be used directly
- ///
- /// If you want to override the default behavior, you should implement PartialEq through a wrapper type
- pub trait AnyAttributeValue: Any {
- /// Perform a comparison between two values
- fn cmp_any<'a>(&'a self, _other: &'a dyn AnyAttributeValue) -> bool {
- false
- }
- }
- impl<T: Any + PartialEq> AnyAttributeValue for T {
- fn cmp_any(&self, other: &dyn AnyAttributeValue) -> bool {
- // we can't, for whatever reason use other as &dyn Any
- let right: &dyn Any = unsafe { std::mem::transmute(other) };
- match right.downcast_ref::<T>() {
- Some(right) => self == right,
- None => false,
- }
- }
- }
- #[test]
- fn cmp_any_works_even_though_it_transmutes() {
- // same type, same value
- let a = 2;
- let b = 2;
- assert!(a.cmp_any(&b as &dyn AnyAttributeValue));
- // same type, different value
- let a = "asds";
- let b = "asdsasd";
- assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
- // different type, different values
- let a = 123;
- let b = "asdsasd";
- assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
- // Custom structs
- #[derive(PartialEq)]
- struct CustomStruct {
- a: i32,
- }
- let a = CustomStruct { a: 1 };
- let b = CustomStruct { a: 1 };
- assert!(a.cmp_any(&b as &dyn AnyAttributeValue));
- let a = CustomStruct { a: 1 };
- let b = CustomStruct { a: 123 };
- assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
- let a = CustomStruct { a: 1 };
- let b = "asdasd";
- assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
- }
|