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}
83