Skip to main content

made_core/value_objects/ceremony/
ceremony_lineage.rs

1use serde::{Deserialize, Deserializer, Serialize};
2
3use crate::error::DomainError;
4
5use super::{CeremonyId, ChildDepth, ChildDepthBudget, ChildGroupId, ChildPosition};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
8pub struct CeremonyLineage {
9    root_id: CeremonyId,
10    parent_id: CeremonyId,
11    group_id: ChildGroupId,
12    position: ChildPosition,
13    depth: ChildDepth,
14    remaining_depth: ChildDepthBudget,
15}
16
17impl CeremonyLineage {
18    pub fn new(
19        root_id: CeremonyId,
20        parent_id: CeremonyId,
21        group_id: ChildGroupId,
22        position: ChildPosition,
23        depth: ChildDepth,
24        remaining_depth: ChildDepthBudget,
25    ) -> Result<Self, DomainError> {
26        let lineage = Self {
27            root_id,
28            parent_id,
29            group_id,
30            position,
31            depth,
32            remaining_depth,
33        };
34        lineage.validate()?;
35        Ok(lineage)
36    }
37    #[must_use]
38    pub fn root_id(&self) -> &CeremonyId {
39        &self.root_id
40    }
41    #[must_use]
42    pub fn parent_id(&self) -> &CeremonyId {
43        &self.parent_id
44    }
45    #[must_use]
46    pub fn group_id(&self) -> &ChildGroupId {
47        &self.group_id
48    }
49    #[must_use]
50    pub const fn position(&self) -> ChildPosition {
51        self.position
52    }
53    #[must_use]
54    pub const fn depth(&self) -> ChildDepth {
55        self.depth
56    }
57    #[must_use]
58    pub const fn remaining_depth(&self) -> ChildDepthBudget {
59        self.remaining_depth
60    }
61
62    pub fn validate(&self) -> Result<(), DomainError> {
63        let root_is_parent = self.root_id == self.parent_id;
64        if (self.depth == ChildDepth::FIRST) != root_is_parent {
65            return Err(DomainError::InvalidDocument {
66                reason: "child lineage root and parent are inconsistent with depth".to_owned(),
67            });
68        }
69        if self.depth.get() + self.remaining_depth.get() > super::MaxChildDepth::SERVER_MAX.get() {
70            return Err(DomainError::InvalidDocument {
71                reason: "child lineage exceeds the server depth ceiling".to_owned(),
72            });
73        }
74        Ok(())
75    }
76}
77
78impl<'de> Deserialize<'de> for CeremonyLineage {
79    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
80    where
81        D: Deserializer<'de>,
82    {
83        #[derive(Deserialize)]
84        struct UncheckedCeremonyLineage {
85            root_id: CeremonyId,
86            parent_id: CeremonyId,
87            group_id: ChildGroupId,
88            position: ChildPosition,
89            depth: ChildDepth,
90            remaining_depth: ChildDepthBudget,
91        }
92
93        let raw = UncheckedCeremonyLineage::deserialize(deserializer)?;
94        Self::new(
95            raw.root_id,
96            raw.parent_id,
97            raw.group_id,
98            raw.position,
99            raw.depth,
100            raw.remaining_depth,
101        )
102        .map_err(serde::de::Error::custom)
103    }
104}