kinode_process_lib/types/
process_id.rs

1pub use crate::ProcessId;
2use serde::{Deserialize, Serialize};
3use std::hash::{Hash, Hasher};
4
5/// `ProcessId` is defined in the wit bindings, but constructors and methods
6/// are defined here. A `ProcessId` contains a process name, a package name,
7/// and a publisher node ID.
8impl ProcessId {
9    /// Create a new `ProcessId`. If `process_name` is left as None, this will generate
10    /// a random u64 number, convert to string, and store that as the name.
11    pub fn new(process_name: Option<&str>, package_name: &str, publisher_node: &str) -> Self {
12        ProcessId {
13            process_name: process_name
14                .unwrap_or(&rand::random::<u64>().to_string())
15                .into(),
16            package_name: package_name.into(),
17            publisher_node: publisher_node.into(),
18        }
19    }
20    /// Read the process name from a `ProcessId`.
21    pub fn process(&self) -> &str {
22        &self.process_name
23    }
24    /// Read the package name from a `ProcessId`.
25    pub fn package(&self) -> &str {
26        &self.package_name
27    }
28    /// Read the publisher node ID from a `ProcessId`. Note that `ProcessId`
29    /// segments are not parsed for validity, and a node ID stored here is
30    /// not guaranteed to be a valid ID in the name system, or be connected
31    /// to an identity at all.
32    pub fn publisher(&self) -> &str {
33        &self.publisher_node
34    }
35}
36
37impl std::str::FromStr for ProcessId {
38    type Err = ProcessIdParseError;
39    /// Attempts to parse a `ProcessId` from a string. The string must match the pattern
40    /// of three segments containing only lowercase letters, numbers and hyphens, separated by colons.
41    fn from_str(input: &str) -> Result<Self, ProcessIdParseError> {
42        let re = regex::Regex::new(r"^[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-.]+$").unwrap();
43        if !re.is_match(input) {
44            return Err(ProcessIdParseError::InvalidCharacter);
45        }
46
47        let segments: Vec<&str> = input.split(':').collect();
48        Ok(ProcessId {
49            process_name: segments[0].to_string(),
50            package_name: segments[1].to_string(),
51            publisher_node: segments[2].to_string(),
52        })
53    }
54}
55
56impl Serialize for ProcessId {
57    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58    where
59        S: serde::ser::Serializer,
60    {
61        format!("{}", self).serialize(serializer)
62    }
63}
64
65impl<'a> Deserialize<'a> for ProcessId {
66    fn deserialize<D>(deserializer: D) -> Result<ProcessId, D::Error>
67    where
68        D: serde::de::Deserializer<'a>,
69    {
70        let s = String::deserialize(deserializer)?;
71        s.parse().map_err(serde::de::Error::custom)
72    }
73}
74
75impl Hash for ProcessId {
76    fn hash<H: Hasher>(&self, state: &mut H) {
77        self.process_name.hash(state);
78        self.package_name.hash(state);
79        self.publisher_node.hash(state);
80    }
81}
82
83impl Eq for ProcessId {}
84
85impl From<(&str, &str, &str)> for ProcessId {
86    fn from(input: (&str, &str, &str)) -> Self {
87        ProcessId::new(Some(input.0), input.1, input.2)
88    }
89}
90
91impl std::fmt::Display for ProcessId {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        write!(
94            f,
95            "{}:{}:{}",
96            self.process_name, self.package_name, self.publisher_node
97        )
98    }
99}
100
101impl PartialEq for ProcessId {
102    fn eq(&self, other: &Self) -> bool {
103        self.process_name == other.process_name
104            && self.package_name == other.package_name
105            && self.publisher_node == other.publisher_node
106    }
107}
108
109impl PartialEq<&str> for ProcessId {
110    fn eq(&self, other: &&str) -> bool {
111        &self.to_string() == other
112    }
113}
114
115impl PartialEq<ProcessId> for &str {
116    fn eq(&self, other: &ProcessId) -> bool {
117        self == &other.to_string()
118    }
119}
120
121#[derive(Debug)]
122pub enum ProcessIdParseError {
123    TooManyColons,
124    MissingField,
125    InvalidCharacter,
126}
127
128impl std::fmt::Display for ProcessIdParseError {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        write!(
131            f,
132            "{}",
133            match self {
134                ProcessIdParseError::TooManyColons => "Too many colons",
135                ProcessIdParseError::MissingField => "Missing field",
136                ProcessIdParseError::InvalidCharacter => "Invalid character",
137            }
138        )
139    }
140}
141
142impl std::error::Error for ProcessIdParseError {
143    fn description(&self) -> &str {
144        match self {
145            ProcessIdParseError::TooManyColons => "Too many colons",
146            ProcessIdParseError::MissingField => "Missing field",
147            ProcessIdParseError::InvalidCharacter => "Invalid character",
148        }
149    }
150}