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 {
907 let micros = (f64::from(dt.timestamp_subsec_nanos()) / 1_000f64).round();
910 dt.timestamp() as f64 + (micros / 1_000_000f64)
911}
912
913pub fn timestamp_to_datetime(ts: f64) -> LocalResult<DateTime<Utc>> {
918 let secs = ts.floor();
920 let fract = ts - secs;
922 let micros = (fract * 1_000_000f64).round() as u32;
923 match micros == 1_000_000 {
926 true => Utc.timestamp_opt(secs as i64 + 1, 0),
927 false => Utc.timestamp_opt(secs as i64, micros * 1_000),
928 }
929}
930
931fn utc_result_to_annotated<V: IntoValue>(
932 result: LocalResult<DateTime<Utc>>,
933 original_value: V,
934 mut meta: Meta,
935) -> Annotated<DateTime<Utc>> {
936 match result {
937 LocalResult::Single(value) => Annotated(Some(value), meta),
938 LocalResult::Ambiguous(_, _) => {
939 meta.add_error(Error::expected("ambiguous timestamp"));
940 meta.set_original_value(Some(original_value));
941 Annotated(None, meta)
942 }
943 LocalResult::None => {
944 meta.add_error(Error::invalid("timestamp out of range"));
945 meta.set_original_value(Some(original_value));
946 Annotated(None, meta)
947 }
948 }
949}
950
951impl FromValue for Timestamp {
952 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
953 let rv = match value {
954 Annotated(Some(Value::String(value)), mut meta) => {
955 let parsed = match value.parse::<NaiveDateTime>() {
957 Ok(dt) => Ok(DateTime::from_naive_utc_and_offset(dt, Utc)),
958
959 Err(_) => value.parse(),
966 };
967 match parsed {
968 Ok(value) => Annotated(Some(value), meta),
969 Err(err) => {
970 meta.add_error(Error::invalid(err));
971 meta.set_original_value(Some(value));
972 Annotated(None, meta)
973 }
974 }
975 }
976 Annotated(Some(Value::U64(ts)), meta) => {
977 utc_result_to_annotated(Utc.timestamp_opt(ts as i64, 0), ts, meta)
978 }
979 Annotated(Some(Value::I64(ts)), meta) => {
980 utc_result_to_annotated(Utc.timestamp_opt(ts, 0), ts, meta)
981 }
982 Annotated(Some(Value::F64(ts)), meta) => {
983 utc_result_to_annotated(timestamp_to_datetime(ts), ts, meta)
984 }
985 Annotated(None, meta) => Annotated(None, meta),
986 Annotated(Some(value), mut meta) => {
987 meta.add_error(Error::expected("a timestamp"));
988 meta.set_original_value(Some(value));
989 Annotated(None, meta)
990 }
991 };
992
993 match rv {
994 Annotated(Some(value), mut meta) => {
995 if value.year() > 9999 {
996 meta.add_error(Error::invalid("timestamp out of range"));
1000 meta.set_original_value(Some(Timestamp(value)));
1001 Annotated(None, meta)
1002 } else {
1003 Annotated(Some(Timestamp(value)), meta)
1004 }
1005 }
1006 x => x.map_value(Timestamp),
1007 }
1008 }
1009}
1010
1011impl IntoValue for Timestamp {
1012 fn into_value(self) -> Value {
1013 Value::F64(datetime_to_timestamp(self.0))
1014 }
1015
1016 fn serialize_payload<S>(&self, s: S, _behavior: SkipSerialization) -> Result<S::Ok, S::Error>
1017 where
1018 Self: Sized,
1019 S: Serializer,
1020 {
1021 Serialize::serialize(&datetime_to_timestamp(self.0), s)
1022 }
1023}
1024
1025impl Empty for Timestamp {
1026 fn is_empty(&self) -> bool {
1027 false
1028 }
1029}
1030
1031#[cfg(test)]
1032mod tests {
1033 use similar_asserts::assert_eq;
1034
1035 use super::*;
1036
1037 #[test]
1038 fn test_timestamp_to_datetime() {
1039 assert_eq!(timestamp_to_datetime(0.), Utc.timestamp_opt(0, 0));
1040 assert_eq!(timestamp_to_datetime(1000.), Utc.timestamp_opt(1000, 0));
1041 assert_eq!(timestamp_to_datetime(-1000.), Utc.timestamp_opt(-1000, 0));
1042 assert_eq!(
1043 timestamp_to_datetime(1.234_567),
1044 Utc.timestamp_opt(1, 234_567_000)
1045 );
1046 assert_eq!(timestamp_to_datetime(2.999_999_51), Utc.timestamp_opt(3, 0));
1047 assert_eq!(
1048 timestamp_to_datetime(2.999_999_45),
1049 Utc.timestamp_opt(2, 999_999_000)
1050 );
1051 assert_eq!(
1052 timestamp_to_datetime(-0.000_001),
1053 Utc.timestamp_opt(-1, 999_999_000)
1054 );
1055 assert_eq!(
1056 timestamp_to_datetime(-3.000_000_49),
1057 Utc.timestamp_opt(-3, 0)
1058 );
1059 assert_eq!(
1060 timestamp_to_datetime(-3.000_000_51),
1061 Utc.timestamp_opt(-4, 999_999_000)
1062 );
1063 }
1064
1065 #[test]
1066 fn test_values_serialization() {
1067 let value = Annotated::new(Values {
1068 values: Annotated::new(vec![
1069 Annotated::new(0u64),
1070 Annotated::new(1u64),
1071 Annotated::new(2u64),
1072 ]),
1073 other: Object::default(),
1074 });
1075 assert_eq!(value.to_json().unwrap(), "{\"values\":[0,1,2]}");
1076 }
1077
1078 #[test]
1079 fn test_values_deserialization() {
1080 #[derive(Clone, Debug, Empty, FromValue, IntoValue, PartialEq)]
1081 struct Exception {
1082 #[metastructure(field = "type")]
1083 ty: Annotated<String>,
1084 value: Annotated<String>,
1085 }
1086 let value = Annotated::<Values<Exception>>::from_json(
1087 r#"{"values": [{"type": "Test", "value": "aha!"}]}"#,
1088 )
1089 .unwrap();
1090 assert_eq!(
1091 value,
1092 Annotated::new(Values::new(vec![Annotated::new(Exception {
1093 ty: Annotated::new("Test".to_owned()),
1094 value: Annotated::new("aha!".to_owned()),
1095 })]))
1096 );
1097
1098 let value =
1099 Annotated::<Values<Exception>>::from_json(r#"[{"type": "Test", "value": "aha!"}]"#)
1100 .unwrap();
1101 assert_eq!(
1102 value,
1103 Annotated::new(Values::new(vec![Annotated::new(Exception {
1104 ty: Annotated::new("Test".to_owned()),
1105 value: Annotated::new("aha!".to_owned()),
1106 })]))
1107 );
1108
1109 let value =
1110 Annotated::<Values<Exception>>::from_json(r#"{"type": "Test", "value": "aha!"}"#)
1111 .unwrap();
1112 assert_eq!(
1113 value,
1114 Annotated::new(Values::new(vec![Annotated::new(Exception {
1115 ty: Annotated::new("Test".to_owned()),
1116 value: Annotated::new("aha!".to_owned()),
1117 })]))
1118 );
1119 }
1120
1121 #[test]
1122 fn test_hex_to_string() {
1123 assert_eq!("0x0", &Addr(0).to_string());
1124 assert_eq!("0x2a", &Addr(42).to_string());
1125 }
1126
1127 #[test]
1128 fn test_hex_from_string() {
1129 assert_eq!(Addr(0), "0".parse().unwrap());
1130 assert_eq!(Addr(42), "42".parse().unwrap());
1131 assert_eq!(Addr(42), "0x2a".parse().unwrap());
1132 assert_eq!(Addr(42), "0X2A".parse().unwrap());
1133 }
1134
1135 #[test]
1136 fn test_hex_serialization() {
1137 let value = Value::String("0x2a".to_owned());
1138 let addr: Annotated<Addr> = FromValue::from_value(Annotated::new(value));
1139 assert_eq!(addr.payload_to_json().unwrap(), "\"0x2a\"");
1140 let value = Value::U64(42);
1141 let addr: Annotated<Addr> = FromValue::from_value(Annotated::new(value));
1142 assert_eq!(addr.payload_to_json().unwrap(), "\"0x2a\"");
1143 }
1144
1145 #[test]
1146 fn test_hex_deserialization() {
1147 let addr = Annotated::<Addr>::from_json("\"0x2a\"").unwrap();
1148 assert_eq!(addr.payload_to_json().unwrap(), "\"0x2a\"");
1149 let addr = Annotated::<Addr>::from_json("42").unwrap();
1150 assert_eq!(addr.payload_to_json().unwrap(), "\"0x2a\"");
1151 }
1152
1153 #[test]
1154 fn test_level() {
1155 assert_eq!(
1156 Level::Info,
1157 Annotated::<Level>::from_json("\"log\"").unwrap().0.unwrap()
1158 );
1159 assert_eq!(
1160 Level::Warning,
1161 Annotated::<Level>::from_json("30").unwrap().0.unwrap()
1162 );
1163 assert_eq!(
1164 Level::Fatal,
1165 Annotated::<Level>::from_json("\"critical\"")
1166 .unwrap()
1167 .0
1168 .unwrap()
1169 );
1170 }
1171
1172 #[test]
1173 fn test_ip_addr() {
1174 assert_eq!(
1175 IpAddr("{{auto}}".into()),
1176 Annotated::<IpAddr>::from_json("\"{{auto}}\"")
1177 .unwrap()
1178 .0
1179 .unwrap()
1180 );
1181 assert_eq!(
1182 IpAddr("127.0.0.1".into()),
1183 Annotated::<IpAddr>::from_json("\"127.0.0.1\"")
1184 .unwrap()
1185 .0
1186 .unwrap()
1187 );
1188 assert_eq!(
1189 IpAddr("::1".into()),
1190 Annotated::<IpAddr>::from_json("\"::1\"")
1191 .unwrap()
1192 .0
1193 .unwrap()
1194 );
1195 assert_eq!(
1196 Annotated::from_error(
1197 Error::expected("an ip address"),
1198 Some(Value::String("clearly invalid value".into()))
1199 ),
1200 Annotated::<IpAddr>::from_json("\"clearly invalid value\"").unwrap()
1201 );
1202 }
1203
1204 #[test]
1205 fn test_timestamp_year_out_of_range() {
1206 #[derive(Debug, FromValue, Default, Empty, IntoValue)]
1207 struct Helper {
1208 foo: Annotated<Timestamp>,
1209 }
1210
1211 let x: Annotated<Helper> = Annotated::from_json(r#"{"foo": 1562770897893}"#).unwrap();
1212 assert_eq!(
1213 x.to_json_pretty().unwrap(),
1214 r#"{
1215 "foo": null,
1216 "_meta": {
1217 "foo": {
1218 "": {
1219 "err": [
1220 [
1221 "invalid_data",
1222 {
1223 "reason": "timestamp out of range"
1224 }
1225 ]
1226 ],
1227 "val": 1562770897893.0
1228 }
1229 }
1230 }
1231}"#
1232 );
1233 }
1234
1235 #[test]
1236 fn test_timestamp_completely_out_of_range() {
1237 #[derive(Debug, FromValue, Default, Empty, IntoValue)]
1238 struct Helper {
1239 foo: Annotated<Timestamp>,
1240 }
1241
1242 let x: Annotated<Helper> =
1243 Annotated::from_json(r#"{"foo": -10000000000000000.0}"#).unwrap();
1244 assert_eq!(
1245 x.to_json_pretty().unwrap(),
1246 r#"{
1247 "foo": null,
1248 "_meta": {
1249 "foo": {
1250 "": {
1251 "err": [
1252 [
1253 "invalid_data",
1254 {
1255 "reason": "timestamp out of range"
1256 }
1257 ]
1258 ],
1259 "val": -1e16
1260 }
1261 }
1262 }
1263}"#
1264 );
1265 }
1266}