ic_backup/model/inventory/target/
mod.rs1use super::InventoryRecordError;
4use crate::model::artifacts::ArtifactChecksumRecord;
5use serde::{Deserialize, Deserializer, Serialize};
6
7pub const MAX_INVENTORY_ROLE_BYTES: usize = 256;
9
10#[derive(Clone, Debug)]
12pub struct InventoryTargetRequest {
13 pub canister_id: String,
15 pub parent_canister_id: Option<String>,
17 pub role: Option<String>,
19 pub module_hash: Option<String>,
21}
22
23#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
25#[serde(try_from = "TargetFields")]
26pub struct InventoryTargetRecord {
27 canister_id: String,
28 parent_canister_id: Option<String>,
29 role: Option<String>,
30 module_hash: Option<String>,
31}
32
33#[derive(Deserialize)]
34#[serde(deny_unknown_fields)]
35struct TargetFields {
36 canister_id: String,
37 #[serde(deserialize_with = "required_text")]
38 parent_canister_id: Option<String>,
39 #[serde(deserialize_with = "required_text")]
40 role: Option<String>,
41 #[serde(deserialize_with = "required_text")]
42 module_hash: Option<String>,
43}
44fn required_text<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<String>, D::Error> {
45 Option::deserialize(deserializer)
46}
47impl TryFrom<TargetFields> for InventoryTargetRecord {
48 type Error = InventoryRecordError;
49 fn try_from(fields: TargetFields) -> Result<Self, Self::Error> {
50 Self::new(&InventoryTargetRequest {
51 canister_id: fields.canister_id,
52 parent_canister_id: fields.parent_canister_id,
53 role: fields.role,
54 module_hash: fields.module_hash,
55 })
56 }
57}
58impl InventoryTargetRecord {
59 pub fn new(request: &InventoryTargetRequest) -> Result<Self, InventoryRecordError> {
64 if request
65 .role
66 .as_ref()
67 .is_some_and(|role| role.len() > MAX_INVENTORY_ROLE_BYTES)
68 {
69 return Err(InventoryRecordError::RoleTooLarge);
70 }
71 Ok(Self {
72 canister_id: crate::model::principal::canonical_text(&request.canister_id)
73 .ok_or(InventoryRecordError::InvalidPrincipal("canister_id"))?,
74 parent_canister_id: request
75 .parent_canister_id
76 .as_deref()
77 .map(|value| {
78 crate::model::principal::canonical_text(value)
79 .ok_or(InventoryRecordError::InvalidPrincipal("parent_canister_id"))
80 })
81 .transpose()?,
82 role: request.role.clone(),
83 module_hash: request
84 .module_hash
85 .as_deref()
86 .map(|value| {
87 ArtifactChecksumRecord::from_hash(value).map(|hash| hash.hash().to_owned())
88 })
89 .transpose()?,
90 })
91 }
92 #[must_use]
94 pub fn canister_id(&self) -> &str {
95 &self.canister_id
96 }
97 #[must_use]
99 pub fn parent_canister_id(&self) -> Option<&str> {
100 self.parent_canister_id.as_deref()
101 }
102 #[must_use]
104 pub fn role(&self) -> Option<&str> {
105 self.role.as_deref()
106 }
107 #[must_use]
109 pub fn module_hash(&self) -> Option<&str> {
110 self.module_hash.as_deref()
111 }
112}