|
1 | 1 | use serde::{Deserialize, Serialize}; |
2 | | -use spin_app::locked::FixedVersion; |
| 2 | +use spin_serde::FixedVersion; |
| 3 | +pub use spin_serde::{KebabId, SnakeId}; |
3 | 4 |
|
4 | 5 | pub use super::common::{ComponentBuildConfig, ComponentSource, Variable, WasiFilesMount}; |
5 | 6 |
|
@@ -115,70 +116,6 @@ pub struct Component { |
115 | 116 | pub build: Option<ComponentBuildConfig>, |
116 | 117 | } |
117 | 118 |
|
118 | | -/// A "kebab-case" identifier. |
119 | | -pub type KebabId = Id<'-'>; |
120 | | - |
121 | | -/// A "snake_case" identifier. |
122 | | -pub type SnakeId = Id<'_'>; |
123 | | - |
124 | | -/// An ID is a non-empty string containing one or more component model |
125 | | -/// `word`s separated by a delimiter char. |
126 | | -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] |
127 | | -#[serde(into = "String", try_from = "String")] |
128 | | -pub struct Id<const DELIM: char>(String); |
129 | | - |
130 | | -impl<const DELIM: char> std::fmt::Display for Id<DELIM> { |
131 | | - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
132 | | - write!(f, "{}", self.0) |
133 | | - } |
134 | | -} |
135 | | - |
136 | | -impl<const DELIM: char> AsRef<str> for Id<DELIM> { |
137 | | - fn as_ref(&self) -> &str { |
138 | | - &self.0 |
139 | | - } |
140 | | -} |
141 | | - |
142 | | -impl<const DELIM: char> From<Id<DELIM>> for String { |
143 | | - fn from(value: Id<DELIM>) -> Self { |
144 | | - value.0 |
145 | | - } |
146 | | -} |
147 | | - |
148 | | -impl<const DELIM: char> TryFrom<String> for Id<DELIM> { |
149 | | - type Error = String; |
150 | | - |
151 | | - fn try_from(id: String) -> Result<Self, Self::Error> { |
152 | | - if id.is_empty() { |
153 | | - return Err("empty".into()); |
154 | | - } |
155 | | - for word in id.split(DELIM) { |
156 | | - if word.is_empty() { |
157 | | - return Err(format!("{DELIM:?}-separated words must not be empty")); |
158 | | - } |
159 | | - let mut chars = word.chars(); |
160 | | - let first = chars.next().unwrap(); |
161 | | - if !first.is_ascii_alphabetic() { |
162 | | - return Err(format!( |
163 | | - "{DELIM:?}-separated words must start with an ASCII letter; got {first:?}" |
164 | | - )); |
165 | | - } |
166 | | - let word_is_uppercase = first.is_ascii_uppercase(); |
167 | | - for ch in chars { |
168 | | - if ch.is_ascii_digit() { |
169 | | - } else if !ch.is_ascii_alphanumeric() { |
170 | | - return Err(format!( |
171 | | - "{DELIM:?}-separated words may only contain alphanumeric ASCII; got {ch:?}" |
172 | | - )); |
173 | | - } else if ch.is_ascii_uppercase() != word_is_uppercase { |
174 | | - return Err(format!("{DELIM:?}-separated words must be all lowercase or all UPPERCASE; got {word:?}")); |
175 | | - } |
176 | | - } |
177 | | - } |
178 | | - Ok(Self(id)) |
179 | | - } |
180 | | -} |
181 | | - |
182 | 119 | mod one_or_many { |
183 | 120 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
184 | 121 |
|
|
0 commit comments