Skip to content

Commit dc865ff

Browse files
sbosnickseanmonstar
authored andcommitted
Document the invariants that make Method safe
The internal InlineExtension and AllocatedExtension types have invariants that ensure that the two uses of "unsafe" in the "extension" submodule of "method" are safe. This documents those invariants for future reference.
1 parent 493b38f commit dc865ff

File tree

1 file changed

+15
-0
lines changed

1 file changed

+15
-0
lines changed

src/method.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,11 @@ mod extension {
314314
use std::str;
315315

316316
#[derive(Clone, PartialEq, Eq, Hash)]
317+
// Invariant: the first self.1 bytes of self.0 are valid UTF-8.
317318
pub struct InlineExtension([u8; InlineExtension::MAX], u8);
318319

319320
#[derive(Clone, PartialEq, Eq, Hash)]
321+
// Invariant: self.0 contains valid UTF-8.
320322
pub struct AllocatedExtension(Box<[u8]>);
321323

322324
impl InlineExtension {
@@ -328,11 +330,15 @@ mod extension {
328330

329331
write_checked(src, &mut data)?;
330332

333+
// Invariant: write_checked ensures that the first src.len() bytes
334+
// of data are valid UTF-8.
331335
Ok(InlineExtension(data, src.len() as u8))
332336
}
333337

334338
pub fn as_str(&self) -> &str {
335339
let InlineExtension(ref data, len) = self;
340+
// Safety: the invariant of InlineExtension ensures that the first
341+
// len bytes of data contain valid UTF-8.
336342
unsafe {str::from_utf8_unchecked(&data[..*len as usize])}
337343
}
338344
}
@@ -343,10 +349,14 @@ mod extension {
343349

344350
write_checked(src, &mut data)?;
345351

352+
// Invariant: data is exactly src.len() long and write_checked
353+
// ensures that the first src.len() bytes of data are valid UTF-8.
346354
Ok(AllocatedExtension(data.into_boxed_slice()))
347355
}
348356

349357
pub fn as_str(&self) -> &str {
358+
// Safety: the invariant of AllocatedExtension ensures that self.0
359+
// contains valid UTF-8.
350360
unsafe {str::from_utf8_unchecked(&self.0)}
351361
}
352362
}
@@ -363,6 +373,9 @@ mod extension {
363373
//
364374
// https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#Method
365375
//
376+
// Note that this definition means that any &[u8] that consists solely of valid
377+
// characters is also valid UTF-8 because the valid method characters are a
378+
// subset of the valid 1 byte UTF-8 encoding.
366379
const METHOD_CHARS: [u8; 256] = [
367380
// 0 1 2 3 4 5 6 7 8 9
368381
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // x
@@ -393,6 +406,8 @@ mod extension {
393406
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0' // 25x
394407
];
395408

409+
// write_checked ensures (among other things) that the first src.len() bytes
410+
// of dst are valid UTF-8
396411
fn write_checked(src: &[u8], dst: &mut [u8]) -> Result<(), InvalidMethod> {
397412
for (i, &b) in src.iter().enumerate() {
398413
let b = METHOD_CHARS[b as usize];

0 commit comments

Comments
 (0)