@@ -50,6 +50,7 @@ pub struct Release {
50
50
pub ( crate ) build_time : Option < DateTime < Utc > > ,
51
51
pub ( crate ) stars : i32 ,
52
52
pub ( crate ) has_unyanked_releases : Option < bool > ,
53
+ pub ( crate ) href : Option < & ' static str > ,
53
54
}
54
55
55
56
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
@@ -124,6 +125,7 @@ pub(crate) async fn get_releases(
124
125
build_time : row. get ( 5 ) ,
125
126
stars : row. get :: < Option < i32 > , _ > ( 6 ) . unwrap_or ( 0 ) ,
126
127
has_unyanked_releases : None ,
128
+ href : None ,
127
129
} )
128
130
. try_collect ( )
129
131
. await ?)
@@ -142,13 +144,28 @@ struct SearchResult {
142
144
pub next_page : Option < String > ,
143
145
}
144
146
147
+ fn rust_lib_release ( name : & str , description : & str , href : & ' static str ) -> ReleaseStatus {
148
+ ReleaseStatus :: Available ( Release {
149
+ name : name. to_string ( ) ,
150
+ version : String :: new ( ) ,
151
+ description : Some ( description. to_string ( ) ) ,
152
+ build_time : None ,
153
+ target_name : None ,
154
+ rustdoc_status : false ,
155
+ stars : 0 ,
156
+ has_unyanked_releases : None ,
157
+ href : Some ( href) ,
158
+ } )
159
+ }
160
+
145
161
/// Get the search results for a crate search query
146
162
///
147
163
/// This delegates to the crates.io search API.
148
164
async fn get_search_results (
149
165
conn : & mut sqlx:: PgConnection ,
150
166
registry : & RegistryApi ,
151
167
query_params : & str ,
168
+ query : & str ,
152
169
) -> Result < SearchResult , anyhow:: Error > {
153
170
let crate :: registry_api:: Search { crates, meta } = registry. search ( query_params) . await ?;
154
171
@@ -206,28 +223,68 @@ async fn get_search_results(
206
223
rustdoc_status : row. rustdoc_status . unwrap_or ( false ) ,
207
224
stars : row. stars . unwrap_or ( 0 ) ,
208
225
has_unyanked_releases : row. has_unyanked_releases ,
226
+ href : None ,
209
227
} ,
210
228
)
211
229
} )
212
230
. try_collect ( )
213
231
. await ?;
214
232
233
+ // start with the original names from crates.io to keep the original ranking,
234
+ // extend with the release/build information from docs.rs
235
+ // Crates that are not on docs.rs yet will not be returned.
236
+ let mut results = Vec :: new ( ) ;
237
+ match query {
238
+ "std" | "libstd" => {
239
+ results. push ( rust_lib_release (
240
+ "std" ,
241
+ "Rust standard library" ,
242
+ "https://doc.rust-lang.org/stable/std" ,
243
+ ) ) ;
244
+ }
245
+ "core" | "libcore" => {
246
+ results. push ( rust_lib_release (
247
+ "core" ,
248
+ "Rust core library" ,
249
+ "https://doc.rust-lang.org/stable/core" ,
250
+ ) ) ;
251
+ }
252
+ "alloc" | "liballoc" => {
253
+ results. push ( rust_lib_release (
254
+ "core" ,
255
+ "Rust alloc library" ,
256
+ "https://doc.rust-lang.org/stable/alloc" ,
257
+ ) ) ;
258
+ }
259
+ "proc_macro" | "proc-macro" | "libproc_macro" | "libproc-macro" => {
260
+ results. push ( rust_lib_release (
261
+ "proc_macro" ,
262
+ "Rust proc_macro library" ,
263
+ "https://doc.rust-lang.org/stable/proc_macro" ,
264
+ ) ) ;
265
+ }
266
+ "test" | "libtest" => {
267
+ results. push ( rust_lib_release (
268
+ "test" ,
269
+ "Rust test library" ,
270
+ "https://doc.rust-lang.org/stable/test" ,
271
+ ) ) ;
272
+ }
273
+ _ => { }
274
+ }
275
+
215
276
let names: Vec < String > =
216
277
Arc :: into_inner ( names) . expect ( "Arc still borrowed in `get_search_results`" ) ;
278
+ results. extend ( names. into_iter ( ) . map ( |name| {
279
+ if let Some ( release) = crates. remove ( & name) {
280
+ ReleaseStatus :: Available ( release)
281
+ } else {
282
+ ReleaseStatus :: NotAvailable ( name)
283
+ }
284
+ } ) ) ;
285
+
217
286
Ok ( SearchResult {
218
- // start with the original names from crates.io to keep the original ranking,
219
- // extend with the release/build information from docs.rs
220
- // Crates that are not on docs.rs yet will not be returned.
221
- results : names
222
- . into_iter ( )
223
- . map ( |name| {
224
- if let Some ( release) = crates. remove ( & name) {
225
- ReleaseStatus :: Available ( release)
226
- } else {
227
- ReleaseStatus :: NotAvailable ( name)
228
- }
229
- } )
230
- . collect ( ) ,
287
+ results,
231
288
prev_page : meta. prev_page ,
232
289
next_page : meta. next_page ,
233
290
} )
@@ -589,15 +646,15 @@ pub(crate) async fn search_handler(
589
646
}
590
647
}
591
648
592
- get_search_results ( & mut conn, & registry, query_params) . await ?
649
+ get_search_results ( & mut conn, & registry, query_params, "" ) . await ?
593
650
} else if !query. is_empty ( ) {
594
651
let query_params: String = form_urlencoded:: Serializer :: new ( String :: new ( ) )
595
652
. append_pair ( "q" , & query)
596
653
. append_pair ( "sort" , & sort_by)
597
654
. append_pair ( "per_page" , & RELEASES_IN_RELEASES . to_string ( ) )
598
655
. finish ( ) ;
599
656
600
- get_search_results ( & mut conn, & registry, & query_params) . await ?
657
+ get_search_results ( & mut conn, & registry, & query_params, & query ) . await ?
601
658
} else {
602
659
return Err ( AxumNope :: NoResults ) ;
603
660
} ;
@@ -2231,4 +2288,55 @@ mod tests {
2231
2288
Ok ( ( ) )
2232
2289
} ) ;
2233
2290
}
2291
+
2292
+ #[ test]
2293
+ fn test_search_std ( ) {
2294
+ async_wrapper ( |env| async move {
2295
+ let web = env. web_app ( ) . await ;
2296
+
2297
+ async fn inner ( web : & axum:: Router , krate : & str ) -> Result < ( ) , anyhow:: Error > {
2298
+ let full = kuchikiki:: parse_html ( ) . one (
2299
+ web. get ( & format ! ( "/releases/search?query={krate}" ) )
2300
+ . await ?
2301
+ . text ( )
2302
+ . await ?,
2303
+ ) ;
2304
+ let items = full
2305
+ . select ( "ul a.release" )
2306
+ . expect ( "missing list items" )
2307
+ . collect :: < Vec < _ > > ( ) ;
2308
+
2309
+ // empty because expand_rebuild_queue is not set
2310
+ let item_element = items. first ( ) . unwrap ( ) ;
2311
+ let item = item_element. as_node ( ) ;
2312
+ assert_eq ! (
2313
+ item. select( ".name" )
2314
+ . unwrap( )
2315
+ . next( )
2316
+ . unwrap( )
2317
+ . text_contents( ) ,
2318
+ "std"
2319
+ ) ;
2320
+ assert_eq ! (
2321
+ item. select( ".description" )
2322
+ . unwrap( )
2323
+ . next( )
2324
+ . unwrap( )
2325
+ . text_contents( ) ,
2326
+ "Rust standard library" ,
2327
+ ) ;
2328
+ assert_eq ! (
2329
+ item_element. attributes. borrow( ) . get( "href" ) . unwrap( ) ,
2330
+ "https://doc.rust-lang.org/stable/std"
2331
+ ) ;
2332
+
2333
+ Ok ( ( ) )
2334
+ }
2335
+
2336
+ inner ( & web, "std" ) . await ?;
2337
+ inner ( & web, "libstd" ) . await ?;
2338
+
2339
+ Ok ( ( ) )
2340
+ } ) ;
2341
+ }
2234
2342
}
0 commit comments