proxmox_api/types/
bounded_integer.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub enum BoundedIntegerError {
3 ValueLower,
4 ValueHigher,
5}
6
7impl std::fmt::Display for BoundedIntegerError {
8 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9 match self {
10 BoundedIntegerError::ValueLower => write!(f, "value is below minimum"),
11 BoundedIntegerError::ValueHigher => write!(f, "value is above maximum"),
12 }
13 }
14}
15
16impl std::error::Error for BoundedIntegerError {}
17
18pub trait BoundedInteger {
19 const MIN: Option<i128> = None;
20 const MAX: Option<i128> = None;
21 const DEFAULT: Option<i128> = None;
22 const TYPE_DESCRIPTION: &'static str;
23
24 fn get(&self) -> i128;
25
26 fn new(value: i128) -> Result<Self, BoundedIntegerError>
27 where
28 Self: Sized;
29
30 fn validate(value: i128) -> Result<(), BoundedIntegerError> {
31 if let Some(min) = Self::MIN
32 && value < min
33 {
34 return Err(BoundedIntegerError::ValueLower);
35 }
36 if let Some(max) = Self::MAX
37 && value > max
38 {
39 return Err(BoundedIntegerError::ValueHigher);
40 }
41 Ok(())
42 }
43}
44
45use serde::{Deserialize, Deserializer, Serializer};
46
47pub fn serialize_bounded_integer<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
48where
49 S: Serializer,
50 T: BoundedInteger,
51{
52 serializer.serialize_i128(value.get())
53}
54
55fn parse_value_to_i128(value: &serde_json::Value) -> Option<i128> {
56 match value {
57 serde_json::Value::Number(n) => n.as_i128(),
58 serde_json::Value::String(s) => s.parse::<i128>().ok(),
59 _ => None,
60 }
61}
62
63pub fn deserialize_bounded_integer<'de, T, D>(deserializer: D) -> Result<T, D::Error>
64where
65 D: Deserializer<'de>,
66 T: BoundedInteger + TryFrom<i128, Error = BoundedIntegerError>,
67{
68 let value = Option::<serde_json::Value>::deserialize(deserializer)?;
69 let i128_value = value
70 .as_ref()
71 .and_then(parse_value_to_i128)
72 .ok_or_else(|| serde::de::Error::custom("could not parse value as i128"))?;
73 T::try_from(i128_value).map_err(|e| {
74 serde::de::Error::custom(format!(
75 "could not parse as {} with error: {}",
76 T::TYPE_DESCRIPTION,
77 e
78 ))
79 })
80}