proto_types/protovalidate/
into_comparable.rs

1use paste::paste;
2
3use super::comparable_rules::{ComparableGreaterThan, ComparableLessThan, ComparableRules};
4use crate::{
5  protovalidate::{
6    double_rules::{GreaterThan as DoubleGreaterThan, LessThan as DoubleLessThan},
7    duration_rules::{GreaterThan as DurationGreaterThan, LessThan as DurationLessThan},
8    fixed32_rules::{GreaterThan as Fixed32GreaterThan, LessThan as Fixed32LessThan},
9    fixed64_rules::{GreaterThan as Fixed64GreaterThan, LessThan as Fixed64LessThan},
10    float_rules::{GreaterThan as FloatGreaterThan, LessThan as FloatLessThan},
11    int32_rules::{GreaterThan as Int32GreaterThan, LessThan as Int32LessThan},
12    int64_rules::{GreaterThan as Int64GreaterThan, LessThan as Int64LessThan},
13    s_fixed32_rules::{GreaterThan as SFixed32GreaterThan, LessThan as SFixed32LessThan},
14    s_fixed64_rules::{GreaterThan as SFixed64GreaterThan, LessThan as SFixed64LessThan},
15    s_int32_rules::{GreaterThan as SInt32GreaterThan, LessThan as SInt32LessThan},
16    s_int64_rules::{GreaterThan as SInt64GreaterThan, LessThan as SInt64LessThan},
17    timestamp_rules::{GreaterThan as TimestampGreaterThan, LessThan as TimestampLessThan},
18    u_int32_rules::{GreaterThan as UInt32GreaterThan, LessThan as UInt32LessThan},
19    u_int64_rules::{GreaterThan as UInt64GreaterThan, LessThan as UInt64LessThan},
20    DurationRules, TimestampComparableRules, TimestampRules,
21  },
22  Duration, Timestamp, TimestampError,
23};
24
25pub trait IntoComparable<T> {
26  fn into_comparable(self) -> T;
27}
28
29impl TimestampRules {
30  pub fn comparable_rules(&self) -> Result<TimestampComparableRules, String> {
31    let format_timestamp = |t: Timestamp, msg: &str| -> Result<String, String> {
32      t.format(&format!("{} {}", msg, "%d %b %Y %R %Z"))
33        .map_err(|e: TimestampError| {
34          format!(
35            "failed to convert protobuf timestamp to chrono timestamp: {}",
36            e
37          )
38        })
39    };
40
41    let mut greater_than: Option<ComparableGreaterThan<Timestamp>> = None;
42
43    if let Some(gt_rule) = self.greater_than {
44      greater_than = match gt_rule {
45        TimestampGreaterThan::Gt(v) => Some(ComparableGreaterThan::Gt {
46          val: v,
47          error_message: format_timestamp(v, "must be later than")?,
48        }),
49
50        TimestampGreaterThan::Gte(v) => Some(ComparableGreaterThan::Gte {
51          val: v,
52          error_message: format_timestamp(v, "cannot be earlier than")?,
53        }),
54        _ => None,
55      }
56    }
57
58    let mut less_than: Option<ComparableLessThan<Timestamp>> = None;
59
60    if let Some(gt_rule) = self.less_than {
61      less_than = match gt_rule {
62        TimestampLessThan::Lt(v) => Some(ComparableLessThan::Lt {
63          val: v,
64          error_message: format_timestamp(v, "must be earlier than")?,
65        }),
66
67        TimestampLessThan::Lte(v) => Some(ComparableLessThan::Lte {
68          val: v,
69          error_message: format_timestamp(v, "cannot be later than")?,
70        }),
71        _ => None,
72      }
73    }
74
75    let comparable_rules = ComparableRules {
76      less_than,
77      greater_than,
78    };
79
80    let lt_now = matches!(self.less_than, Some(TimestampLessThan::LtNow(true)));
81
82    let gt_now = matches!(self.greater_than, Some(TimestampGreaterThan::GtNow(true)));
83
84    Ok(TimestampComparableRules {
85      comparable_rules: comparable_rules.validate().map_err(|e| e.to_string())?,
86      lt_now,
87      gt_now,
88    })
89  }
90}
91
92impl DurationRules {
93  pub fn comparable_rules(&self) -> Result<ComparableRules<Duration>, &'static str> {
94    let greater_than = self.greater_than.map(|rule| match rule {
95      DurationGreaterThan::Gt(val) => ComparableGreaterThan::Gt {
96        val,
97        error_message: format!("must be longer than {}", val),
98      },
99      DurationGreaterThan::Gte(val) => ComparableGreaterThan::Gte {
100        val,
101        error_message: format!("cannot be shorter than {}", val),
102      },
103    });
104
105    let less_than = self.less_than.map(|rule| match rule {
106      DurationLessThan::Lt(val) => ComparableLessThan::Lt {
107        val,
108        error_message: format!("must be shorter than {}", val),
109      },
110      DurationLessThan::Lte(val) => ComparableLessThan::Lte {
111        val,
112        error_message: format!("cannot be longer than {}", val),
113      },
114    });
115
116    let comparable_rules = ComparableRules {
117      greater_than,
118      less_than,
119    };
120    comparable_rules.validate()
121  }
122}
123
124macro_rules! into_comparable {
125  ($target_type:ty, $rule_type:ident) => {
126    paste! {
127      impl IntoComparable<ComparableLessThan<$target_type>> for [< $rule_type LessThan >] {
128        fn into_comparable(self) -> ComparableLessThan<$target_type> {
129          match self {
130            Self::Lt(val) => ComparableLessThan::Lt { val, error_message: format!("must be smaller than {}", val) },
131            Self::Lte(val) => ComparableLessThan::Lte { val, error_message: format!("cannot be greater than {}", val) },
132          }
133        }
134      }
135
136      impl IntoComparable<ComparableGreaterThan<$target_type>> for [< $rule_type GreaterThan >] {
137        fn into_comparable(self) -> ComparableGreaterThan<$target_type> {
138          match self {
139            Self::Gt(val) => ComparableGreaterThan::Gt { val, error_message: format!("must be greater than {}", val) },
140            Self::Gte(val) => ComparableGreaterThan::Gte { val, error_message: format!("cannot be smaller than {}", val) },
141          }
142        }
143      }
144    }
145  };
146}
147
148into_comparable!(f32, Float);
149into_comparable!(f64, Double);
150into_comparable!(i64, Int64);
151into_comparable!(i32, Int32);
152into_comparable!(i64, SInt64);
153into_comparable!(i32, SInt32);
154into_comparable!(i64, SFixed64);
155into_comparable!(i32, SFixed32);
156into_comparable!(u64, UInt64);
157into_comparable!(u32, UInt32);
158into_comparable!(u64, Fixed64);
159into_comparable!(u32, Fixed32);