uv_normalize/
package_name.rs1use std::borrow::Cow;
2use std::cmp::PartialEq;
3use std::str::FromStr;
4
5use serde::{Deserialize, Deserializer, Serialize};
6
7use uv_small_str::SmallString;
8
9use crate::{InvalidNameError, validate_and_normalize_ref};
10
11#[derive(
18 Debug,
19 Clone,
20 PartialEq,
21 Eq,
22 PartialOrd,
23 Ord,
24 Hash,
25 Serialize,
26 rkyv::Archive,
27 rkyv::Deserialize,
28 rkyv::Serialize,
29)]
30#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
31#[rkyv(derive(Debug))]
32pub struct PackageName(SmallString);
33
34impl PackageName {
35 #[allow(clippy::needless_pass_by_value)]
39 pub fn from_owned(name: String) -> Result<Self, InvalidNameError> {
40 validate_and_normalize_ref(&name).map(Self)
41 }
42
43 pub fn as_dist_info_name(&self) -> Cow<'_, str> {
47 if let Some(dash_position) = self.0.find('-') {
48 let mut owned_string = String::with_capacity(self.0.len());
50 owned_string.push_str(&self.0[..dash_position]);
51 owned_string.push('_');
52
53 owned_string.extend(
55 self.0[dash_position + 1..]
56 .chars()
57 .map(|character| if character == '-' { '_' } else { character }),
58 );
59
60 Cow::Owned(owned_string)
61 } else {
62 Cow::Borrowed(self.0.as_ref())
63 }
64 }
65
66 pub fn as_str(&self) -> &str {
68 &self.0
69 }
70}
71
72impl From<&Self> for PackageName {
73 fn from(package_name: &Self) -> Self {
75 package_name.clone()
76 }
77}
78
79impl FromStr for PackageName {
80 type Err = InvalidNameError;
81
82 fn from_str(name: &str) -> Result<Self, Self::Err> {
83 validate_and_normalize_ref(name).map(Self)
84 }
85}
86
87impl<'de> Deserialize<'de> for PackageName {
88 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89 where
90 D: Deserializer<'de>,
91 {
92 struct Visitor;
93
94 impl serde::de::Visitor<'_> for Visitor {
95 type Value = PackageName;
96
97 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
98 f.write_str("a string")
99 }
100
101 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
102 PackageName::from_str(v).map_err(serde::de::Error::custom)
103 }
104
105 fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
106 PackageName::from_owned(v).map_err(serde::de::Error::custom)
107 }
108 }
109
110 deserializer.deserialize_str(Visitor)
111 }
112}
113
114impl std::fmt::Display for PackageName {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 self.0.fmt(f)
117 }
118}
119
120impl AsRef<str> for PackageName {
121 fn as_ref(&self) -> &str {
122 &self.0
123 }
124}