onetaskgraph_plugin_api/
id.rs1use std::fmt;
8
9use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
10use serde::{Deserialize, Serialize};
11
12use crate::SourceError;
13
14#[derive(
20 Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, JsonSchema,
21)]
22#[serde(transparent)]
23pub struct NativeId(pub String);
24
25impl NativeId {
26 #[must_use]
28 pub fn as_str(&self) -> &str {
29 &self.0
30 }
31}
32
33impl From<&str> for NativeId {
34 fn from(value: &str) -> Self {
35 Self(value.to_owned())
36 }
37}
38
39impl From<String> for NativeId {
40 fn from(value: String) -> Self {
41 Self(value)
42 }
43}
44
45impl fmt::Display for NativeId {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.write_str(&self.0)
48 }
49}
50
51pub const SOURCE_NAME_PATTERN: &str = "^[a-z0-9][a-z0-9-]*$";
57
58#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
64#[serde(try_from = "String", into = "String")]
65pub struct SourceName(String);
66
67impl SourceName {
68 pub fn new(value: impl Into<String>) -> Result<Self, SourceError> {
75 let value = value.into();
76 if Self::is_valid(&value) {
77 Ok(Self(value))
78 } else {
79 Err(SourceError::Config {
80 message: format!(
81 "source name {value:?} is not usable; names must match {SOURCE_NAME_PATTERN} \
82 (lower-case letters, digits and hyphens, starting with a letter or digit)"
83 ),
84 })
85 }
86 }
87
88 fn is_valid(value: &str) -> bool {
94 let mut chars = value.chars();
95 let Some(first) = chars.next() else {
96 return false;
97 };
98 if !(first.is_ascii_lowercase() || first.is_ascii_digit()) {
99 return false;
100 }
101 chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-')
102 }
103
104 #[must_use]
106 pub fn as_str(&self) -> &str {
107 &self.0
108 }
109}
110
111impl TryFrom<String> for SourceName {
112 type Error = SourceError;
113
114 fn try_from(value: String) -> Result<Self, Self::Error> {
115 Self::new(value)
116 }
117}
118
119impl From<SourceName> for String {
120 fn from(value: SourceName) -> Self {
121 value.0
122 }
123}
124
125impl fmt::Display for SourceName {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 f.write_str(&self.0)
128 }
129}
130
131impl JsonSchema for SourceName {
132 fn schema_name() -> std::borrow::Cow<'static, str> {
133 "SourceName".into()
134 }
135
136 fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
137 json_schema!({
138 "type": "string",
139 "pattern": SOURCE_NAME_PATTERN,
140 "description": "The name a configuration document gives one configured source.",
141 })
142 }
143}