Skip to content

Commit 46c9a9a

Browse files
committed
Improve escape methods.
1 parent 522f5a1 commit 46c9a9a

File tree

2 files changed

+46
-36
lines changed

2 files changed

+46
-36
lines changed

library/core/src/char/convert.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ impl From<char> for u32 {
4848
/// ```
4949
#[inline]
5050
fn from(c: char) -> Self {
51-
c as u32
51+
let c = c as Self;
52+
53+
// SAFETY: `char::MAX` is the highest valid Unicode code point.
54+
unsafe { core::hint::assert_unchecked(c <= char::MAX as Self) };
55+
56+
c
5257
}
5358
}
5459

@@ -69,7 +74,12 @@ impl From<char> for u64 {
6974
fn from(c: char) -> Self {
7075
// The char is casted to the value of the code point, then zero-extended to 64 bit.
7176
// See [https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics]
72-
c as u64
77+
let c = c as Self;
78+
79+
// SAFETY: `char::MAX` is the highest valid Unicode code point.
80+
unsafe { core::hint::assert_unchecked(c <= char::MAX as Self) };
81+
82+
c
7383
}
7484
}
7585

@@ -90,7 +100,12 @@ impl From<char> for u128 {
90100
fn from(c: char) -> Self {
91101
// The char is casted to the value of the code point, then zero-extended to 128 bit.
92102
// See [https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics]
93-
c as u128
103+
let c = c as Self;
104+
105+
// SAFETY: `char::MAX` is the highest valid Unicode code point.
106+
unsafe { core::hint::assert_unchecked(c <= char::MAX as Self) };
107+
108+
c
94109
}
95110
}
96111

library/core/src/escape.rs

+28-33
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@ use crate::ops::Range;
77
const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
88

99
#[inline]
10-
const fn backslash<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], u8) {
10+
const fn backslash<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], Range<u8>) {
1111
const { assert!(N >= 2) };
1212

1313
let mut output = [ascii::Char::Null; N];
1414

1515
output[0] = ascii::Char::ReverseSolidus;
1616
output[1] = a;
1717

18-
(output, 2)
18+
(output, 0..2)
1919
}
2020

2121
/// Escapes an ASCII character.
2222
///
2323
/// Returns a buffer and the length of the escaped representation.
24-
const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], u8) {
24+
const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], Range<u8>) {
2525
const { assert!(N >= 4) };
2626

2727
match byte {
@@ -38,7 +38,7 @@ const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], u8) {
3838
&& !byte.is_ascii_control()
3939
{
4040
output[0] = c;
41-
(output, 1)
41+
(output, 0..1)
4242
} else {
4343
let hi = HEX_DIGITS[(byte >> 4) as usize];
4444
let lo = HEX_DIGITS[(byte & 0xf) as usize];
@@ -48,7 +48,7 @@ const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], u8) {
4848
output[2] = hi;
4949
output[3] = lo;
5050

51-
(output, 4)
51+
(output, 0..4)
5252
}
5353
}
5454
}
@@ -57,34 +57,28 @@ const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], u8) {
5757
/// Escapes a character `\u{NNNN}` representation.
5858
///
5959
/// Returns a buffer and the length of the escaped representation.
60-
const fn escape_unicode<const N: usize>(c: char) -> ([ascii::Char; N], u8) {
61-
const { assert!(N >= 10) };
60+
const fn escape_unicode<const N: usize>(c: char) -> ([ascii::Char; N], Range<u8>) {
61+
const { assert!(N >= 10 && N < u8::MAX as usize) };
6262

63-
let c = c as u32;
63+
let c = u32::from(c);
6464

6565
// OR-ing `1` ensures that for `c == 0` the code computes that
6666
// one digit should be printed.
67-
let u_len = (8 - (c | 1).leading_zeros() / 4) as usize;
68-
69-
let closing_paren_offset = 3 + u_len;
67+
let start = (c | 1).leading_zeros() as usize / 4 - 2;
7068

7169
let mut output = [ascii::Char::Null; N];
72-
73-
output[0] = ascii::Char::ReverseSolidus;
74-
output[1] = ascii::Char::SmallU;
75-
output[2] = ascii::Char::LeftCurlyBracket;
76-
77-
output[3 + u_len.saturating_sub(6)] = HEX_DIGITS[((c >> 20) & 0x0f) as usize];
78-
output[3 + u_len.saturating_sub(5)] = HEX_DIGITS[((c >> 16) & 0x0f) as usize];
79-
output[3 + u_len.saturating_sub(4)] = HEX_DIGITS[((c >> 12) & 0x0f) as usize];
80-
output[3 + u_len.saturating_sub(3)] = HEX_DIGITS[((c >> 8) & 0x0f) as usize];
81-
output[3 + u_len.saturating_sub(2)] = HEX_DIGITS[((c >> 4) & 0x0f) as usize];
82-
output[3 + u_len.saturating_sub(1)] = HEX_DIGITS[((c >> 0) & 0x0f) as usize];
83-
84-
output[closing_paren_offset] = ascii::Char::RightCurlyBracket;
85-
86-
let len = (closing_paren_offset + 1) as u8;
87-
(output, len)
70+
output[3] = HEX_DIGITS[((c >> 20) & 15) as usize];
71+
output[4] = HEX_DIGITS[((c >> 16) & 15) as usize];
72+
output[5] = HEX_DIGITS[((c >> 12) & 15) as usize];
73+
output[6] = HEX_DIGITS[((c >> 8) & 15) as usize];
74+
output[7] = HEX_DIGITS[((c >> 4) & 15) as usize];
75+
output[8] = HEX_DIGITS[((c >> 0) & 15) as usize];
76+
output[9] = ascii::Char::RightCurlyBracket;
77+
output[start + 0] = ascii::Char::ReverseSolidus;
78+
output[start + 1] = ascii::Char::SmallU;
79+
output[start + 2] = ascii::Char::LeftCurlyBracket;
80+
81+
(output, (start as u8)..(N as u8))
8882
}
8983

9084
/// An iterator over an fixed-size array.
@@ -102,25 +96,26 @@ pub(crate) struct EscapeIterInner<const N: usize> {
10296

10397
impl<const N: usize> EscapeIterInner<N> {
10498
pub const fn backslash(c: ascii::Char) -> Self {
105-
let (data, len) = backslash(c);
106-
Self { data, alive: 0..len }
99+
let (data, range) = backslash(c);
100+
Self { data, alive: range }
107101
}
108102

109103
pub const fn ascii(c: u8) -> Self {
110-
let (data, len) = escape_ascii(c);
111-
Self { data, alive: 0..len }
104+
let (data, range) = escape_ascii(c);
105+
Self { data, alive: range }
112106
}
113107

114108
pub const fn unicode(c: char) -> Self {
115-
let (data, len) = escape_unicode(c);
116-
Self { data, alive: 0..len }
109+
let (data, range) = escape_unicode(c);
110+
Self { data, alive: range }
117111
}
118112

119113
#[inline]
120114
pub const fn empty() -> Self {
121115
Self { data: [ascii::Char::Null; N], alive: 0..0 }
122116
}
123117

118+
#[inline]
124119
pub fn as_ascii(&self) -> &[ascii::Char] {
125120
// SAFETY: `self.alive` is guaranteed to be a valid range for indexing `self.data`.
126121
unsafe {

0 commit comments

Comments
 (0)