squitter 0.1.1

no_std, no_alloc parser and encoder for 1090ES/DF17 (ADS-B extended squitter) messages
Documentation
//! The Mode S six-bit callsign alphabet (ICAO Annex 10 Vol IV), used by
//! aircraft identification messages. Distinct from AIS's six-bit ASCII
//! alphabet (different domain, different mapping): `A`-`Z` are `1..=26`,
//! `0`-`9` are `48..=57`, space is `32`; everything else is unused.

/// Converts a six-bit callsign value to its ASCII byte. Unused code points
/// map to `#`, a placeholder that should never appear in a real callsign.
#[must_use]
pub const fn sixbit_to_ascii(v: u8) -> u8 {
    match v {
        1..=26 => b'A' + (v - 1),
        48..=57 => b'0' + (v - 48),
        32 => b' ',
        _ => b'#',
    }
}

/// Converts an ASCII byte to its six-bit callsign value. Bytes outside the
/// representable set (`A`-`Z`, `0`-`9`, space) map to space, since callsigns
/// are defined only over that alphabet.
#[must_use]
pub const fn ascii_to_sixbit(c: u8) -> u8 {
    match c {
        b'A'..=b'Z' => c - b'A' + 1,
        b'0'..=b'9' => c - b'0' + 48,
        _ => 32,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn roundtrips_letters_and_digits_and_space() {
        for c in b'A'..=b'Z' {
            assert_eq!(sixbit_to_ascii(ascii_to_sixbit(c)), c);
        }
        for c in b'0'..=b'9' {
            assert_eq!(sixbit_to_ascii(ascii_to_sixbit(c)), c);
        }
        assert_eq!(sixbit_to_ascii(ascii_to_sixbit(b' ')), b' ');
    }

    #[test]
    fn known_values() {
        assert_eq!(sixbit_to_ascii(1), b'A');
        assert_eq!(sixbit_to_ascii(26), b'Z');
        assert_eq!(sixbit_to_ascii(48), b'0');
        assert_eq!(sixbit_to_ascii(57), b'9');
        assert_eq!(sixbit_to_ascii(32), b' ');
    }
}