arbitrary_value.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. use std::{
  2. any::Any,
  3. fmt::{Arguments, Formatter},
  4. };
  5. use bumpalo::Bump;
  6. /// Possible values for an attribute
  7. #[derive(Clone, Copy)]
  8. pub enum AttributeValue<'a> {
  9. /// Reference strs, most common
  10. Text(&'a str),
  11. /// Basic float values
  12. Float(f32),
  13. /// Basic Int values
  14. Int(i32),
  15. /// Basic bool values
  16. Bool(bool),
  17. /// Everything else
  18. Any(&'a dyn AnyAttributeValue),
  19. }
  20. impl<'a> PartialEq for AttributeValue<'a> {
  21. fn eq(&self, other: &Self) -> bool {
  22. match (self, other) {
  23. (Self::Text(l0), Self::Text(r0)) => l0 == r0,
  24. (Self::Float(l0), Self::Float(r0)) => l0 == r0,
  25. (Self::Int(l0), Self::Int(r0)) => l0 == r0,
  26. (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
  27. (Self::Any(l0), Self::Any(r0)) => (*l0).cmp_any(*r0),
  28. _ => false,
  29. }
  30. }
  31. }
  32. impl std::fmt::Debug for AttributeValue<'_> {
  33. fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
  34. match self {
  35. AttributeValue::Text(s) => write!(f, "AttributeValue::Text({:?})", s),
  36. AttributeValue::Float(v) => write!(f, "AttributeValue::Float({:?})", v),
  37. AttributeValue::Int(v) => write!(f, "AttributeValue::Int({:?})", v),
  38. AttributeValue::Bool(b) => write!(f, "AttributeValue::Bool({:?})", b),
  39. AttributeValue::Any(_) => write!(f, "AttributeValue::Any()"),
  40. }
  41. }
  42. }
  43. /// A value that can be converted into an attribute value
  44. pub trait IntoAttributeValue<'a> {
  45. /// Convert into an attribute value
  46. fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>;
  47. }
  48. impl<'a> IntoAttributeValue<'a> for &'a str {
  49. fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
  50. AttributeValue::Text(self)
  51. }
  52. }
  53. impl<'a> IntoAttributeValue<'a> for f32 {
  54. fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
  55. AttributeValue::Float(self)
  56. }
  57. }
  58. impl<'a> IntoAttributeValue<'a> for i32 {
  59. fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
  60. AttributeValue::Int(self)
  61. }
  62. }
  63. impl<'a> IntoAttributeValue<'a> for bool {
  64. fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
  65. AttributeValue::Bool(self)
  66. }
  67. }
  68. impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
  69. fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> {
  70. use bumpalo::core_alloc::fmt::Write;
  71. let mut str_buf = bumpalo::collections::String::new_in(bump);
  72. str_buf.write_fmt(self).unwrap();
  73. AttributeValue::Text(str_buf.into_bump_str())
  74. }
  75. }
  76. // todo
  77. #[allow(missing_docs)]
  78. impl<'a> AttributeValue<'a> {
  79. pub fn is_truthy(&self) -> bool {
  80. match self {
  81. AttributeValue::Text(t) => *t == "true",
  82. AttributeValue::Bool(t) => *t,
  83. _ => false,
  84. }
  85. }
  86. pub fn is_falsy(&self) -> bool {
  87. match self {
  88. AttributeValue::Text(t) => *t == "false",
  89. AttributeValue::Bool(t) => !(*t),
  90. _ => false,
  91. }
  92. }
  93. }
  94. /// A trait that allows for comparing two values of the same type through the Any trait
  95. ///
  96. /// Defaults to false if the types are not the same
  97. ///
  98. /// This is an implicit trait, so any value that is 'static and PartialEq can be used directly
  99. ///
  100. /// If you want to override the default behavior, you should implement PartialEq through a wrapper type
  101. pub trait AnyAttributeValue: Any {
  102. /// Perform a comparison between two values
  103. fn cmp_any<'a>(&'a self, _other: &'a dyn AnyAttributeValue) -> bool {
  104. false
  105. }
  106. }
  107. impl<T: Any + PartialEq> AnyAttributeValue for T {
  108. fn cmp_any(&self, other: &dyn AnyAttributeValue) -> bool {
  109. // we can't, for whatever reason use other as &dyn Any
  110. let right: &dyn Any = unsafe { std::mem::transmute(other) };
  111. match right.downcast_ref::<T>() {
  112. Some(right) => self == right,
  113. None => false,
  114. }
  115. }
  116. }
  117. #[test]
  118. fn cmp_any_works_even_though_it_transmutes() {
  119. // same type, same value
  120. let a = 2;
  121. let b = 2;
  122. assert!(a.cmp_any(&b as &dyn AnyAttributeValue));
  123. // same type, different value
  124. let a = "asds";
  125. let b = "asdsasd";
  126. assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
  127. // different type, different values
  128. let a = 123;
  129. let b = "asdsasd";
  130. assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
  131. // Custom structs
  132. #[derive(PartialEq)]
  133. struct CustomStruct {
  134. a: i32,
  135. }
  136. let a = CustomStruct { a: 1 };
  137. let b = CustomStruct { a: 1 };
  138. assert!(a.cmp_any(&b as &dyn AnyAttributeValue));
  139. let a = CustomStruct { a: 1 };
  140. let b = CustomStruct { a: 123 };
  141. assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
  142. let a = CustomStruct { a: 1 };
  143. let b = "asdasd";
  144. assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
  145. }