Skip to content

Commit 949e863

Browse files
committed
refactor: move lockfile schemas to cargo-util-schemas
1 parent efc42e1 commit 949e863

File tree

5 files changed

+226
-227
lines changed

5 files changed

+226
-227
lines changed

crates/cargo-util-schemas/src/lockfile.rs

Lines changed: 222 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,229 @@
1+
use std::collections::BTreeMap;
2+
use std::fmt;
3+
use std::{cmp::Ordering, str::FromStr};
4+
5+
use serde::{Deserialize, Serialize, de, ser};
6+
use url::Url;
7+
8+
use crate::core::{GitReference, SourceKind};
9+
10+
/// The `Cargo.lock` structure.
11+
#[derive(Serialize, Deserialize, Debug)]
12+
pub struct EncodableResolve {
13+
pub version: Option<u32>,
14+
pub package: Option<Vec<EncodableDependency>>,
15+
/// `root` is optional to allow backward compatibility.
16+
pub root: Option<EncodableDependency>,
17+
pub metadata: Option<Metadata>,
18+
#[serde(default, skip_serializing_if = "Patch::is_empty")]
19+
pub patch: Patch,
20+
}
21+
22+
#[derive(Serialize, Deserialize, Debug, Default)]
23+
pub struct Patch {
24+
pub unused: Vec<EncodableDependency>,
25+
}
26+
27+
pub type Metadata = BTreeMap<String, String>;
28+
29+
impl Patch {
30+
fn is_empty(&self) -> bool {
31+
self.unused.is_empty()
32+
}
33+
}
34+
35+
#[derive(Serialize, Deserialize, Debug, PartialOrd, Ord, PartialEq, Eq)]
36+
pub struct EncodableDependency {
37+
pub name: String,
38+
pub version: String,
39+
pub source: Option<EncodableSourceId>,
40+
pub checksum: Option<String>,
41+
pub dependencies: Option<Vec<EncodablePackageId>>,
42+
pub replace: Option<EncodablePackageId>,
43+
}
44+
45+
#[derive(Debug, Clone)]
46+
pub struct EncodableSourceId {
47+
/// Full string of the source
48+
source_str: String,
49+
/// Used for sources ordering
50+
kind: SourceKind,
51+
/// Used for sources ordering
52+
url: Url,
53+
}
54+
55+
impl EncodableSourceId {
56+
pub fn new(source: String) -> Result<Self, EncodableSourceIdError> {
57+
let source_str = source.clone();
58+
let (kind, url) = source.split_once('+').ok_or_else(|| {
59+
EncodableSourceIdError(EncodableSourceIdErrorKind::InvalidSource(source.clone()).into())
60+
})?;
61+
62+
let url = Url::parse(url).map_err(|msg| EncodableSourceIdErrorKind::InvalidUrl {
63+
url: url.to_string(),
64+
msg: msg.to_string(),
65+
})?;
66+
67+
let kind = match kind {
68+
"git" => {
69+
let reference = GitReference::from_query(url.query_pairs());
70+
SourceKind::Git(reference)
71+
}
72+
"registry" => SourceKind::Registry,
73+
"sparse" => SourceKind::SparseRegistry,
74+
"path" => SourceKind::Path,
75+
kind => {
76+
return Err(EncodableSourceIdErrorKind::UnsupportedSource(kind.to_string()).into());
77+
}
78+
};
79+
80+
Ok(Self {
81+
source_str,
82+
kind,
83+
url,
84+
})
85+
}
86+
87+
pub fn kind(&self) -> &SourceKind {
88+
&self.kind
89+
}
90+
91+
pub fn url(&self) -> &Url {
92+
&self.url
93+
}
94+
95+
pub fn source_str(&self) -> &String {
96+
&self.source_str
97+
}
98+
99+
pub fn as_url(&self) -> impl fmt::Display + '_ {
100+
self.source_str.clone()
101+
}
102+
}
103+
104+
impl ser::Serialize for EncodableSourceId {
105+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
106+
where
107+
S: ser::Serializer,
108+
{
109+
s.collect_str(&self.as_url())
110+
}
111+
}
112+
113+
impl<'de> de::Deserialize<'de> for EncodableSourceId {
114+
fn deserialize<D>(d: D) -> Result<Self, D::Error>
115+
where
116+
D: de::Deserializer<'de>,
117+
{
118+
let s = String::deserialize(d)?;
119+
Ok(EncodableSourceId::new(s).map_err(de::Error::custom)?)
120+
}
121+
}
122+
123+
impl std::hash::Hash for EncodableSourceId {
124+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
125+
self.kind.hash(state);
126+
self.url.hash(state);
127+
}
128+
}
129+
130+
impl std::cmp::PartialEq for EncodableSourceId {
131+
fn eq(&self, other: &Self) -> bool {
132+
self.kind == other.kind && self.url == other.url
133+
}
134+
}
135+
136+
impl std::cmp::Eq for EncodableSourceId {}
137+
138+
impl PartialOrd for EncodableSourceId {
139+
fn partial_cmp(&self, other: &EncodableSourceId) -> Option<Ordering> {
140+
Some(self.cmp(other))
141+
}
142+
}
143+
144+
impl Ord for EncodableSourceId {
145+
fn cmp(&self, other: &EncodableSourceId) -> Ordering {
146+
self.kind
147+
.cmp(&other.kind)
148+
.then_with(|| self.url.cmp(&other.url))
149+
}
150+
}
151+
152+
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
153+
pub struct EncodablePackageId {
154+
pub name: String,
155+
pub version: Option<String>,
156+
pub source: Option<EncodableSourceId>,
157+
}
158+
159+
impl fmt::Display for EncodablePackageId {
160+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161+
write!(f, "{}", self.name)?;
162+
if let Some(s) = &self.version {
163+
write!(f, " {}", s)?;
164+
}
165+
if let Some(s) = &self.source {
166+
write!(f, " ({})", s.as_url())?;
167+
}
168+
Ok(())
169+
}
170+
}
171+
172+
impl FromStr for EncodablePackageId {
173+
type Err = EncodablePackageIdError;
174+
175+
fn from_str(s: &str) -> Result<EncodablePackageId, Self::Err> {
176+
let mut s = s.splitn(3, ' ');
177+
let name = s.next().unwrap();
178+
let version = s.next();
179+
let source_id = match s.next() {
180+
Some(s) => {
181+
if let Some(s) = s.strip_prefix('(').and_then(|s| s.strip_suffix(')')) {
182+
Some(EncodableSourceId::new(s.to_string())?)
183+
} else {
184+
return Err(EncodablePackageIdErrorKind::InvalidSerializedPackageId.into());
185+
}
186+
}
187+
None => None,
188+
};
189+
190+
Ok(EncodablePackageId {
191+
name: name.to_string(),
192+
version: version.map(|v| v.to_string()),
193+
source: source_id,
194+
})
195+
}
196+
}
197+
198+
impl ser::Serialize for EncodablePackageId {
199+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
200+
where
201+
S: ser::Serializer,
202+
{
203+
s.collect_str(self)
204+
}
205+
}
206+
207+
impl<'de> de::Deserialize<'de> for EncodablePackageId {
208+
fn deserialize<D>(d: D) -> Result<EncodablePackageId, D::Error>
209+
where
210+
D: de::Deserializer<'de>,
211+
{
212+
String::deserialize(d).and_then(|string| {
213+
string
214+
.parse::<EncodablePackageId>()
215+
.map_err(de::Error::custom)
216+
})
217+
}
218+
}
219+
1220
#[derive(Debug, thiserror::Error)]
2221
#[error(transparent)]
3-
pub struct EncodableSourceIdError(#[from] pub EncodableSourceIdErrorKind);
222+
pub struct EncodableSourceIdError(#[from] EncodableSourceIdErrorKind);
4223

5224
#[non_exhaustive]
6225
#[derive(Debug, thiserror::Error)]
7-
pub enum EncodableSourceIdErrorKind {
226+
enum EncodableSourceIdErrorKind {
8227
#[error("invalid source `{0}`")]
9228
InvalidSource(String),
10229

@@ -27,7 +246,7 @@ impl From<EncodableSourceIdError> for EncodablePackageIdError {
27246

28247
#[non_exhaustive]
29248
#[derive(Debug, thiserror::Error)]
30-
pub enum EncodablePackageIdErrorKind {
249+
enum EncodablePackageIdErrorKind {
31250
#[error("invalid serialied PackageId")]
32251
InvalidSerializedPackageId,
33252

0 commit comments

Comments
 (0)