uv_normalize/
group_name.rs1#[cfg(feature = "schemars")]
2use std::borrow::Cow;
3use std::fmt::{Display, Formatter};
4use std::path::PathBuf;
5use std::str::FromStr;
6use std::sync::LazyLock;
7
8use serde::ser::SerializeSeq;
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10
11use uv_small_str::SmallString;
12
13use crate::{
14 InvalidNameError, InvalidPipGroupError, InvalidPipGroupPathError, validate_and_normalize_ref,
15};
16
17#[derive(
23 Debug,
24 Clone,
25 PartialEq,
26 Eq,
27 PartialOrd,
28 Ord,
29 Hash,
30 rkyv::Archive,
31 rkyv::Deserialize,
32 rkyv::Serialize,
33)]
34#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
35#[rkyv(derive(Debug))]
36pub struct GroupName(SmallString);
37
38impl GroupName {
39 #[allow(clippy::needless_pass_by_value)]
43 pub fn from_owned(name: String) -> Result<Self, InvalidNameError> {
44 validate_and_normalize_ref(&name).map(Self)
45 }
46
47 pub fn as_str(&self) -> &str {
49 &self.0
50 }
51}
52
53impl FromStr for GroupName {
54 type Err = InvalidNameError;
55
56 fn from_str(name: &str) -> Result<Self, Self::Err> {
57 validate_and_normalize_ref(name).map(Self)
58 }
59}
60
61impl<'de> Deserialize<'de> for GroupName {
62 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63 where
64 D: Deserializer<'de>,
65 {
66 struct Visitor;
67
68 impl serde::de::Visitor<'_> for Visitor {
69 type Value = GroupName;
70
71 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
72 f.write_str("a string")
73 }
74
75 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
76 GroupName::from_str(v).map_err(serde::de::Error::custom)
77 }
78
79 fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
80 GroupName::from_owned(v).map_err(serde::de::Error::custom)
81 }
82 }
83
84 deserializer.deserialize_str(Visitor)
85 }
86}
87
88impl Serialize for GroupName {
89 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
90 where
91 S: Serializer,
92 {
93 self.0.serialize(serializer)
94 }
95}
96
97impl std::fmt::Display for GroupName {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 self.0.fmt(f)
100 }
101}
102
103impl AsRef<str> for GroupName {
104 fn as_ref(&self) -> &str {
105 &self.0
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
114#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
115pub struct PipGroupName {
116 pub path: Option<PathBuf>,
117 pub name: GroupName,
118}
119
120impl FromStr for PipGroupName {
121 type Err = InvalidPipGroupError;
122
123 fn from_str(path_and_name: &str) -> Result<Self, Self::Err> {
124 if let Some((path, name)) = path_and_name.rsplit_once(':') {
130 if !path.ends_with("pyproject.toml") {
132 Err(InvalidPipGroupPathError(path.to_owned()))?;
133 }
134
135 let name = GroupName::from_str(name)?;
136 let path = Some(PathBuf::from(path));
137 Ok(Self { path, name })
138 } else {
139 let name = GroupName::from_str(path_and_name)?;
140 let path = None;
141 Ok(Self { path, name })
142 }
143 }
144}
145
146impl<'de> Deserialize<'de> for PipGroupName {
147 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
148 where
149 D: Deserializer<'de>,
150 {
151 let s = String::deserialize(deserializer)?;
152 Self::from_str(&s).map_err(serde::de::Error::custom)
153 }
154}
155
156impl Serialize for PipGroupName {
157 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
158 where
159 S: Serializer,
160 {
161 let string = self.to_string();
162 string.serialize(serializer)
163 }
164}
165
166impl Display for PipGroupName {
167 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
168 if let Some(path) = &self.path {
169 write!(f, "{}:{}", path.display(), self.name)
170 } else {
171 self.name.fmt(f)
172 }
173 }
174}
175
176#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
178pub enum DefaultGroups {
179 All,
181 List(Vec<GroupName>),
183}
184
185#[cfg(feature = "schemars")]
186impl schemars::JsonSchema for DefaultGroups {
187 fn schema_name() -> Cow<'static, str> {
188 Cow::Borrowed("DefaultGroups")
189 }
190
191 fn json_schema(generator: &mut schemars::generate::SchemaGenerator) -> schemars::Schema {
192 schemars::json_schema!({
193 "description": "Either the literal \"all\" or a list of groups",
194 "oneOf": [
195 {
196 "description": "All groups are defaulted",
197 "type": "string",
198 "const": "all"
199 },
200 {
201 "description": "A list of groups",
202 "type": "array",
203 "items": generator.subschema_for::<GroupName>()
204 }
205 ]
206 })
207 }
208}
209
210impl serde::Serialize for DefaultGroups {
212 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
213 where
214 S: serde::Serializer,
215 {
216 match self {
217 Self::All => serializer.serialize_str("all"),
218 Self::List(groups) => {
219 let mut seq = serializer.serialize_seq(Some(groups.len()))?;
220 for group in groups {
221 seq.serialize_element(&group)?;
222 }
223 seq.end()
224 }
225 }
226 }
227}
228
229impl<'de> serde::Deserialize<'de> for DefaultGroups {
231 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
232 where
233 D: serde::Deserializer<'de>,
234 {
235 struct StringOrVecVisitor;
236
237 impl<'de> serde::de::Visitor<'de> for StringOrVecVisitor {
238 type Value = DefaultGroups;
239
240 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
241 formatter.write_str(r#"the string "all" or a list of strings"#)
242 }
243
244 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
245 where
246 E: serde::de::Error,
247 {
248 if value != "all" {
249 return Err(serde::de::Error::custom(
250 r#"default-groups must be "all" or a ["list", "of", "groups"]"#,
251 ));
252 }
253 Ok(DefaultGroups::All)
254 }
255
256 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
257 where
258 A: serde::de::SeqAccess<'de>,
259 {
260 let mut groups = Vec::new();
261
262 while let Some(elem) = seq.next_element::<GroupName>()? {
263 groups.push(elem);
264 }
265
266 Ok(DefaultGroups::List(groups))
267 }
268 }
269
270 deserializer.deserialize_any(StringOrVecVisitor)
271 }
272}
273
274impl Default for DefaultGroups {
275 fn default() -> Self {
277 Self::List(Vec::new())
278 }
279}
280
281pub static DEV_DEPENDENCIES: LazyLock<GroupName> =
286 LazyLock::new(|| GroupName::from_str("dev").unwrap());