Skip to main content

proxmox_api/types/
bounded_integer.rs

1#[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}