From 208985d771bb92227f3a0ae30d56f810cd803159 Mon Sep 17 00:00:00 2001 From: Steven Bosnick Date: Sun, 29 Mar 2020 22:31:56 -0400 Subject: [PATCH] Audit the use of unsafe in byte_str.rs Add comments describing the invariant that makes the one use of unsafe sound. --- src/byte_str.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/byte_str.rs b/src/byte_str.rs index 686c661a..04e3e15e 100644 --- a/src/byte_str.rs +++ b/src/byte_str.rs @@ -4,6 +4,7 @@ use std::{ops, str}; #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub(crate) struct ByteStr { + // Invariant: bytes contains valid UTF-8 bytes: Bytes, } @@ -11,6 +12,7 @@ impl ByteStr { #[inline] pub fn new() -> ByteStr { ByteStr { + // Invariant: the empty slice is trivially valid UTF-8. bytes: Bytes::new(), } } @@ -18,11 +20,18 @@ impl ByteStr { #[inline] pub fn from_static(val: &'static str) -> ByteStr { ByteStr { + // Invariant: val is a str so contains vaid UTF-8. bytes: Bytes::from_static(val.as_bytes()), } } #[inline] + /// ## Panics + /// In a debug build this will panic if `bytes` is not valid UTF-8. + /// + /// ## Safety + /// `bytes` must contain valid UTF-8. In a release build it is undefined + /// behaviour to call this with `bytes` that is not valid UTF-8. pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr { if cfg!(debug_assertions) { match str::from_utf8(&bytes) { @@ -33,6 +42,7 @@ impl ByteStr { ), } } + // Invariant: assumed by the safety requirements of this function. ByteStr { bytes: bytes } } } @@ -43,6 +53,7 @@ impl ops::Deref for ByteStr { #[inline] fn deref(&self) -> &str { let b: &[u8] = self.bytes.as_ref(); + // Safety: the invariant of `bytes` is that it contains valid UTF-8. unsafe { str::from_utf8_unchecked(b) } } } @@ -51,6 +62,7 @@ impl From for ByteStr { #[inline] fn from(src: String) -> ByteStr { ByteStr { + // Invariant: src is a String so contains valid UTF-8. bytes: Bytes::from(src), } } @@ -60,6 +72,7 @@ impl<'a> From<&'a str> for ByteStr { #[inline] fn from(src: &'a str) -> ByteStr { ByteStr { + // Invariant: src is a str so contains valid UTF-8. bytes: Bytes::copy_from_slice(src.as_bytes()), } }