Skip to main content

links_notation/
reference_literal.rs

1//! Version 1 lossless UTF-8 reference literals, with readable legacy quoting.
2
3/// Encodes exact Unicode text as a version 1 UTF-8 hexadecimal reference.
4pub fn encode_reference_literal(text: &str) -> String {
5    use std::fmt::Write;
6    let mut result = String::with_capacity(text.len() * 2 + 4);
7    result.push_str("~1{");
8    for byte in text.bytes() {
9        write!(result, "{byte:02x}").expect("writing to a string cannot fail");
10    }
11    result.push('}');
12    result
13}
14
15/// Decodes a complete literal, rejecting malformed UTF-8 and unsupported versions.
16pub fn decode_reference_literal(literal: &str) -> Result<String, &'static str> {
17    let prefix = prefix_end(literal).ok_or("invalid reference literal")?;
18    if &literal[..prefix] != "~1{" || !literal.ends_with('}') {
19        return Err("invalid or unsupported reference literal");
20    }
21    let hex = &literal[prefix..literal.len() - 1];
22    if !hex.len().is_multiple_of(2) || !hex.bytes().all(|b| b.is_ascii_hexdigit()) {
23        return Err("reference literal requires an even number of hex digits");
24    }
25    let bytes = (0..hex.len())
26        .step_by(2)
27        .map(|i| u8::from_str_radix(&hex[i..i + 2], 16).expect("validated hex"))
28        .collect();
29    String::from_utf8(bytes).map_err(|_| "reference literal must contain valid UTF-8")
30}
31
32pub(crate) fn prefix_end(text: &str) -> Option<usize> {
33    let bytes = text.as_bytes();
34    if bytes.first() != Some(&b'~') {
35        return None;
36    }
37    let mut position = 1;
38    while bytes.get(position).is_some_and(u8::is_ascii_digit) {
39        position += 1;
40    }
41    (position > 1 && bytes.get(position) == Some(&b'{')).then_some(position + 1)
42}
43
44pub(crate) fn format_reference(text: &str) -> String {
45    if text.is_empty() || text.chars().any(|c| c < ' ' || c == '\u{7f}') {
46        return encode_reference_literal(text);
47    }
48    if prefix_end(text).is_none()
49        && !text.starts_with('#')
50        && !text.chars().any(|c| {
51            c.is_whitespace() || matches!(c, '\u{feff}' | '(' | ')' | ':' | '\'' | '"' | '`')
52        })
53    {
54        return text.to_string();
55    }
56    let first = text.chars().next();
57    let (quote, count) = ['\'', '"', '`']
58        .into_iter()
59        .filter(|&quote| first != Some(quote))
60        .map(|quote| {
61            let (mut longest, mut current) = (0, 0);
62            for c in text.chars() {
63                current = if c == quote { current + 1 } else { 0 };
64                longest = longest.max(current);
65            }
66            (quote, (longest + 1) | 1)
67        })
68        .min_by_key(|&(_, count)| count)
69        .expect("at least two eligible delimiters");
70    let delimiter = quote.to_string().repeat(count);
71    format!("{delimiter}{text}{delimiter}")
72}