1use std::borrow::Cow;
3use std::cmp::Ordering;
4use std::ops::{Add, Sub};
5use std::str::FromStr;
6use std::{fmt, net};
7
8use chrono::{DateTime, Datelike, Duration, LocalResult, NaiveDateTime, TimeZone, Utc};
9use enumset::EnumSet;
10use relay_protocol::{
11 Annotated, Array, Empty, Error, ErrorKind, FromValue, IntoValue, Meta, Object,
12 SkipSerialization, Value,
13};
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15
16use crate::processor::{
17 ProcessValue, ProcessingResult, ProcessingState, Processor, ValueType, process_value,
18};
19
20#[derive(Clone, Debug, PartialEq, Empty, IntoValue, ProcessValue)]
22#[metastructure(process_func = "process_values")]
23pub struct Values<T> {
24 #[metastructure(required = true, skip_serialization = "empty_deep")]
26 pub values: Annotated<Array<T>>,
27
28 #[metastructure(additional_properties)]
30 pub other: Object<Value>,
31}
32
33impl<T> Default for Values<T> {
34 fn default() -> Values<T> {
35 Values::new(Vec::new())
37 }
38}
39
40impl<T> Values<T> {
41 pub fn new(values: Array<T>) -> Values<T> {
43 Values {
44 values: Annotated::new(values),
45 other: Object::default(),
46 }
47 }
48}
49
50impl<T: FromValue> FromValue for Values<T> {
51 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
52 match value {
53 Annotated(Some(Value::Array(items)), meta) => Annotated(
56 Some(Values {
57 values: Annotated(
58 Some(items.into_iter().map(FromValue::from_value).collect()),
59 meta,
60 ),
61 other: Object::new(),
62 }),
63 Meta::default(),
64 ),
65 Annotated(Some(Value::Object(mut obj)), meta) => {
66 if obj.is_empty() {
67 Annotated(None, meta)
71 } else if let Some(values) = obj.remove("values") {
72 Annotated(
75 Some(Values {
76 values: FromValue::from_value(values),
77 other: obj,
78 }),
79 meta,
80 )
81 } else {
82 Annotated(
85 Some(Values {
86 values: Annotated(
87 Some(vec![FromValue::from_value(Annotated(
88 Some(Value::Object(obj)),
89 meta,
90 ))]),
91 Meta::default(),
92 ),
93 other: Object::new(),
94 }),
95 Meta::default(),
96 )
97 }
98 }
99 Annotated(None, meta) => Annotated(None, meta),
100 Annotated(Some(value), mut meta) => {
101 meta.add_error(Error::expected("a list or values object"));
102 meta.set_original_value(Some(value));
103 Annotated(None, meta)
104 }
105 }
106 }
107}
108
109pub trait AsPair {
111 type Key: AsRef<str>;
112 type Value: ProcessValue;
113
114 fn from_pair(pair: (Annotated<Self::Key>, Annotated<Self::Value>)) -> Self;
116
117 fn into_pair(self) -> (Annotated<Self::Key>, Annotated<Self::Value>);
119
120 fn as_pair(&self) -> (&Annotated<Self::Key>, &Annotated<Self::Value>);
122
123 fn as_pair_mut(&mut self) -> (&mut Annotated<Self::Key>, &mut Annotated<Self::Value>);
125
126 fn key(&self) -> Option<&str> {
128 self.as_pair().0.as_str()
129 }
130
131 fn value(&self) -> Option<&Self::Value> {
133 self.as_pair().1.value()
134 }
135}
136
137impl<K, V> AsPair for (Annotated<K>, Annotated<V>)
138where
139 K: AsRef<str>,
140 V: ProcessValue,
141{
142 type Key = K;
143 type Value = V;
144
145 fn from_pair(pair: (Annotated<Self::Key>, Annotated<Self::Value>)) -> Self {
146 pair
147 }
148
149 fn into_pair(self) -> (Annotated<Self::Key>, Annotated<Self::Value>) {
150 self
151 }
152
153 fn as_pair(&self) -> (&Annotated<Self::Key>, &Annotated<Self::Value>) {
154 (&self.0, &self.1)
155 }
156
157 fn as_pair_mut(&mut self) -> (&mut Annotated<Self::Key>, &mut Annotated<Self::Value>) {
158 (&mut self.0, &mut self.1)
159 }
160}
161
162#[derive(Clone, Debug, Default, PartialEq, Empty, IntoValue)]
164pub struct PairList<T>(pub Array<T>);
165
166impl<T, K, V> PairList<T>
167where
168 K: AsRef<str>,
169 V: ProcessValue,
170 T: AsPair<Key = K, Value = V>,
171{
172 pub fn position<Q>(&self, key: Q) -> Option<usize>
174 where
175 Q: AsRef<str>,
176 {
177 let key = key.as_ref();
178 self.0
179 .iter()
180 .filter_map(Annotated::value)
181 .position(|entry| entry.as_pair().0.as_str() == Some(key))
182 }
183
184 pub fn get<'a, Q>(&'a self, key: Q) -> Option<&'a Annotated<V>>
189 where
190 Q: AsRef<str>,
191 K: 'a,
192 {
193 self.position(key)
194 .and_then(|pos| self.0.get(pos))
195 .and_then(Annotated::value)
196 .map(|pair| pair.as_pair().1)
197 }
198
199 pub fn get_value<'a, Q>(&'a self, key: Q) -> Option<&'a V>
204 where
205 Q: AsRef<str>,
206 K: 'a,
207 {
208 self.get(key).and_then(Annotated::value)
209 }
210
211 pub fn contains<Q>(&self, key: Q) -> bool
213 where
214 Q: AsRef<str>,
215 {
216 self.position(key).is_some()
217 }
218
219 pub fn remove<Q>(&mut self, key: Q) -> Option<Annotated<V>>
221 where
222 Q: AsRef<str>,
223 {
224 self.position(key)
225 .and_then(|index| self.0.remove(index).0)
226 .map(|entry| entry.into_pair().1)
227 }
228
229 pub fn insert(&mut self, key: K, value: Annotated<V>) -> Option<Annotated<V>> {
231 match self.position(key.as_ref()) {
232 Some(index) => self
233 .get_mut(index)
234 .and_then(|annotated| annotated.value_mut().as_mut())
235 .map(|pair| std::mem::replace(pair.as_pair_mut().1, value)),
236 None => {
237 self.push(Annotated::new(T::from_pair((Annotated::new(key), value))));
238 None
239 }
240 }
241 }
242}
243
244impl<T> std::ops::Deref for PairList<T> {
245 type Target = Array<T>;
246
247 fn deref(&self) -> &Self::Target {
248 &self.0
249 }
250}
251
252impl<T> std::ops::DerefMut for PairList<T> {
253 fn deref_mut(&mut self) -> &mut Self::Target {
254 &mut self.0
255 }
256}
257
258impl<A> FromIterator<Annotated<A>> for PairList<A> {
259 fn from_iter<T>(iter: T) -> Self
260 where
261 T: IntoIterator<Item = Annotated<A>>,
262 {
263 PairList(FromIterator::from_iter(iter))
264 }
265}
266
267impl<T> From<Array<T>> for PairList<T> {
268 fn from(value: Array<T>) -> Self {
269 PairList(value)
270 }
271}
272
273impl<T: FromValue> FromValue for PairList<T> {
274 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
275 match value {
276 Annotated(Some(Value::Array(items)), meta) => {
277 let mut rv = Vec::new();
278 for item in items.into_iter() {
279 rv.push(T::from_value(item));
280 }
281 Annotated(Some(PairList(rv)), meta)
282 }
283 Annotated(Some(Value::Object(items)), meta) => {
284 let mut rv = Vec::new();
285 for (key, value) in items.into_iter() {
286 rv.push(T::from_value(Annotated::new(Value::Array(vec![
287 Annotated::new(Value::String(key)),
288 value,
289 ]))));
290 }
291 Annotated(Some(PairList(rv)), meta)
292 }
293 other => FromValue::from_value(other).map_value(PairList),
294 }
295 }
296}
297
298impl<T> ProcessValue for PairList<T>
299where
300 T: ProcessValue + AsPair,
301{
302 #[inline]
303 fn value_type(&self) -> EnumSet<ValueType> {
304 EnumSet::only(ValueType::Object)
305 }
306
307 #[inline]
308 fn process_value<P>(
309 &mut self,
310 meta: &mut Meta,
311 processor: &mut P,
312 state: &ProcessingState<'_>,
313 ) -> ProcessingResult
314 where
315 P: Processor,
316 {
317 processor.process_pairlist(self, meta, state)
318 }
319
320 fn process_child_values<P>(
321 &mut self,
322 processor: &mut P,
323 state: &ProcessingState<'_>,
324 ) -> ProcessingResult
325 where
326 P: Processor,
327 {
328 for (idx, pair) in self.0.iter_mut().enumerate() {
329 let state = state.enter_index(idx, state.inner_attrs(), ValueType::for_field(pair));
330 process_value(pair, processor, &state)?;
331 }
332
333 Ok(())
334 }
335}
336
337macro_rules! hex_metrastructure {
338 ($type:ident, $expectation:expr) => {
339 impl FromStr for $type {
340 type Err = std::num::ParseIntError;
341
342 fn from_str(s: &str) -> Result<$type, Self::Err> {
343 if s.starts_with("0x") || s.starts_with("0X") {
344 u64::from_str_radix(&s[2..], 16).map($type)
345 } else {
346 s.parse().map($type)
347 }
348 }
349 }
350
351 impl fmt::Display for $type {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 write!(f, "{:#x}", self.0)
354 }
355 }
356
357 impl Empty for $type {
358 #[inline]
359 fn is_empty(&self) -> bool {
360 false
361 }
362 }
363
364 impl FromValue for $type {
365 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
366 match value {
367 Annotated(Some(Value::String(value)), mut meta) => match value.parse() {
368 Ok(value) => Annotated(Some(value), meta),
369 Err(err) => {
370 meta.add_error(Error::invalid(err));
371 meta.set_original_value(Some(value));
372 Annotated(None, meta)
373 }
374 },
375 Annotated(Some(Value::U64(value)), meta) => Annotated(Some($type(value)), meta),
376 Annotated(Some(Value::I64(value)), meta) => {
377 Annotated(Some($type(value as u64)), meta)
378 }
379 Annotated(None, meta) => Annotated(None, meta),
380 Annotated(Some(value), mut meta) => {
381 meta.add_error(Error::expected($expectation));
382 meta.set_original_value(Some(value));
383 Annotated(None, meta)
384 }
385 }
386 }
387 }
388
389 impl IntoValue for $type {
390 fn into_value(self) -> Value {
391 Value::String(self.to_string())
392 }
393 fn serialize_payload<S>(
394 &self,
395 s: S,
396 _behavior: relay_protocol::SkipSerialization,
397 ) -> Result<S::Ok, S::Error>
398 where
399 Self: Sized,
400 S: Serializer,
401 {
402 Serializer::collect_str(s, self)
403 }
404 }
405
406 impl ProcessValue for $type {}
407 };
408}
409
410#[derive(Debug)]
412pub struct InvalidRegVal;
413
414impl fmt::Display for InvalidRegVal {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 write!(f, "invalid register value")
417 }
418}
419
420impl std::error::Error for InvalidRegVal {}
421
422#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
424pub struct RegVal(pub u64);
425
426hex_metrastructure!(RegVal, "register value");
427
428#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
430pub struct Addr(pub u64);
431
432hex_metrastructure!(Addr, "address");
433relay_common::impl_str_serde!(Addr, "an address");
434
435#[derive(
437 Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Empty, IntoValue, ProcessValue, Serialize,
438)]
439pub struct IpAddr(pub String);
440
441impl IpAddr {
442 pub fn auto() -> IpAddr {
444 IpAddr("{{auto}}".into())
445 }
446
447 pub fn parse<S>(value: S) -> Result<Self, S>
449 where
450 S: AsRef<str> + Into<String>,
451 {
452 if value.as_ref() == "{{auto}}" {
453 return Ok(IpAddr(value.into()));
454 }
455
456 match net::IpAddr::from_str(value.as_ref()) {
457 Ok(_) => Ok(IpAddr(value.into())),
458 Err(_) => Err(value),
459 }
460 }
461
462 pub fn is_auto(&self) -> bool {
464 self.0 == "{{auto}}"
465 }
466
467 pub fn is_valid(&self) -> bool {
469 self.is_auto() || net::IpAddr::from_str(&self.0).is_ok()
470 }
471
472 pub fn as_str(&self) -> &str {
474 &self.0
475 }
476
477 pub fn into_inner(self) -> String {
479 self.0
480 }
481}
482
483impl AsRef<str> for IpAddr {
484 fn as_ref(&self) -> &str {
485 &self.0
486 }
487}
488
489impl Default for IpAddr {
490 fn default() -> Self {
491 IpAddr::auto()
492 }
493}
494
495impl From<std::net::IpAddr> for IpAddr {
496 fn from(ip_addr: std::net::IpAddr) -> Self {
497 Self(ip_addr.to_string())
498 }
499}
500
501impl fmt::Display for IpAddr {
502 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
503 self.0.fmt(f)
504 }
505}
506
507impl<'de> Deserialize<'de> for IpAddr {
508 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
509 where
510 D: Deserializer<'de>,
511 {
512 let string = Cow::<'_, str>::deserialize(deserializer)?;
513 IpAddr::parse(string).map_err(|_| serde::de::Error::custom("expected an ip address"))
514 }
515}
516
517impl FromValue for IpAddr {
518 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
519 match value {
520 Annotated(Some(Value::String(value)), mut meta) => match IpAddr::parse(value) {
521 Ok(addr) => Annotated(Some(addr), meta),
522 Err(value) => {
523 meta.add_error(Error::expected("an ip address"));
524 meta.set_original_value(Some(value));
525 Annotated(None, meta)
526 }
527 },
528 Annotated(None, meta) => Annotated(None, meta),
529 Annotated(Some(value), mut meta) => {
530 meta.add_error(Error::expected("an ip address"));
531 meta.set_original_value(Some(value));
532 Annotated(None, meta)
533 }
534 }
535 }
536}
537
538impl FromStr for IpAddr {
539 type Err = ();
540
541 fn from_str(value: &str) -> Result<Self, Self::Err> {
542 IpAddr::parse(value).map_err(|_| ())
543 }
544}
545
546#[derive(Debug)]
548pub struct ParseLevelError;
549
550impl fmt::Display for ParseLevelError {
551 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
552 write!(f, "invalid level")
553 }
554}
555
556impl std::error::Error for ParseLevelError {}
557
558#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
560pub enum Level {
561 Debug,
563 #[default]
565 Info,
566 Warning,
568 Error,
570 Fatal,
572}
573
574impl Level {
575 pub fn name(self) -> &'static str {
576 match self {
577 Level::Debug => "debug",
578 Level::Info => "info",
579 Level::Warning => "warning",
580 Level::Error => "error",
581 Level::Fatal => "fatal",
582 }
583 }
584
585 fn from_python_level(value: u64) -> Option<Level> {
586 Some(match value {
587 10 => Level::Debug,
588 20 => Level::Info,
589 30 => Level::Warning,
590 40 => Level::Error,
591 50 => Level::Fatal,
592 _ => return None,
593 })
594 }
595}
596
597impl FromStr for Level {
598 type Err = ParseLevelError;
599
600 fn from_str(string: &str) -> Result<Self, Self::Err> {
601 Ok(match string {
602 "debug" => Level::Debug,
603 "info" | "log" => Level::Info,
604 "warning" => Level::Warning,
605 "error" => Level::Error,
606 "fatal" | "critical" => Level::Fatal,
607 _ => return Err(ParseLevelError),
608 })
609 }
610}
611
612impl fmt::Display for Level {
613 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
614 f.write_str(self.name())
615 }
616}
617
618impl FromValue for Level {
619 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
620 match value {
621 Annotated(Some(Value::String(value)), mut meta) => match value.parse() {
622 Ok(value) => Annotated(Some(value), meta),
623 Err(err) => {
624 meta.add_error(Error::invalid(err));
625 meta.set_original_value(Some(value));
626 Annotated(None, meta)
627 }
628 },
629 Annotated(Some(Value::U64(val)), mut meta) => match Level::from_python_level(val) {
630 Some(value) => Annotated(Some(value), meta),
631 None => {
632 meta.add_error(ErrorKind::InvalidData);
633 meta.set_original_value(Some(val));
634 Annotated(None, meta)
635 }
636 },
637 Annotated(Some(Value::I64(val)), mut meta) => {
638 match Level::from_python_level(val as u64) {
639 Some(value) => Annotated(Some(value), meta),
640 None => {
641 meta.add_error(ErrorKind::InvalidData);
642 meta.set_original_value(Some(val));
643 Annotated(None, meta)
644 }
645 }
646 }
647 Annotated(None, meta) => Annotated(None, meta),
648 Annotated(Some(value), mut meta) => {
649 meta.add_error(Error::expected("a level"));
650 meta.set_original_value(Some(value));
651 Annotated(None, meta)
652 }
653 }
654 }
655}
656
657impl IntoValue for Level {
658 fn into_value(self) -> Value {
659 Value::String(self.to_string())
660 }
661
662 fn serialize_payload<S>(&self, s: S, _behavior: SkipSerialization) -> Result<S::Ok, S::Error>
663 where
664 Self: Sized,
665 S: Serializer,
666 {
667 Serialize::serialize(self.name(), s)
668 }
669}
670
671impl ProcessValue for Level {}
672
673impl Empty for Level {
674 #[inline]
675 fn is_empty(&self) -> bool {
676 false
677 }
678}
679
680#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Empty, IntoValue, ProcessValue)]
682pub struct LenientString(pub String);
683
684impl LenientString {
685 pub fn as_str(&self) -> &str {
687 &self.0
688 }
689
690 pub fn into_inner(self) -> String {
692 self.0
693 }
694}
695
696impl AsRef<str> for LenientString {
697 fn as_ref(&self) -> &str {
698 &self.0
699 }
700}
701
702impl std::ops::Deref for LenientString {
703 type Target = String;
704
705 fn deref(&self) -> &Self::Target {
706 &self.0
707 }
708}
709
710impl std::ops::DerefMut for LenientString {
711 fn deref_mut(&mut self) -> &mut Self::Target {
712 &mut self.0
713 }
714}
715
716impl From<String> for LenientString {
717 fn from(value: String) -> Self {
718 LenientString(value)
719 }
720}
721
722impl FromValue for LenientString {
723 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
724 match value {
725 Annotated(Some(Value::String(string)), meta) => Annotated(Some(string), meta),
726 Annotated(Some(Value::Bool(true)), meta) => Annotated(Some("True".to_owned()), meta),
728 Annotated(Some(Value::Bool(false)), meta) => Annotated(Some("False".to_owned()), meta),
729 Annotated(Some(Value::U64(num)), meta) => Annotated(Some(num.to_string()), meta),
730 Annotated(Some(Value::I64(num)), meta) => Annotated(Some(num.to_string()), meta),
731 Annotated(Some(Value::F64(num)), mut meta) => {
732 if num.abs() < (1i64 << 53) as f64 {
733 Annotated(Some(num.trunc().to_string()), meta)
734 } else {
735 meta.add_error(Error::expected("a number with JSON precision"));
736 meta.set_original_value(Some(num));
737 Annotated(None, meta)
738 }
739 }
740 Annotated(None, meta) => Annotated(None, meta),
741 Annotated(Some(value), mut meta) => {
742 meta.add_error(Error::expected("a primitive value"));
743 meta.set_original_value(Some(value));
744 Annotated(None, meta)
745 }
746 }
747 .map_value(LenientString)
748 }
749}
750
751#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Empty, IntoValue, ProcessValue)]
753pub struct JsonLenientString(pub String);
754
755impl JsonLenientString {
756 pub fn as_str(&self) -> &str {
758 &self.0
759 }
760
761 pub fn into_inner(self) -> String {
763 self.0
764 }
765}
766
767impl AsRef<str> for JsonLenientString {
768 fn as_ref(&self) -> &str {
769 &self.0
770 }
771}
772
773impl std::ops::Deref for JsonLenientString {
774 type Target = String;
775
776 fn deref(&self) -> &Self::Target {
777 &self.0
778 }
779}
780
781impl std::ops::DerefMut for JsonLenientString {
782 fn deref_mut(&mut self) -> &mut Self::Target {
783 &mut self.0
784 }
785}
786
787impl From<JsonLenientString> for String {
788 fn from(value: JsonLenientString) -> Self {
789 value.0
790 }
791}
792
793impl FromValue for JsonLenientString {
794 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
795 match value {
796 Annotated(Some(Value::String(string)), meta) => Annotated(Some(string.into()), meta),
797 Annotated(Some(other), meta) => {
798 Annotated(Some(serde_json::to_string(&other).unwrap().into()), meta)
799 }
800 Annotated(None, meta) => Annotated(None, meta),
801 }
802 }
803}
804
805impl From<String> for JsonLenientString {
806 fn from(value: String) -> Self {
807 JsonLenientString(value)
808 }
809}
810
811#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
812pub struct Timestamp(pub DateTime<Utc>);
813
814impl Timestamp {
815 pub fn into_inner(self) -> DateTime<Utc> {
816 self.0
817 }
818}
819
820impl From<Timestamp> for uuid::Timestamp {
821 fn from(value: Timestamp) -> Self {
822 uuid::Timestamp::from_unix(
823 uuid::NoContext,
824 u64::try_from(value.0.timestamp()).unwrap_or(0),
825 value.0.timestamp_subsec_nanos(),
826 )
827 }
828}
829
830impl ProcessValue for Timestamp {
831 #[inline]
832 fn value_type(&self) -> EnumSet<ValueType> {
833 EnumSet::only(ValueType::DateTime)
834 }
835
836 #[inline]
837 fn process_value<P>(
838 &mut self,
839 meta: &mut Meta,
840 processor: &mut P,
841 state: &ProcessingState<'_>,
842 ) -> ProcessingResult
843 where
844 P: Processor,
845 {
846 processor.process_timestamp(self, meta, state)
847 }
848}
849
850impl From<DateTime<Utc>> for Timestamp {
851 fn from(value: DateTime<Utc>) -> Self {
852 Timestamp(value)
853 }
854}
855
856impl Add<Duration> for Timestamp {
857 type Output = Self;
858
859 fn add(self, duration: Duration) -> Self::Output {
860 Timestamp(self.0 + duration)
861 }
862}
863
864impl Sub<Timestamp> for Timestamp {
865 type Output = chrono::Duration;
866
867 fn sub(self, rhs: Timestamp) -> Self::Output {
868 self.into_inner() - rhs.into_inner()
869 }
870}
871
872impl PartialEq<DateTime<Utc>> for Timestamp {
873 fn eq(&self, other: &DateTime<Utc>) -> bool {
874 &self.0 == other
875 }
876}
877
878impl PartialOrd<DateTime<Utc>> for Timestamp {
879 fn partial_cmp(&self, other: &DateTime<Utc>) -> Option<Ordering> {
880 self.0.partial_cmp(other)
881 }
882}
883
884impl fmt::Display for Timestamp {
885 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
886 self.0.fmt(f)
887 }
888}
889
890pub fn datetime_to_timestamp(dt: DateTime<Utc>) -> f64 {
891 let micros = (f64::from(dt.timestamp_subsec_nanos()) / 1_000f64).round();
907 dt.timestamp() as f64 + (micros / 1_000_000f64)
908}
909
910fn utc_result_to_annotated<V: IntoValue>(
911 result: LocalResult<DateTime<Utc>>,
912 original_value: V,
913 mut meta: Meta,
914) -> Annotated<DateTime<Utc>> {
915 match result {
916 LocalResult::Single(value) => Annotated(Some(value), meta),
917 LocalResult::Ambiguous(_, _) => {
918 meta.add_error(Error::expected("ambiguous timestamp"));
919 meta.set_original_value(Some(original_value));
920 Annotated(None, meta)
921 }
922 LocalResult::None => {
923 meta.add_error(Error::invalid("timestamp out of range"));
924 meta.set_original_value(Some(original_value));
925 Annotated(None, meta)
926 }
927 }
928}
929
930impl FromValue for Timestamp {
931 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
932 let rv = match value {
933 Annotated(Some(Value::String(value)), mut meta) => {
934 let parsed = match value.parse::<NaiveDateTime>() {
936 Ok(dt) => Ok(DateTime::from_naive_utc_and_offset(dt, Utc)),
937
938 Err(_) => value.parse(),
945 };
946 match parsed {
947 Ok(value) => Annotated(Some(value), meta),
948 Err(err) => {
949 meta.add_error(Error::invalid(err));
950 meta.set_original_value(Some(value));
951 Annotated(None, meta)
952 }
953 }
954 }
955 Annotated(Some(Value::U64(ts)), meta) => {
956 utc_result_to_annotated(Utc.timestamp_opt(ts as i64, 0), ts, meta)
957 }
958 Annotated(Some(Value::I64(ts)), meta) => {
959 utc_result_to_annotated(Utc.timestamp_opt(ts, 0), ts, meta)
960 }
961 Annotated(Some(Value::F64(ts)), meta) => {
962 let secs = ts as i64;
963 let nanos = (ts.fract() * 1_000_000_000f64) as u32;
966 utc_result_to_annotated(Utc.timestamp_opt(secs, nanos), ts, meta)
967 }
968 Annotated(None, meta) => Annotated(None, meta),
969 Annotated(Some(value), mut meta) => {
970 meta.add_error(Error::expected("a timestamp"));
971 meta.set_original_value(Some(value));
972 Annotated(None, meta)
973 }
974 };
975
976 match rv {
977 Annotated(Some(value), mut meta) => {
978 if value.year() > 9999 {
979 meta.add_error(Error::invalid("timestamp out of range"));
983 meta.set_original_value(Some(Timestamp(value)));
984 Annotated(None, meta)
985 } else {
986 Annotated(Some(Timestamp(value)), meta)
987 }
988 }
989 x => x.map_value(Timestamp),
990 }
991 }
992}
993
994impl IntoValue for Timestamp {
995 fn into_value(self) -> Value {
996 Value::F64(datetime_to_timestamp(self.0))
997 }
998
999 fn serialize_payload<S>(&self, s: S, _behavior: SkipSerialization) -> Result<S::Ok, S::Error>
1000 where
1001 Self: Sized,
1002 S: Serializer,
1003 {
1004 Serialize::serialize(&datetime_to_timestamp(self.0), s)
1005 }
1006}
1007
1008impl Empty for Timestamp {
1009 fn is_empty(&self) -> bool {
1010 false
1011 }
1012}
1013
1014#[cfg(test)]
1015mod tests {
1016 use similar_asserts::assert_eq;
1017
1018 use super::*;
1019
1020 #[test]
1021 fn test_values_serialization() {
1022 let value = Annotated::new(Values {
1023 values: Annotated::new(vec![
1024 Annotated::new(0u64),
1025 Annotated::new(1u64),
1026 Annotated::new(2u64),
1027 ]),
1028 other: Object::default(),
1029 });
1030 assert_eq!(value.to_json().unwrap(), "{\"values\":[0,1,2]}");
1031 }
1032
1033 #[test]
1034 fn test_values_deserialization() {
1035 #[derive(Clone, Debug, Empty, FromValue, IntoValue, PartialEq)]
1036 struct Exception {
1037 #[metastructure(field = "type")]
1038 ty: Annotated<String>,
1039 value: Annotated<String>,
1040 }
1041 let value = Annotated::<Values<Exception>>::from_json(
1042 r#"{"values": [{"type": "Test", "value": "aha!"}]}"#,
1043 )
1044 .unwrap();
1045 assert_eq!(
1046 value,
1047 Annotated::new(Values::new(vec![Annotated::new(Exception {
1048 ty: Annotated::new("Test".to_owned()),
1049 value: Annotated::new("aha!".to_owned()),
1050 })]))
1051 );
1052
1053 let value =
1054 Annotated::<Values<Exception>>::from_json(r#"[{"type": "Test", "value": "aha!"}]"#)
1055 .unwrap();
1056 assert_eq!(
1057 value,
1058 Annotated::new(Values::new(vec![Annotated::new(Exception {
1059 ty: Annotated::new("Test".to_owned()),
1060 value: Annotated::new("aha!".to_owned()),
1061 })]))
1062 );
1063
1064 let value =
1065 Annotated::<Values<Exception>>::from_json(r#"{"type": "Test", "value": "aha!"}"#)
1066 .unwrap();
1067 assert_eq!(
1068 value,
1069 Annotated::new(Values::new(vec![Annotated::new(Exception {
1070 ty: Annotated::new("Test".to_owned()),
1071 value: Annotated::new("aha!".to_owned()),
1072 })]))
1073 );
1074 }
1075
1076 #[test]
1077 fn test_hex_to_string() {
1078 assert_eq!("0x0", &Addr(0).to_string());
1079 assert_eq!("0x2a", &Addr(42).to_string());
1080 }
1081
1082 #[test]
1083 fn test_hex_from_string() {
1084 assert_eq!(Addr(0), "0".parse().unwrap());
1085 assert_eq!(Addr(42), "42".parse().unwrap());
1086 assert_eq!(Addr(42), "0x2a".parse().unwrap());
1087 assert_eq!(Addr(42), "0X2A".parse().unwrap());
1088 }
1089
1090 #[test]
1091 fn test_hex_serialization() {
1092 let value = Value::String("0x2a".to_owned());
1093 let addr: Annotated<Addr> = FromValue::from_value(Annotated::new(value));
1094 assert_eq!(addr.payload_to_json().unwrap(), "\"0x2a\"");
1095 let value = Value::U64(42);
1096 let addr: Annotated<Addr> = FromValue::from_value(Annotated::new(value));
1097 assert_eq!(addr.payload_to_json().unwrap(), "\"0x2a\"");
1098 }
1099
1100 #[test]
1101 fn test_hex_deserialization() {
1102 let addr = Annotated::<Addr>::from_json("\"0x2a\"").unwrap();
1103 assert_eq!(addr.payload_to_json().unwrap(), "\"0x2a\"");
1104 let addr = Annotated::<Addr>::from_json("42").unwrap();
1105 assert_eq!(addr.payload_to_json().unwrap(), "\"0x2a\"");
1106 }
1107
1108 #[test]
1109 fn test_level() {
1110 assert_eq!(
1111 Level::Info,
1112 Annotated::<Level>::from_json("\"log\"").unwrap().0.unwrap()
1113 );
1114 assert_eq!(
1115 Level::Warning,
1116 Annotated::<Level>::from_json("30").unwrap().0.unwrap()
1117 );
1118 assert_eq!(
1119 Level::Fatal,
1120 Annotated::<Level>::from_json("\"critical\"")
1121 .unwrap()
1122 .0
1123 .unwrap()
1124 );
1125 }
1126
1127 #[test]
1128 fn test_ip_addr() {
1129 assert_eq!(
1130 IpAddr("{{auto}}".into()),
1131 Annotated::<IpAddr>::from_json("\"{{auto}}\"")
1132 .unwrap()
1133 .0
1134 .unwrap()
1135 );
1136 assert_eq!(
1137 IpAddr("127.0.0.1".into()),
1138 Annotated::<IpAddr>::from_json("\"127.0.0.1\"")
1139 .unwrap()
1140 .0
1141 .unwrap()
1142 );
1143 assert_eq!(
1144 IpAddr("::1".into()),
1145 Annotated::<IpAddr>::from_json("\"::1\"")
1146 .unwrap()
1147 .0
1148 .unwrap()
1149 );
1150 assert_eq!(
1151 Annotated::from_error(
1152 Error::expected("an ip address"),
1153 Some(Value::String("clearly invalid value".into()))
1154 ),
1155 Annotated::<IpAddr>::from_json("\"clearly invalid value\"").unwrap()
1156 );
1157 }
1158
1159 #[test]
1160 fn test_timestamp_year_out_of_range() {
1161 #[derive(Debug, FromValue, Default, Empty, IntoValue)]
1162 struct Helper {
1163 foo: Annotated<Timestamp>,
1164 }
1165
1166 let x: Annotated<Helper> = Annotated::from_json(r#"{"foo": 1562770897893}"#).unwrap();
1167 assert_eq!(
1168 x.to_json_pretty().unwrap(),
1169 r#"{
1170 "foo": null,
1171 "_meta": {
1172 "foo": {
1173 "": {
1174 "err": [
1175 [
1176 "invalid_data",
1177 {
1178 "reason": "timestamp out of range"
1179 }
1180 ]
1181 ],
1182 "val": 1562770897893.0
1183 }
1184 }
1185 }
1186}"#
1187 );
1188 }
1189
1190 #[test]
1191 fn test_timestamp_completely_out_of_range() {
1192 #[derive(Debug, FromValue, Default, Empty, IntoValue)]
1193 struct Helper {
1194 foo: Annotated<Timestamp>,
1195 }
1196
1197 let x: Annotated<Helper> =
1198 Annotated::from_json(r#"{"foo": -10000000000000000.0}"#).unwrap();
1199 assert_eq!(
1200 x.to_json_pretty().unwrap(),
1201 r#"{
1202 "foo": null,
1203 "_meta": {
1204 "foo": {
1205 "": {
1206 "err": [
1207 [
1208 "invalid_data",
1209 {
1210 "reason": "timestamp out of range"
1211 }
1212 ]
1213 ],
1214 "val": -1e16
1215 }
1216 }
1217 }
1218}"#
1219 );
1220 }
1221}