holochain_zome_types/
cell.rs

1//! A "Cell" represents a DNA/AgentId pair - a space where one dna/agent
2//! can track its source chain and service network requests / responses.
3
4use crate::prelude::*;
5use holo_hash::AgentPubKey;
6use holo_hash::DnaHash;
7use holochain_serialized_bytes::prelude::*;
8use std::fmt;
9
10/// The unique identifier for a Cell.
11/// Cells are uniquely determined by this pair - this pair is necessary
12/// and sufficient to refer to a cell in a conductor
13#[derive(
14    Clone,
15    Debug,
16    Hash,
17    PartialEq,
18    Eq,
19    serde::Serialize,
20    serde::Deserialize,
21    SerializedBytes,
22    Ord,
23    PartialOrd,
24)]
25pub struct CellId(DnaHash, AgentPubKey);
26
27/// Delimiter in a clone id that separates the base cell's role name from the
28/// clone index.
29pub const CLONE_ID_DELIMITER: &str = ".";
30
31/// Identifier of a clone cell, composed of the DNA's role name and the index
32/// of the clone, starting at 0.
33///
34/// Example: `profiles.0`
35#[derive(Clone, Debug, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
36pub struct CloneId(pub String);
37
38impl CloneId {
39    /// Construct a clone id from role name and clone index.
40    pub fn new(role_name: &RoleName, clone_index: u32) -> Self {
41        CloneId(format!(
42            "{}{}{}",
43            role_name, CLONE_ID_DELIMITER, clone_index
44        ))
45    }
46
47    /// Get the clone's base cell's role name.
48    pub fn as_base_role_name(&self) -> RoleName {
49        let (role_name, _) = self.0.split_once(CLONE_ID_DELIMITER).unwrap();
50        role_name.into()
51    }
52
53    /// Get the index of the clone cell.
54    pub fn as_clone_index(&self) -> u32 {
55        let (_, clone_index) = self.0.split_once(CLONE_ID_DELIMITER).unwrap();
56        clone_index.parse::<u32>().unwrap()
57    }
58
59    /// Get an app role name representation of the clone id.
60    pub fn as_app_role_name(&self) -> &RoleName {
61        &self.0
62    }
63}
64
65impl fmt::Display for CloneId {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(
68            f,
69            "{}{}{}",
70            self.as_base_role_name(),
71            CLONE_ID_DELIMITER,
72            self.as_clone_index()
73        )
74    }
75}
76
77/// Errors during conversion from [`RoleName`] to [`CloneId`].
78#[derive(Debug, thiserror::Error)]
79pub enum CloneIdError {
80    /// Multiple clone id delimiters found in app role name. There must only be one delimiter.
81    #[error("Multiple occurrences of reserved character '{CLONE_ID_DELIMITER}' found in app role name: {0}")]
82    MultipleDelimiters(RoleName),
83    /// The clone index could not be parsed into a u32.
84    #[error("Malformed clone index in app role name: {0}")]
85    MalformedCloneIndex(RoleName),
86    /// The role name is not composed of two parts separated by the clone id delimiter.
87    #[error("The role name is not composed of two parts separated by the clone id delimiter: {0}")]
88    MalformedCloneId(RoleName),
89}
90
91impl TryFrom<RoleName> for CloneId {
92    type Error = CloneIdError;
93    fn try_from(value: RoleName) -> Result<Self, Self::Error> {
94        let parts: Vec<&str> = value.split(CLONE_ID_DELIMITER).collect();
95        if parts.len() > 2 {
96            return Err(CloneIdError::MultipleDelimiters(value));
97        }
98        if parts.len() < 2 {
99            return Err(CloneIdError::MalformedCloneId(value));
100        }
101        let role_name = parts[0];
102        let clone_index = parts[1]
103            .parse::<u32>()
104            .map_err(|_| CloneIdError::MalformedCloneIndex(value.clone()))?;
105        Ok(Self::new(&role_name.into(), clone_index))
106    }
107}
108
109impl fmt::Display for CellId {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        write!(f, "Cell({}, {})", self.dna_hash(), self.agent_pubkey())
112    }
113}
114
115impl CellId {
116    /// Create a CellId from its components
117    pub fn new(dna_hash: DnaHash, agent_pubkey: AgentPubKey) -> Self {
118        CellId(dna_hash, agent_pubkey)
119    }
120
121    /// The dna hash/address for this cell.
122    pub fn dna_hash(&self) -> &DnaHash {
123        &self.0
124    }
125
126    /// The agent id / public key for this cell.
127    pub fn agent_pubkey(&self) -> &AgentPubKey {
128        &self.1
129    }
130
131    /// Into [DnaHash] and [AgentPubKey]
132    pub fn into_dna_and_agent(self) -> (DnaHash, AgentPubKey) {
133        (self.0, self.1)
134    }
135}
136
137impl From<(DnaHash, AgentPubKey)> for CellId {
138    fn from(pair: (DnaHash, AgentPubKey)) -> Self {
139        Self(pair.0, pair.1)
140    }
141}