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