uv_distribution_types/
index_name.rs1use std::borrow::Cow;
2use std::ops::Deref;
3use std::str::FromStr;
4
5use thiserror::Error;
6
7use uv_small_str::SmallString;
8
9#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, serde::Serialize)]
13#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
14pub struct IndexName(SmallString);
15
16impl IndexName {
17 pub fn new(name: &str) -> Result<Self, IndexNameError> {
20 for c in name.chars() {
21 match c {
22 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' => {}
23 c if c.is_ascii() => {
24 return Err(IndexNameError::UnsupportedCharacter(c, name.to_string()));
25 }
26 c => {
27 return Err(IndexNameError::NonAsciiName(c, name.to_string()));
28 }
29 }
30 }
31 Ok(Self(SmallString::from(name)))
32 }
33
34 pub fn to_env_var(&self) -> String {
38 self.0
39 .chars()
40 .map(|c| {
41 if c.is_ascii_alphanumeric() {
42 c.to_ascii_uppercase()
43 } else {
44 '_'
45 }
46 })
47 .collect::<String>()
48 }
49}
50
51impl FromStr for IndexName {
52 type Err = IndexNameError;
53
54 fn from_str(s: &str) -> Result<Self, Self::Err> {
55 Self::new(s)
56 }
57}
58
59impl<'de> serde::de::Deserialize<'de> for IndexName {
60 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
61 where
62 D: serde::de::Deserializer<'de>,
63 {
64 let s = Cow::<'_, str>::deserialize(deserializer)?;
65 Self::new(&s).map_err(serde::de::Error::custom)
66 }
67}
68
69impl std::fmt::Display for IndexName {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 self.0.fmt(f)
72 }
73}
74
75impl AsRef<str> for IndexName {
76 fn as_ref(&self) -> &str {
77 &self.0
78 }
79}
80
81impl Deref for IndexName {
82 type Target = str;
83
84 fn deref(&self) -> &Self::Target {
85 &self.0
86 }
87}
88
89#[derive(Error, Debug)]
91pub enum IndexNameError {
92 #[error("Index included a name, but the name was empty")]
93 EmptyName,
94 #[error(
95 "Index names may only contain letters, digits, hyphens, underscores, and periods, but found unsupported character (`{0}`) in: `{1}`"
96 )]
97 UnsupportedCharacter(char, String),
98 #[error("Index names must be ASCII, but found non-ASCII character (`{0}`) in: `{1}`")]
99 NonAsciiName(char, String),
100}