Skip to content

Commit de64f1d

Browse files
authored
Use ref-cast for DisplaySafeUrl (#13696)
By default, Rust does not support safe cast from `&U` to `&T` for `#[repr(transparent)] T(U)` even if the newtype opts in. The dtolnay ref-cast crate fills this gap, allowing to remove `DisplaySafeUrlRef`.
1 parent 410dc33 commit de64f1d

File tree

8 files changed

+97
-137
lines changed

8 files changed

+97
-137
lines changed

Cargo.lock

Lines changed: 30 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ procfs = { version = "0.17.0", default-features = false, features = ["flate2"] }
138138
pubgrub = { git = "https://github.com/astral-sh/pubgrub", rev = "06ec5a5f59ffaeb6cf5079c6cb184467da06c9db" }
139139
quote = { version = "1.0.37" }
140140
rayon = { version = "1.10.0" }
141+
ref-cast = { version = "1.0.24" }
141142
reflink-copy = { version = "0.1.19" }
142143
regex = { version = "1.10.6" }
143144
regex-automata = { version = "0.4.8", default-features = false, features = ["dfa-build", "dfa-search", "perf", "std", "syntax"] }

crates/uv-auth/src/credentials.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use base64::write::EncoderWriter;
44
use std::borrow::Cow;
55
use std::fmt;
66
use uv_redacted::DisplaySafeUrl;
7-
use uv_redacted::DisplaySafeUrlRef;
87

98
use netrc::Netrc;
109
use reqwest::Request;
@@ -145,7 +144,7 @@ impl Credentials {
145144
/// If a username is provided, it must match the login in the netrc file or [`None`] is returned.
146145
pub(crate) fn from_netrc(
147146
netrc: &Netrc,
148-
url: DisplaySafeUrlRef<'_>,
147+
url: &DisplaySafeUrl,
149148
username: Option<&str>,
150149
) -> Option<Self> {
151150
let host = url.host_str()?;

crates/uv-auth/src/keyring.rs

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{io::Write, process::Stdio};
22
use tokio::process::Command;
33
use tracing::{instrument, trace, warn};
4-
use uv_redacted::DisplaySafeUrlRef;
4+
use uv_redacted::DisplaySafeUrl;
55
use uv_warnings::warn_user_once;
66

77
use crate::credentials::Credentials;
@@ -36,11 +36,7 @@ impl KeyringProvider {
3636
/// Returns [`None`] if no password was found for the username or if any errors
3737
/// are encountered in the keyring backend.
3838
#[instrument(skip_all, fields(url = % url.to_string(), username))]
39-
pub async fn fetch(
40-
&self,
41-
url: DisplaySafeUrlRef<'_>,
42-
username: Option<&str>,
43-
) -> Option<Credentials> {
39+
pub async fn fetch(&self, url: &DisplaySafeUrl, username: Option<&str>) -> Option<Credentials> {
4440
// Validate the request
4541
debug_assert!(
4642
url.host_str().is_some(),
@@ -229,7 +225,7 @@ mod tests {
229225
let keyring = KeyringProvider::empty();
230226
// Panics due to debug assertion; returns `None` in production
231227
let result = std::panic::AssertUnwindSafe(
232-
keyring.fetch(DisplaySafeUrlRef::from(&url), Some("user")),
228+
keyring.fetch(DisplaySafeUrl::ref_cast(&url), Some("user")),
233229
)
234230
.catch_unwind()
235231
.await;
@@ -242,7 +238,7 @@ mod tests {
242238
let keyring = KeyringProvider::empty();
243239
// Panics due to debug assertion; returns `None` in production
244240
let result = std::panic::AssertUnwindSafe(
245-
keyring.fetch(DisplaySafeUrlRef::from(&url), Some(url.username())),
241+
keyring.fetch(DisplaySafeUrl::ref_cast(&url), Some(url.username())),
246242
)
247243
.catch_unwind()
248244
.await;
@@ -255,7 +251,7 @@ mod tests {
255251
let keyring = KeyringProvider::empty();
256252
// Panics due to debug assertion; returns `None` in production
257253
let result = std::panic::AssertUnwindSafe(
258-
keyring.fetch(DisplaySafeUrlRef::from(&url), Some(url.username())),
254+
keyring.fetch(DisplaySafeUrl::ref_cast(&url), Some(url.username())),
259255
)
260256
.catch_unwind()
261257
.await;
@@ -265,7 +261,7 @@ mod tests {
265261
#[tokio::test]
266262
async fn fetch_url_no_auth() {
267263
let url = Url::parse("https://example.com").unwrap();
268-
let url = DisplaySafeUrlRef::from(&url);
264+
let url = DisplaySafeUrl::ref_cast(&url);
269265
let keyring = KeyringProvider::empty();
270266
let credentials = keyring.fetch(url, Some("user"));
271267
assert!(credentials.await.is_none());
@@ -277,7 +273,7 @@ mod tests {
277273
let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]);
278274
assert_eq!(
279275
keyring
280-
.fetch(DisplaySafeUrlRef::from(&url), Some("user"))
276+
.fetch(DisplaySafeUrl::ref_cast(&url), Some("user"))
281277
.await,
282278
Some(Credentials::basic(
283279
Some("user".to_string()),
@@ -287,7 +283,7 @@ mod tests {
287283
assert_eq!(
288284
keyring
289285
.fetch(
290-
DisplaySafeUrlRef::from(&url.join("test").unwrap()),
286+
DisplaySafeUrl::ref_cast(&url.join("test").unwrap()),
291287
Some("user")
292288
)
293289
.await,
@@ -303,7 +299,7 @@ mod tests {
303299
let url = Url::parse("https://example.com").unwrap();
304300
let keyring = KeyringProvider::dummy([("other.com", "user", "password")]);
305301
let credentials = keyring
306-
.fetch(DisplaySafeUrlRef::from(&url), Some("user"))
302+
.fetch(DisplaySafeUrl::ref_cast(&url), Some("user"))
307303
.await;
308304
assert_eq!(credentials, None);
309305
}
@@ -318,7 +314,7 @@ mod tests {
318314
assert_eq!(
319315
keyring
320316
.fetch(
321-
DisplaySafeUrlRef::from(&url.join("foo").unwrap()),
317+
DisplaySafeUrl::ref_cast(&url.join("foo").unwrap()),
322318
Some("user")
323319
)
324320
.await,
@@ -329,7 +325,7 @@ mod tests {
329325
);
330326
assert_eq!(
331327
keyring
332-
.fetch(DisplaySafeUrlRef::from(&url), Some("user"))
328+
.fetch(DisplaySafeUrl::ref_cast(&url), Some("user"))
333329
.await,
334330
Some(Credentials::basic(
335331
Some("user".to_string()),
@@ -339,7 +335,7 @@ mod tests {
339335
assert_eq!(
340336
keyring
341337
.fetch(
342-
DisplaySafeUrlRef::from(&url.join("bar").unwrap()),
338+
DisplaySafeUrl::ref_cast(&url.join("bar").unwrap()),
343339
Some("user")
344340
)
345341
.await,
@@ -355,7 +351,7 @@ mod tests {
355351
let url = Url::parse("https://example.com").unwrap();
356352
let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]);
357353
let credentials = keyring
358-
.fetch(DisplaySafeUrlRef::from(&url), Some("user"))
354+
.fetch(DisplaySafeUrl::ref_cast(&url), Some("user"))
359355
.await;
360356
assert_eq!(
361357
credentials,
@@ -370,7 +366,7 @@ mod tests {
370366
async fn fetch_url_no_username() {
371367
let url = Url::parse("https://example.com").unwrap();
372368
let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]);
373-
let credentials = keyring.fetch(DisplaySafeUrlRef::from(&url), None).await;
369+
let credentials = keyring.fetch(DisplaySafeUrl::ref_cast(&url), None).await;
374370
assert_eq!(
375371
credentials,
376372
Some(Credentials::basic(
@@ -385,14 +381,14 @@ mod tests {
385381
let url = Url::parse("https://example.com").unwrap();
386382
let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "foo", "password")]);
387383
let credentials = keyring
388-
.fetch(DisplaySafeUrlRef::from(&url), Some("bar"))
384+
.fetch(DisplaySafeUrl::ref_cast(&url), Some("bar"))
389385
.await;
390386
assert_eq!(credentials, None);
391387

392388
// Still fails if we have `foo` in the URL itself
393389
let url = Url::parse("https://[email protected]").unwrap();
394390
let credentials = keyring
395-
.fetch(DisplaySafeUrlRef::from(&url), Some("bar"))
391+
.fetch(DisplaySafeUrl::ref_cast(&url), Some("bar"))
396392
.await;
397393
assert_eq!(credentials, None);
398394
}

crates/uv-auth/src/middleware.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use std::sync::{Arc, LazyLock};
22

3+
use anyhow::{anyhow, format_err};
34
use http::{Extensions, StatusCode};
4-
use uv_redacted::{DisplaySafeUrl, DisplaySafeUrlRef};
5+
use netrc::Netrc;
6+
use reqwest::{Request, Response};
7+
use reqwest_middleware::{Error, Middleware, Next};
8+
use tracing::{debug, trace, warn};
59

610
use crate::{
711
CREDENTIALS_CACHE, CredentialsCache, KeyringProvider,
@@ -10,11 +14,7 @@ use crate::{
1014
index::{AuthPolicy, Indexes},
1115
realm::Realm,
1216
};
13-
use anyhow::{anyhow, format_err};
14-
use netrc::Netrc;
15-
use reqwest::{Request, Response};
16-
use reqwest_middleware::{Error, Middleware, Next};
17-
use tracing::{debug, trace, warn};
17+
use uv_redacted::DisplaySafeUrl;
1818

1919
/// Strategy for loading netrc files.
2020
enum NetrcMode {
@@ -274,7 +274,7 @@ impl Middleware for AuthMiddleware {
274274
trace!("Checking for credentials for {url}");
275275
(request, None)
276276
};
277-
let retry_request_url = DisplaySafeUrlRef::from(retry_request.url());
277+
let retry_request_url = DisplaySafeUrl::ref_cast(retry_request.url());
278278

279279
let username = credentials
280280
.as_ref()
@@ -283,13 +283,13 @@ impl Middleware for AuthMiddleware {
283283
let credentials = if let Some(index_url) = maybe_index_url {
284284
self.cache().get_url(index_url, &username).or_else(|| {
285285
self.cache()
286-
.get_realm(Realm::from(&*retry_request_url), username)
286+
.get_realm(Realm::from(&**retry_request_url), username)
287287
})
288288
} else {
289289
// Since there is no known index for this URL, check if there are credentials in
290290
// the realm-level cache.
291291
self.cache()
292-
.get_realm(Realm::from(&*retry_request_url), username)
292+
.get_realm(Realm::from(&**retry_request_url), username)
293293
}
294294
.or(credentials);
295295

@@ -433,7 +433,7 @@ impl AuthMiddleware {
433433
} else if let Some(credentials) = self
434434
.fetch_credentials(
435435
Some(&credentials),
436-
DisplaySafeUrlRef::from(request.url()),
436+
DisplaySafeUrl::ref_cast(request.url()),
437437
index_url,
438438
auth_policy,
439439
)
@@ -468,7 +468,7 @@ impl AuthMiddleware {
468468
async fn fetch_credentials(
469469
&self,
470470
credentials: Option<&Credentials>,
471-
url: DisplaySafeUrlRef<'_>,
471+
url: &DisplaySafeUrl,
472472
maybe_index_url: Option<&DisplaySafeUrl>,
473473
auth_policy: AuthPolicy,
474474
) -> Option<Arc<Credentials>> {
@@ -481,7 +481,7 @@ impl AuthMiddleware {
481481
let key = if let Some(index_url) = maybe_index_url {
482482
(FetchUrl::Index(index_url.clone()), username)
483483
} else {
484-
(FetchUrl::Realm(Realm::from(&*url)), username)
484+
(FetchUrl::Realm(Realm::from(&**url)), username)
485485
};
486486
if !self.cache().fetches.register(key.clone()) {
487487
let credentials = self
@@ -529,7 +529,7 @@ impl AuthMiddleware {
529529
if let Some(username) = credentials.and_then(|credentials| credentials.username()) {
530530
if let Some(index_url) = maybe_index_url {
531531
debug!("Checking keyring for credentials for index URL {}@{}", username, index_url);
532-
keyring.fetch(DisplaySafeUrlRef::from(index_url), Some(username)).await
532+
keyring.fetch(DisplaySafeUrl::ref_cast(index_url), Some(username)).await
533533
} else {
534534
debug!("Checking keyring for credentials for full URL {}@{}", username, url);
535535
keyring.fetch(url, Some(username)).await
@@ -539,7 +539,7 @@ impl AuthMiddleware {
539539
debug!(
540540
"Checking keyring for credentials for index URL {index_url} without username due to `authenticate = always`"
541541
);
542-
keyring.fetch(DisplaySafeUrlRef::from(index_url), None).await
542+
keyring.fetch(DisplaySafeUrl::ref_cast(index_url), None).await
543543
} else {
544544
None
545545
}

crates/uv-redacted/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ doctest = false
1616
workspace = true
1717

1818
[dependencies]
19+
ref-cast = { workspace = true }
1920
schemars = { workspace = true, optional = true }
2021
serde = { workspace = true }
2122
url = { workspace = true }

0 commit comments

Comments
 (0)