ASCII Table — Rust source
A searchable, filterable reference for all 128 ASCII code points. See the decimal, hex, octal, and binary form of every character, narrow to printable characters only, clamp the code-point range, and click any row to copy. Runs 100% client-side.
This is the Rust implementation — the same logic the interactive tool runs, in a shareable, citable form.
//! ASCII Table — pure logic (Rust port).
//!
//! CosmoDev polyglot showcase port of the `ascii-table` tool, ported from
//! `src/lib/ascii-table.ts`. Every field is a pure function of the code point
//! 0–127; no I/O, no external crates — the Rust standard library only.
//!
//! Display source — part of CosmoDev's polyglot tool pages.
//!
//! Each of the 128 ASCII code points is described by its decimal / hex / octal /
//! binary forms, a display glyph, a human name, whether it is printable, whether
//! it is a control character, and (for control chars that have one) a C-style
//! escape sequence.
use std::sync::OnceLock;
/// A single ASCII code point and its derived representations.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Entry {
/// Decimal code point, 0–127.
pub dec: u8,
/// Uppercase hex, e.g. `"0x41"`.
pub hex: String,
/// Zero-padded 3-digit octal, e.g. `"101"`.
pub oct: String,
/// Zero-padded 8-bit binary, e.g. `"01000001"`.
pub binary: String,
/// Display glyph: the literal char for printables, a control-picture glyph otherwise.
pub char: String,
/// Human-readable name, e.g. `"Line Feed (LF)"`, `"Uppercase A"`, `"Space"`.
pub name: String,
/// True for 32–126 (visible or space).
pub printable: bool,
/// True for 0–31 and 127.
pub control: bool,
/// C-style escape for control chars that have one (e.g. `"\\n"`); `None` otherwise.
pub escape: Option<String>,
}
/// Official ASCII control-character names for 0–31 and 127.
///
/// Expressed as a `match` so the compiler verifies exhaustiveness — every
/// control code point is labeled, and adding a new branch without coverage is a
/// compile error. The unreachable arm documents the precondition.
fn control_name(code: u8) -> &'static str {
match code {
0 => "Null (NUL)",
1 => "Start of Heading (SOH)",
2 => "Start of Text (STX)",
3 => "End of Text (ETX)",
4 => "End of Transmission (EOT)",
5 => "Enquiry (ENQ)",
6 => "Acknowledge (ACK)",
7 => "Bell (BEL)",
8 => "Backspace (BS)",
9 => "Horizontal Tab (HT)",
10 => "Line Feed (LF)",
11 => "Vertical Tab (VT)",
12 => "Form Feed (FF)",
13 => "Carriage Return (CR)",
14 => "Shift Out (SO)",
15 => "Shift In (SI)",
16 => "Data Link Escape (DLE)",
17 => "Device Control 1 (DC1)",
18 => "Device Control 2 (DC2)",
19 => "Device Control 3 (DC3)",
20 => "Device Control 4 (DC4)",
21 => "Negative Acknowledge (NAK)",
22 => "Synchronous Idle (SYN)",
23 => "End of Transmission Block (ETB)",
24 => "Cancel (CAN)",
25 => "End of Medium (EM)",
26 => "Substitute (SUB)",
27 => "Escape (ESC)",
28 => "File Separator (FS)",
29 => "Group Separator (GS)",
30 => "Record Separator (RS)",
31 => "Unit Separator (US)",
127 => "Delete (DEL)",
// Only called with control codes; defensive guard for misuse.
_ => unreachable!("control_name called with non-control code point {code}"),
}
}
/// C-style escape for the control chars that own a standard/common one.
/// Returns the literal 2-character source token (backslash + letter), or `None`.
fn control_escape(code: u8) -> Option<&'static str> {
Some(match code {
0 => "\\0",
7 => "\\a",
8 => "\\b",
9 => "\\t",
10 => "\\n",
11 => "\\v",
12 => "\\f",
13 => "\\r",
27 => "\\e",
_ => return None,
})
}
/// Name for a printable punctuation / symbol glyph, if it has a dedicated one.
/// Letters and digits are derived in [`letter_name`].
fn symbol_name(code: u8) -> Option<&'static str> {
Some(match code {
32 => "Space",
33 => "Exclamation mark",
34 => "Quotation mark",
35 => "Number sign",
36 => "Dollar sign",
37 => "Percent sign",
38 => "Ampersand",
39 => "Apostrophe",
40 => "Left parenthesis",
41 => "Right parenthesis",
42 => "Asterisk",
43 => "Plus sign",
44 => "Comma",
45 => "Hyphen / Minus",
46 => "Full stop",
47 => "Slash",
58 => "Colon",
59 => "Semicolon",
60 => "Less-than sign",
61 => "Equals sign",
62 => "Greater-than sign",
63 => "Question mark",
64 => "At sign",
91 => "Left bracket",
92 => "Backslash",
93 => "Right bracket",
94 => "Circumflex / Caret",
95 => "Underscore",
96 => "Grave accent",
123 => "Left brace",
124 => "Vertical bar",
125 => "Right brace",
126 => "Tilde",
_ => return None,
})
}
/// Derive a name for a printable letter or digit.
fn letter_name(code: u8) -> String {
let ch = char::from(code);
match code {
48..=57 => format!("Digit {}", code - 48), // '0'..'9'
65..=90 => format!("Uppercase {ch}"), // 'A'..'Z'
97..=122 => format!("Lowercase {ch}"), // 'a'..'z'
_ => ch.to_string(),
}
}
/// Build a single entry from its code point (0–127).
fn make_entry(code: u8) -> Entry {
let control = code <= 31 || code == 127;
// Control-picture glyph: U+2400 for 0–31, U+2421 ("symbol for delete") for DEL.
// char::from_u32 is defensive — these code points are all valid scalar values.
let char_glyph = if control {
let cp = if code == 127 { 0x2421 } else { 0x2400 + code as u32 };
char::from_u32(cp).map(char::to_string).unwrap_or_default()
} else {
char::from(code).to_string()
};
let name = if control {
control_name(code).to_string()
} else if let Some(sym) = symbol_name(code) {
sym.to_string()
} else {
letter_name(code)
};
let escape = if control {
control_escape(code).map(str::to_string)
} else {
None
};
Entry {
dec: code,
hex: format!("0x{:02X}", code),
oct: format!("{:03o}", code),
binary: format!("{:08b}", code),
char: char_glyph,
name,
printable: !control,
control,
escape,
}
}
// The 128-entry table is built once and cached for the lifetime of the program.
// `OnceLock` (std::sync) gives us a lazily-initialized static without any
// external crate like lazy_static / once_cell.
static ENTRIES: OnceLock<Vec<Entry>> = OnceLock::new();
/// The full 128-entry ASCII table, indexed by code point.
pub fn entries() -> &'static [Entry] {
ENTRIES.get_or_init(|| (0..=127).map(make_entry).collect())
}
/// Look up a single entry by code point.
///
/// Returns `None` for out-of-range input. The TypeScript variant returns `null`;
/// Rust's idiomatic equivalent is `Option`, which the type system forces callers
/// to handle. The borrow ties the returned reference to the static table.
pub fn get_entry(code: i32) -> Option<&'static Entry> {
if !(0..=127).contains(&code) {
return None;
}
Some(&entries()[code as usize])
}
/// Optional parameters for [`filter_table`]. All fields optional.
#[derive(Default)]
pub struct FilterOpts {
/// Case-insensitive substring matched against dec / hex / oct / binary / name / char / escape.
pub query: Option<String>,
/// Hide control characters.
pub printable_only: bool,
/// Lower decimal bound (default 0).
pub min: Option<u8>,
/// Upper decimal bound (default 127).
pub max: Option<u8>,
}
/// Filter the table.
///
/// `query` is a case-insensitive substring matched against dec / hex / oct /
/// binary / name / char / escape. `printable_only` hides controls. `min` / `max`
/// clamp the decimal range (defaults 0–127). Returns references into the shared
/// static table, so filtering is allocation-free apart from the result `Vec`.
pub fn filter_table(opts: &FilterOpts) -> Vec<&'static Entry> {
let q = opts.query.as_deref().unwrap_or("").trim().to_lowercase();
let lo = opts.min.unwrap_or(0);
let hi = opts.max.unwrap_or(127);
entries()
.iter()
.filter(|e| {
if opts.printable_only && !e.printable {
return false;
}
if e.dec < lo || e.dec > hi {
return false;
}
if q.is_empty() {
return true;
}
// Lowercase the fields that carry case; glyphs and numerals pass through.
let dec = e.dec.to_string();
let hex_lc = e.hex.to_lowercase();
let name_lc = e.name.to_lowercase();
let char_lc = e.char.to_lowercase();
let esc = e.escape.as_deref().unwrap_or("");
[dec.as_str(), hex_lc.as_str(), &e.oct, &e.binary, name_lc.as_str(), char_lc.as_str(), esc]
.into_iter()
.any(|h| h.contains(&q))
})
.collect()
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →