Skip to content

Commit 92512d6

Browse files
author
Thomas Bahn
authored
Merge pull request #72 from Zenithsiz/unsafe-doc
Document all `unsafe` usages.
2 parents 5bf5bcd + 926dec3 commit 92512d6

File tree

4 files changed

+192
-97
lines changed

4 files changed

+192
-97
lines changed

src/ascii_char.rs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,8 @@ impl AsciiChar {
376376
#[inline]
377377
#[must_use]
378378
pub unsafe fn from_ascii_unchecked(ch: u8) -> Self {
379-
ch.to_ascii_char_unchecked()
379+
// SAFETY: Caller guarantees `ch` is within bounds of ascii.
380+
unsafe { ch.to_ascii_char_unchecked() }
380381
}
381382

382383
/// Converts an ASCII character into a `u8`.
@@ -659,12 +660,20 @@ impl AsciiChar {
659660
/// ```
660661
#[must_use]
661662
pub fn as_printable_char(self) -> char {
662-
unsafe {
663-
match self as u8 {
664-
b' '..=b'~' => self.as_char(),
665-
127 => '␡',
666-
_ => char::from_u32_unchecked(self as u32 + '␀' as u32),
667-
}
663+
match self as u8 {
664+
// Non printable characters
665+
// SAFETY: From codepoint 0x2400 ('␀') to 0x241f (`␟`), there are characters representing
666+
// the unprintable characters from 0x0 to 0x1f, ordered correctly.
667+
// As `b` is guaranteed to be within 0x0 to 0x1f, the conversion represents a
668+
// valid character.
669+
b @ 0x0..=0x1f => unsafe { char::from_u32_unchecked(u32::from('␀') + u32::from(b)) },
670+
671+
// 0x7f (delete) has it's own character at codepoint 0x2420, not 0x247f, so it is special
672+
// cased to return it's character
673+
0x7f => '␡',
674+
675+
// All other characters are printable, and per function contract use `Self::as_char`
676+
_ => self.as_char(),
668677
}
669678
}
670679

@@ -825,6 +834,14 @@ pub trait ToAsciiChar {
825834
fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>;
826835

827836
/// Convert to `AsciiChar` without checking that it is an ASCII character.
837+
///
838+
/// # Safety
839+
/// Calling this function with a value outside of the ascii range, `0x0` to `0x7f` inclusive,
840+
/// is undefined behavior.
841+
// TODO: Make sure this is the contract we want to express in this function.
842+
// It is ambigous if numbers such as `0xffffff20_u32` are valid ascii characters,
843+
// as this function returns `Ascii::Space` due to the cast to `u8`, even though
844+
// `to_ascii_char` returns `Err()`.
828845
unsafe fn to_ascii_char_unchecked(self) -> AsciiChar;
829846
}
830847

@@ -833,6 +850,7 @@ impl ToAsciiChar for AsciiChar {
833850
fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
834851
Ok(self)
835852
}
853+
836854
#[inline]
837855
unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
838856
self
@@ -846,7 +864,10 @@ impl ToAsciiChar for u8 {
846864
}
847865
#[inline]
848866
unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
849-
mem::transmute(self)
867+
// SAFETY: Caller guarantees `self` is within bounds of the enum
868+
// variants, so this cast successfully produces a valid ascii
869+
// variant
870+
unsafe { mem::transmute::<u8, AsciiChar>(self) }
850871
}
851872
}
852873

@@ -857,34 +878,38 @@ impl ToAsciiChar for u8 {
857878
impl ToAsciiChar for i8 {
858879
#[inline]
859880
fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
860-
(self as u32).to_ascii_char()
881+
u32::from(self as u8).to_ascii_char()
861882
}
862883
#[inline]
863884
unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
864-
mem::transmute(self)
885+
// SAFETY: Caller guarantees `self` is within bounds of the enum
886+
// variants, so this cast successfully produces a valid ascii
887+
// variant
888+
unsafe { mem::transmute::<u8, AsciiChar>(self as u8) }
865889
}
866890
}
867891

868892
impl ToAsciiChar for char {
869893
#[inline]
870894
fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
871-
(self as u32).to_ascii_char()
895+
u32::from(self).to_ascii_char()
872896
}
873897
#[inline]
874898
unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
875-
(self as u32).to_ascii_char_unchecked()
899+
// SAFETY: Caller guarantees we're within ascii range.
900+
unsafe { u32::from(self).to_ascii_char_unchecked() }
876901
}
877902
}
878903

879904
impl ToAsciiChar for u32 {
880905
fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
881-
unsafe {
882-
match self {
883-
0..=127 => Ok(self.to_ascii_char_unchecked()),
884-
_ => Err(ToAsciiCharError(())),
885-
}
906+
match self {
907+
// SAFETY: We're within the valid ascii range in this branch.
908+
0x0..=0x7f => Ok(unsafe { self.to_ascii_char_unchecked() }),
909+
_ => Err(ToAsciiCharError(())),
886910
}
887911
}
912+
888913
#[inline]
889914
unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
890915
// Note: This cast discards the top bytes, this may cause problems, see

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy