Skip to content

Commit 40e7475

Browse files
Martin TailleferCopilot
andcommitted
docs(templated_uri): clarify Escaped invariant and percent_encode slice-boundary safety
Address review feedback on two doc comments: - `Escaped<T>` said the wrapped `Display` output contains "no RFC 6570 reserved characters", but the escaped form intentionally includes well-formed `%XX` sequences (and thus `%`). Reword to "no *unescaped* reserved characters". - `percent_encode` said "all slice boundaries fall on unreserved ASCII bytes", which is imprecise for `s[..first]` (can start at index 0 or a multi-byte code point). State the real property: every `&str` slice index is a UTF-8 character boundary because unreserved bytes are all single-byte ASCII. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 10499452-0720-40ab-9e9f-506e1fd3ccaf
1 parent 1b2dbbb commit 40e7475

1 file changed

Lines changed: 8 additions & 4 deletions

File tree

crates/templated_uri/src/escaped.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ use uuid::Uuid;
1414
/// A wrapper that proves the inner value is already escaped for use in URI templates.
1515
///
1616
/// The invariant is enforced via constructors - only types whose [`Display`] output
17-
/// contains no RFC 6570 reserved characters can be wrapped. For inherently-safe
18-
/// types (integers, [`IpAddr`]) an infallible [`From`] impl is provided.
17+
/// is already safe to splice into a URI verbatim (no *unescaped* RFC 6570 reserved
18+
/// characters; well-formed `%XX` percent-escapes are allowed) can be wrapped. For
19+
/// inherently-safe types (integers, [`IpAddr`]) an infallible [`From`] impl is provided.
1920
/// With the `uuid` feature (enabled by default), `Uuid` is also supported.
2021
/// For strings, use the encoding/validating constructors on [`Escaped<Cow<'static, str>>`]
2122
/// (aliased as [`EscapedString`]).
@@ -272,8 +273,11 @@ fn first_reserved(bytes: &[u8]) -> Option<usize> {
272273
///
273274
/// The clean prefix `s[..first]` and every subsequent run of unreserved bytes are copied
274275
/// in bulk via `push_str` (no per-character formatting), and each reserved byte is emitted
275-
/// as a `%XX` escape using a direct hex table. All slice boundaries fall on unreserved
276-
/// ASCII bytes, so the `&str` indexing is always valid.
276+
/// as a `%XX` escape using a direct hex table. Every index used for `&str` slicing is a
277+
/// UTF-8 character boundary: `first` (and each subsequent run boundary) is the position of
278+
/// a byte that is not an unreserved ASCII byte, and since all unreserved bytes are
279+
/// single-byte ASCII, such a position never falls in the middle of a multi-byte code point.
280+
/// So the `&str` indexing is always valid.
277281
// The manual index advance (`i += 1`) mutates to `i *= 1`, which never advances `i` and spins
278282
// the `while` loop forever, pushing to `out` until the process runs out of memory. That hangs the mutation
279283
// runner rather than producing a killable diff, so the function is skipped; its output is

0 commit comments

Comments
 (0)