onetaskgraph_core/
global_id.rs1use std::fmt;
7use std::str::FromStr;
8
9use onetaskgraph_plugin_api::{NativeId, SourceError, SourceName};
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
18#[serde(try_from = "String", into = "String")]
19pub struct GlobalId {
20 pub source: SourceName,
22 pub native: NativeId,
24}
25
26impl GlobalId {
27 pub const ORIGIN_KEY: &'static str = "onetaskgraph.origin";
37
38 #[must_use]
40 pub fn new(source: SourceName, native: NativeId) -> Self {
41 Self { source, native }
42 }
43}
44
45impl fmt::Display for GlobalId {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(f, "{}:{}", self.source, self.native)
48 }
49}
50
51impl FromStr for GlobalId {
52 type Err = SourceError;
53
54 fn from_str(value: &str) -> Result<Self, Self::Err> {
55 let Some((source, native)) = value.split_once(':') else {
56 return Err(SourceError::Config {
57 message: format!(
58 "{value:?} is not a qualified id; write it as <source>:<id>, for example \
59 work:ENG-1"
60 ),
61 });
62 };
63 if native.is_empty() {
64 return Err(SourceError::Config {
65 message: format!("{value:?} names a source but no id; write it as <source>:<id>"),
66 });
67 }
68 Ok(Self {
69 source: SourceName::new(source)?,
70 native: NativeId::from(native),
71 })
72 }
73}
74
75impl TryFrom<String> for GlobalId {
76 type Error = SourceError;
77
78 fn try_from(value: String) -> Result<Self, Self::Error> {
79 value.parse()
80 }
81}
82
83impl From<GlobalId> for String {
84 fn from(value: GlobalId) -> Self {
85 value.to_string()
86 }
87}