zvariant/
container_depths.rs

1use crate::{Error, MaxDepthExceeded, Result};
2
3// We take the limits from the D-Bus specification for gvariant as well.
4//
5// The GVariant specification removed all the limits, from the D-Bus specification but that turned
6// out to be a [mistake]. Although glib went for a higher limit (128) but we'll stick to the D-Bus
7// limits and expand if/when needed.
8//
9// [mistake]: https://gitlab.gnome.org/GNOME/glib/-/commit/7c4e6e9fbe473de0401c778c6b0c4aad27d5145a
10const MAX_STRUCT_DEPTH: u8 = 32;
11const MAX_ARRAY_DEPTH: u8 = 32;
12const MAX_TOTAL_DEPTH: u8 = 64;
13
14// Represents the current depth of all container being (de)serialized.
15#[derive(Debug, Default, Clone, Copy)]
16pub(crate) struct ContainerDepths {
17    structure: u8,
18    array: u8,
19    variant: u8,
20    #[cfg(feature = "gvariant")]
21    maybe: u8,
22}
23
24impl ContainerDepths {
25    pub fn inc_structure(mut self) -> Result<Self> {
26        self.structure += 1;
27        self.check()
28    }
29
30    pub fn dec_structure(mut self) -> Self {
31        self.structure -= 1;
32        self
33    }
34
35    pub fn inc_array(mut self) -> Result<Self> {
36        self.array += 1;
37        self.check()
38    }
39
40    pub fn dec_array(mut self) -> Self {
41        self.array -= 1;
42        self
43    }
44
45    pub fn inc_variant(mut self) -> Result<Self> {
46        self.variant += 1;
47        self.check()
48    }
49
50    #[cfg(feature = "gvariant")]
51    pub fn inc_maybe(mut self) -> Result<Self> {
52        self.maybe += 1;
53        self.check()
54    }
55
56    #[cfg(feature = "gvariant")]
57    pub fn dec_maybe(mut self) -> Self {
58        self.maybe -= 1;
59        self
60    }
61
62    fn check(self) -> Result<Self> {
63        if self.structure > MAX_STRUCT_DEPTH {
64            return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Structure));
65        }
66
67        if self.array > MAX_ARRAY_DEPTH {
68            return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Array));
69        }
70
71        #[cfg(not(feature = "gvariant"))]
72        let total = self.structure + self.array + self.variant;
73        #[cfg(feature = "gvariant")]
74        let total = self.structure + self.array + self.variant + self.maybe;
75
76        if total > MAX_TOTAL_DEPTH {
77            return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Container));
78        }
79
80        Ok(self)
81    }
82}