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>),
152 DateTime(DateTime<'a>),
155 Measure(Measure<'a>),
158}
159
160impl core::fmt::Debug for Value<'_> {
164 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
165 match self {
166 Value::Str(s) => f.debug_tuple("Str").field(s).finish(),
167 Value::Int(n) => f.debug_tuple("Int").field(n).finish(),
168 Value::Float(x) => f.debug_tuple("Float").field(x).finish(),
169 Value::Decimal(s) => f.debug_tuple("Decimal").field(s).finish(),
170 Value::Number(n) => f.debug_tuple("Number").field(n).finish(),
171 Value::Custom(_) => f.write_str("Custom(..)"),
172 Value::Boxed(_) => f.write_str("Boxed(..)"),
173 Value::Fallback(s) => f.debug_tuple("Fallback").field(s).finish(),
174 Value::DateTime(d) => f.debug_tuple("DateTime").field(d).finish(),
175 Value::Measure(m) => f.debug_tuple("Measure").field(m).finish(),
176 }
177 }
178}
179
180impl<'a> Value<'a> {
181 pub fn from_arg(arg: Arg<'a>) -> Option<Value<'a>> {
183 Some(match arg {
184 Arg::Str(s) => Value::Str(s),
185 Arg::Int(n) => Value::Int(n),
186 Arg::Float(x) => Value::Float(x),
187 Arg::Decimal(s) => Value::Decimal(s),
188 Arg::Custom(c) => Value::Custom(c),
189 Arg::DateTime(d) => Value::DateTime(*d),
190 Arg::Unset => return None,
191 })
192 }
193
194 pub fn as_str(&self) -> Option<&str> {
197 match self {
198 Value::Str(s) | Value::Decimal(s) => Some(s),
199 Value::Custom(c) => c.as_str(),
200 _ => None,
201 }
202 }
203
204 pub fn to_number(&self, host: &dyn Host) -> Option<Number> {
209 match self {
210 Value::Str(s) | Value::Decimal(s) => Number::parse(s),
211 Value::Int(n) => Some(Number::from_i64(*n)),
212 Value::Float(x) => Number::from_f64(*x, host),
213 Value::Number(n) => Some(n.bare()),
214 Value::Measure(m) => Some(m.number.bare()),
215 Value::Custom(c) => c
216 .as_number()
217 .or_else(|| c.as_measure().map(|m| m.number.bare())),
218 Value::Boxed(_) | Value::Fallback(_) | Value::DateTime(_) => None,
219 }
220 }
221
222 pub fn digit_size(&self) -> Option<u8> {
227 crate::number::digit_size(self)
228 }
229
230 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
233 match self {
234 Value::Boxed(b) => b.downcast_ref(),
235 Value::Custom(c) => c.as_any()?.downcast_ref(),
236 _ => None,
237 }
238 }
239
240 pub(crate) fn try_copy(&self) -> Option<Value<'a>> {
243 Some(match self {
244 Value::Str(s) => Value::Str(s),
245 Value::Int(n) => Value::Int(*n),
246 Value::Float(x) => Value::Float(*x),
247 Value::Decimal(s) => Value::Decimal(s),
248 Value::Number(n) => Value::Number(n.clone()),
249 Value::Custom(c) => Value::Custom(*c),
250 Value::Fallback(f) => Value::Fallback(*f),
251 Value::Boxed(_) | Value::DateTime(_) | Value::Measure(_) => return None,
253 })
254 }
255}