~jojo/microcrisp

51fea886147ed61a800d0effcdc0dd48b4be6716 — JoJo 3 months ago 5793a27 master v0.1 v0.1.1
make pack_{str,slice} const fn & bump version to 0.1.1
2 files changed, 46 insertions(+), 12 deletions(-)

M Cargo.toml
M src/lib.rs
M Cargo.toml => Cargo.toml +1 -1
@@ 1,7 1,7 @@
[package]
name = "microcrisp"
authors = ["JoJo <jo@jo.zone>"]
version = "0.1.0"
version = "0.1.1"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

M src/lib.rs => src/lib.rs +45 -11
@@ 10,7 10,7 @@ use std::{
    fmt, str,
};

const SYMBOL_CHARS: &str = "\0abcdefghijklmnopqrstuvwxyz+-*0123456789";
const SYMBOL_CHARS: &[u8] = b"\0abcdefghijklmnopqrstuvwxyz+-*0123456789";
const SYMBOL_MAX_LEN: usize =
    1 + (u128::MAX / (SYMBOL_CHARS.len() - 10) as u128).ilog(SYMBOL_CHARS.len() as u128) as usize;



@@ 98,8 98,8 @@ fn parse_(src: &[u8]) -> PResult<Lisp, &'static str> {
            .map(|x| (i, x))
            .map_err(|e| (i0, e))
        }
        [b, ..] if SYMBOL_CHARS.contains(*b as char) => {
            let s = src[i..].split(|b| !SYMBOL_CHARS.contains(*b as char)).next().unwrap();
        [b, ..] if SYMBOL_CHARS.contains(b) => {
            let s = src[i..].split(|b| !SYMBOL_CHARS.contains(b)).next().unwrap();
            match Symbol::pack_slice(s) {
                Some(symbol) => Ok((i + s.len(), Lisp::Symbol(symbol))),
                None => Err((i, "valid symbol")),


@@ 173,12 173,46 @@ fn map_ok<T, U, E>(r: PResult<T, E>, f: impl FnOnce(T) -> U) -> PResult<U, E> {
}

impl Symbol {
    pub fn pack_str(s: &str) -> Option<Self> {
        Self::pack(s.bytes())
    pub const fn pack_str(s: &str) -> Option<Self> {
        Self::pack_slice(s.as_bytes())
    }

    pub fn pack_slice(s: &[u8]) -> Option<Self> {
        Self::pack(s.iter().cloned())
    const fn ascii_to_val(c: u8) -> Option<u128> {
        let mut i = 0;
        while i < SYMBOL_CHARS.len() {
            if c == SYMBOL_CHARS[i] {
                return Some(i as u128);
            }
            i += 1;
        }
        None
    }

    pub const fn pack_slice(s: &[u8]) -> Option<Self> {
        match s.first() {
            None | Some(b'0'..=b'9' | 0) => None,
            Some(c0) => {
                let mut i = 1;
                let mut acc = match Symbol::ascii_to_val(*c0) {
                    Some(v) => v,
                    None => return None,
                };
                let mut multiplier = (SYMBOL_CHARS.len() - 10) as u128;
                while i < s.len() {
                    let c = s[i];
                    if i == SYMBOL_MAX_LEN || c == 0 {
                        return None;
                    }
                    acc += match Symbol::ascii_to_val(c) {
                        Some(v) => multiplier * v,
                        None => return None,
                    };
                    multiplier *= SYMBOL_CHARS.len() as u128;
                    i += 1;
                }
                Some(Symbol(acc))
            }
        }
    }

    pub fn pack(s: impl IntoIterator<Item = u8>) -> Option<Self> {


@@ 187,13 221,13 @@ impl Symbol {
            None | Some(b'0'..=b'9' | 0) => None,
            Some(c0) => {
                let mut i = 1;
                let mut acc = SYMBOL_CHARS.find(c0 as char)? as u128;
                let mut acc = SYMBOL_CHARS.iter().copied().position(|a| a == c0)? as u128;
                let mut multiplier = (SYMBOL_CHARS.len() - 10) as u128;
                for c in s {
                    if i == SYMBOL_MAX_LEN || c == 0 {
                        return None;
                    }
                    acc += multiplier * SYMBOL_CHARS.find(c as char)? as u128;
                    acc += multiplier * SYMBOL_CHARS.iter().copied().position(|a| a == c)? as u128;
                    multiplier *= SYMBOL_CHARS.len() as u128;
                    i += 1;
                }


@@ 206,11 240,11 @@ impl Symbol {
        let mut cs = [0u8; SYMBOL_MAX_LEN + 1];
        let mut acc = self.0;
        let divisor = (SYMBOL_CHARS.len() - 10) as u128;
        cs[0] = SYMBOL_CHARS.as_bytes()[(acc % divisor) as usize];
        cs[0] = SYMBOL_CHARS[(acc % divisor) as usize];
        acc /= divisor;
        let divisor = SYMBOL_CHARS.len() as u128;
        for c in &mut cs[1..] {
            *c = SYMBOL_CHARS.as_bytes()[(acc % divisor) as usize];
            *c = SYMBOL_CHARS[(acc % divisor) as usize];
            acc /= divisor;
        }
        std::ffi::CStr::from_bytes_until_nul(&cs).unwrap().to_str().unwrap().to_owned()