Skip to content

Match CharEscape discriminants to ESCAPE table entries #1279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

dtolnay
Copy link
Member

@dtolnay dtolnay commented Jul 31, 2025

In agreement with #1273 (comment), this shows no discernible performance change on my machines, despite seeming like it might make a difference in each of the following conversions:

json/src/ser.rs

Lines 1770 to 1782 in 6843c36

use self::CharEscape::*;
let escape_char = match char_escape {
Quote => b'"',
ReverseSolidus => b'\\',
Solidus => b'/',
Backspace => b'b',
FormFeed => b'f',
LineFeed => b'n',
CarriageReturn => b'r',
Tab => b't',
AsciiControl(_) => b'u',
};

json/src/ser.rs

Lines 2111 to 2122 in 6843c36

let char_escape = match escape {
self::BB => CharEscape::Backspace,
self::TT => CharEscape::Tab,
self::NN => CharEscape::LineFeed,
self::FF => CharEscape::FormFeed,
self::RR => CharEscape::CarriageReturn,
self::QU => CharEscape::Quote,
self::BS => CharEscape::ReverseSolidus,
self::UU => CharEscape::AsciiControl(byte),
// Safety: the escape table does not contain any other type of character.
_ => unsafe { hint::unreachable_unchecked() },
};

Compiler Explorer
use core::hint;

pub enum CharEscape1 {
    Quote,
    ReverseSolidus,
    Solidus,
    Backspace,
    FormFeed,
    LineFeed,
    CarriageReturn,
    Tab,
    AsciiControl(u8),
}

#[repr(u8)]
pub enum CharEscape2 {
    Quote = b'"',
    ReverseSolidus = b'\\',
    Solidus = b'/',
    Backspace = b'b',
    FormFeed = b'f',
    LineFeed = b'n',
    CarriageReturn = b'r',
    Tab = b't',
    AsciiControl(u8) = b'u',
}

#[unsafe(no_mangle)]
pub fn charescape1_to_u8(char_escape: CharEscape1) -> u8 {
    match char_escape { 
        CharEscape1::Quote => b'"', 
        CharEscape1::ReverseSolidus => b'\\', 
        CharEscape1::Solidus => b'/', 
        CharEscape1::Backspace => b'b', 
        CharEscape1::FormFeed => b'f', 
        CharEscape1::LineFeed => b'n', 
        CharEscape1::CarriageReturn => b'r', 
        CharEscape1::Tab => b't', 
        CharEscape1::AsciiControl(_) => b'u', 
    }
}

#[unsafe(no_mangle)]
pub fn charescape2_to_u8(char_escape: CharEscape2) -> u8 {
    match char_escape { 
        CharEscape2::Quote => b'"', 
        CharEscape2::ReverseSolidus => b'\\', 
        CharEscape2::Solidus => b'/', 
        CharEscape2::Backspace => b'b', 
        CharEscape2::FormFeed => b'f', 
        CharEscape2::LineFeed => b'n', 
        CharEscape2::CarriageReturn => b'r', 
        CharEscape2::Tab => b't', 
        CharEscape2::AsciiControl(_) => b'u', 
    }
}

#[unsafe(no_mangle)]
pub unsafe fn u8_to_charescape1(escape: u8, byte: u8) -> CharEscape1 {
    match escape { 
        self::BB => CharEscape1::Backspace, 
        self::TT => CharEscape1::Tab, 
        self::NN => CharEscape1::LineFeed, 
        self::FF => CharEscape1::FormFeed, 
        self::RR => CharEscape1::CarriageReturn, 
        self::QU => CharEscape1::Quote, 
        self::BS => CharEscape1::ReverseSolidus, 
        self::UU => CharEscape1::AsciiControl(byte), 
        _ => unsafe { hint::unreachable_unchecked() }, 
    }
}

#[unsafe(no_mangle)]
pub unsafe fn u8_to_charescape2(escape: u8, byte: u8) -> CharEscape2 {
    match escape { 
        self::BB => CharEscape2::Backspace, 
        self::TT => CharEscape2::Tab, 
        self::NN => CharEscape2::LineFeed, 
        self::FF => CharEscape2::FormFeed, 
        self::RR => CharEscape2::CarriageReturn, 
        self::QU => CharEscape2::Quote, 
        self::BS => CharEscape2::ReverseSolidus, 
        self::UU => CharEscape2::AsciiControl(byte), 
        _ => unsafe { hint::unreachable_unchecked() }, 
    }
}

const BB: u8 = b'b';
const TT: u8 = b't';
const NN: u8 = b'n';
const FF: u8 = b'f';
const RR: u8 = b'r';
const QU: u8 = b'"';
const BS: u8 = b'\\';
const UU: u8 = b'u';
charescape1_to_u8:
        movzx   eax, dil
        lea     rcx, [rip + .Lswitch.table.charescape1_to_u8]
        movzx   eax, byte ptr [rax + rcx]
        ret

charescape2_to_u8:
        mov     eax, edi
        ret

u8_to_charescape1:
        mov     edx, esi
        movzx   eax, dil
        add     eax, -92
        cmp     eax, 25
        ja      .LBB2_8
        lea     rcx, [rip + .LJTI2_0]
        movsxd  rax, dword ptr [rcx + 4*rax]
        add     rax, rcx
        jmp     rax
.LBB2_9:
        mov     al, 1
        ret
.LBB2_5:
        mov     al, 5
        ret
.LBB2_8:
        xor     eax, eax
        ret
.LBB2_6:
        mov     al, 4
        ret
.LBB2_2:
        mov     al, 3
        ret
.LBB2_4:
        mov     al, 7
        ret
.LBB2_10:
        mov     al, 8
        ret
.LBB2_7:
        mov     al, 6
        ret
.LBB2_3:
        ud2
.LJTI2_0:
        .long   .LBB2_9-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_2-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_6-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_5-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_7-.LJTI2_0
        .long   .LBB2_3-.LJTI2_0
        .long   .LBB2_4-.LJTI2_0
        .long   .LBB2_10-.LJTI2_0

u8_to_charescape2:
        mov     edx, esi
        mov     eax, edi
        ret

.Lswitch.table.charescape1_to_u8:
        .ascii  "\"\\/bfnrtu"

@dtolnay dtolnay closed this Jul 31, 2025
@dtolnay dtolnay deleted the charescape branch July 31, 2025 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant