1use alloc::boxed::Box;
4use alloc::string::String;
5use core::any::Any;
6
7use crate::datetime::DateTime;
8use crate::host::Host;
9use crate::number::{Measure, Number};
10use crate::parts::FallbackSource;
11
12#[derive(Clone, Copy)]
16#[non_exhaustive]
17pub enum Arg<'a> {
18 Str(&'a str),
20 Int(i64),
22 Float(f64),
24 Decimal(&'a str),
26 Custom(&'a dyn CustomValue),
28 Unset,
30 DateTime(&'a DateTime<'a>),
32}
33
34impl core::fmt::Debug for Arg<'_> {
37 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38 match self {
39 Arg::Str(s) => f.debug_tuple("Str").field(s).finish(),
40 Arg::Int(n) => f.debug_tuple("Int").field(n).finish(),
41 Arg::Float(x) => f.debug_tuple("Float").field(x).finish(),
42 Arg::Decimal(s) => f.debug_tuple("Decimal").field(s).finish(),
43 Arg::Custom(_) => f.write_str("Custom(..)"),
44 Arg::Unset => f.write_str("Unset"),
45 Arg::DateTime(d) => f.debug_tuple("DateTime").field(d).finish(),
46 }
47 }
48}
49
50impl<'a> From<&'a DateTime<'a>> for Arg<'a> {
51 #[inline]
52 fn from(d: &'a DateTime<'a>) -> Self {
53 Arg::DateTime(d)
54 }
55}
56
57impl<'a> From<&'a str> for Arg<'a> {
58 #[inline]
59 fn from(s: &'a str) -> Self {
60 Arg::Str(s)
61 }
62}
63
64impl<'a> From<&'a String> for Arg<'a> {
65 #[inline]
66 fn from(s: &'a String) -> Self {
67 Arg::Str(s)
68 }
69}
70
71macro_rules! int_arg {
72 ($($t:ty),*) => {$(
73 impl From<$t> for Arg<'_> {
74 #[inline]
75 fn from(n: $t) -> Self {
76 Arg::Int(i64::from(n))
77 }
78 }
79 )*};
80}
81int_arg!(i8, i16, i32, i64, u8, u16, u32);
82
83impl From<f64> for Arg<'_> {
84 #[inline]
85 fn from(x: f64) -> Self {
86 Arg::Float(x)
87 }
88}
89
90impl From<f32> for Arg<'_> {
91 #[inline]
92 fn from(x: f32) -> Self {
93 Arg::Float(f64::from(x))
94 }
95}
96
97pub trait CustomValue {
99 fn as_str(&self) -> Option<&str> {
101 None
102 }
103
104 fn as_number(&self) -> Option<Number> {
106 None
107 }
108
109 fn as_any(&self) -> Option<&dyn Any> {
111 None
112 }
113
114 fn as_date_time(&self) -> Option<DateTime<'_>> {
116 None
117 }
118
119 fn as_measure(&self) -> Option<Measure<'_>> {
123 None
124 }
125}
126
127#[non_exhaustive]
131pub enum Value<'a> {
132 Str(&'a str),
134 Int(i64),
136 Float(f64),
138 Decimal(&'a str),
140 Number(Number),
143 Custom(&'a dyn CustomValue),
145 Boxed(Box<dyn Any>),
147 Fallback(FallbackSource<'a>),
153 DateTime(DateTime<'a>),
156 Measure(Measure<'a>),
159}
160
161impl core::fmt::Debug for Value<'_> {
165 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
166 match self {
167 Value::Str(s) => f.debug_tuple("Str").field(s).finish(),
168 Value::Int(n) => f.debug_tuple("Int").field(n).finish(),
169 Value::Float(x) => f.debug_tuple("Float").field(x).finish(),
170 Value::Decimal(s) => f.debug_tuple("Decimal").field(s).finish(),
171 Value::Number(n) => f.debug_tuple("Number").field(n).finish(),
172 Value::Custom(_) => f.write_str("Custom(..)"),
173 Value::Boxed(_) => f.write_str("Boxed(..)"),
174 Value::Fallback(s) => f.debug_tuple("Fallback").field(s).finish(),
175 Value::DateTime(d) => f.debug_tuple("DateTime").field(d).finish(),
176 Value::Measure(m) => f.debug_tuple("Measure").field(m).finish(),
177 }
178 }
179}
180
181impl<'a> Value<'a> {
182 pub fn from_arg(arg: Arg<'a>) -> Option<Value<'a>> {
184 Some(match arg {
185 Arg::Str(s) => Value::Str(s),
186 Arg::Int(n) => Value::Int(n),
187 Arg::Float(x) => Value::Float(x),
188 Arg::Decimal(s) => Value::Decimal(s),
189 Arg::Custom(c) => Value::Custom(c),
190 Arg::DateTime(d) => Value::DateTime(*d),
191 Arg::Unset => return None,
192 })
193 }
194
195 pub fn as_str(&self) -> Option<&str> {
198 match self {
199 Value::Str(s) | Value::Decimal(s) => Some(s),
200 Value::Custom(c) => c.as_str(),
201 _ => None,
202 }
203 }
204
205 pub fn to_number(&self, host: &dyn Host) -> Option<Number> {
210 match self {
211 Value::Str(s) | Value::Decimal(s) => Number::parse(s),
212 Value::Int(n) => Some(Number::from_i64(*n)),
213 Value::Float(x) => Number::from_f64(*x, host),
214 Value::Number(n) => Some(n.bare()),
215 Value::Measure(m) => Some(m.number.bare()),
216 Value::Custom(c) => c
217 .as_number()
218 .or_else(|| c.as_measure().map(|m| m.number.bare())),
219 Value::Boxed(_) | Value::Fallback(_) | Value::DateTime(_) => None,
220 }
221 }
222
223 pub fn digit_size(&self) -> Option<u8> {
228 crate::number::digit_size(self)
229 }
230
231 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
234 match self {
235 Value::Boxed(b) => b.downcast_ref(),
236 Value::Custom(c) => c.as_any()?.downcast_ref(),
237 _ => None,
238 }
239 }
240
241 pub(crate) fn try_copy(&self) -> Option<Value<'a>> {
244 Some(match self {
245 Value::Str(s) => Value::Str(s),
246 Value::Int(n) => Value::Int(*n),
247 Value::Float(x) => Value::Float(*x),
248 Value::Decimal(s) => Value::Decimal(s),
249 Value::Number(n) => Value::Number(n.clone()),
250 Value::Custom(c) => Value::Custom(*c),
251 Value::Fallback(f) => Value::Fallback(*f),
252 Value::Boxed(_) | Value::DateTime(_) | Value::Measure(_) => return None,
254 })
255 }
256}