trust-ident 0.1.0

Mangler for identifiers
Documentation
#![no_std]
use core::{borrow::Borrow, cmp::Ordering, fmt::{Debug, Display, Formatter}, marker::PhantomData, ops::Deref};

use duplicate::duplicate_item;
use nom::{
    character::complete::digit1,
    combinator::{map_res, recognize},
    IResult, Parser,
};
#[macro_use]
extern crate alloc;
use alloc::vec::Vec;
use alloc::{
    borrow::{Cow, ToOwned},
    string::String,
};
fn my_usize(input: &str) -> IResult<&str, usize> {
    map_res(recognize(digit1), str::parse).parse(input)
}
fn my_u32(input: &str) -> IResult<&str, u32> {
    map_res(recognize(digit1), str::parse).parse(input)
}

pub trait Cfg {
    fn valid(ch: char) -> bool;
    const EMBED: &'static str;
    const SEP: &'static str;
}
pub struct CCfg {}
impl Cfg for CCfg {
    fn valid(k: char) -> bool {
        k.is_ascii_alphanumeric() || k == '$'
    }

    const EMBED: &'static str = "$";

    const SEP: &'static str = "c";
}

#[repr(transparent)]
pub struct Ident<C: Cfg>(String, PhantomData<fn(&C) -> &C>);
impl<C: Cfg> Clone for Ident<C>{
    fn clone(&self) -> Self {
        Self(self.0.clone(), self.1.clone())
    }
}
#[repr(transparent)]
pub struct IdentRef<C: Cfg>(PhantomData<fn(&C) -> &C>, str);
impl<C: Cfg> Deref for Ident<C> {
    type Target = IdentRef<C>;

    fn deref(&self) -> &Self::Target {
        unsafe { core::mem::transmute(self.0.as_str()) }
    }
}
impl<C: Cfg> Deref for IdentRef<C> {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        &self.1
    }
}
#[duplicate_item(
    typ;
    [Ident];
    [IdentRef];
)]
const _: () = {
    impl<C: Cfg> PartialEq for typ<C>{
        fn eq(&self, other: &Self) -> bool{
            return self.as_str() == other.as_str();
        }
    }
    impl<C: Cfg> Eq for typ<C>{

    }
    impl<C: Cfg> PartialOrd for typ<C>{
        fn partial_cmp(&self, other: &Self) -> Option<Ordering>{
            self.as_str().partial_cmp(other.as_str())
        }
    }
    impl<C: Cfg> Ord for typ<C>{
        fn cmp(&self, other: &Self) -> Ordering{
            self.as_str().cmp(other.as_str())
        }
    }
    impl<C: Cfg> Debug for typ<C>{
        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error>{
            <str as Debug>::fmt(self.as_str(),f)
        }   
    }
    impl<C: Cfg> Display for typ<C>{
        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error>{
            <str as Display>::fmt(self.as_str(),f)
        }   
    }
};

impl<C: Cfg> IdentRef<C> {
    pub fn as_str<'a>(&'a self) -> &'a str{
        self
    }
    pub fn parse<'a>(a: &'a str) -> Option<&'a Self> {
        if a.chars().all(|k| C::valid(k)) {
            Some(unsafe { core::mem::transmute(a) })
        } else {
            None
        }
    }
    pub fn demangle<'a>(&'a self) -> Option<Cow<'a, str>> {
        let mut ch = vec![];
        let a = self.1.split_once(C::EMBED);
        let Some((a, mut x)) = a else {
            return Some(Cow::Borrowed(&self.1));
        };
        ch.extend(a.chars());
        loop {
            let b;
            let c;
            (x, b) = my_usize(x).ok()?;
            x = x.strip_prefix(C::SEP)?;
            (x, c) = my_u32(x).ok()?;
            ch.insert(b, char::from_u32(c)?);
            x = match x.strip_prefix(C::EMBED) {
                None => return Some(Cow::Owned(ch.into_iter().collect())),
                Some(y) => y,
            }
        }
    }
}
impl<C: Cfg> Ident<C> {
    pub fn parse(a: String) -> Option<Self> {
        if a.chars().all(|k| C::valid(k)) {
            Some(Self(a, PhantomData))
        } else {
            None
        }
    }
    pub fn mangle(a: &str) -> Self {
        let mut v = vec![];
        let mut x = a
            .chars()
            .enumerate()
            .filter(|(i, k)| {
                if C::valid(*k) && C::EMBED.chars().all(|e| e != *k) {
                    return true;
                };
                v.push((*i, *k));
                return false;
            })
            .map(|a| a.1)
            .collect::<String>();
        for (i, v) in v {
            x.extend(format!("{}{i}{}{}", C::EMBED, C::SEP, v as u32).chars());
        }
        return Self(x, PhantomData);
    }
}
impl<C: Cfg> ToOwned for IdentRef<C> {
    type Owned = Ident<C>;

    fn to_owned(&self) -> Self::Owned {
        Ident(self.1.to_owned(), PhantomData)
    }
}
impl<C: Cfg> Borrow<IdentRef<C>> for Ident<C> {
    fn borrow(&self) -> &IdentRef<C> {
        &**self
    }
}

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

#[cfg(test)]
mod tests {
    use alloc::string::String;

    use crate::{CCfg, Ident, IdentRef};

    quickcheck! {
        fn mangle_works(a: String) -> bool{
            return Ident::<CCfg>::mangle(&a).demangle().map(|a|a.into()) == Some(a);
        }
    }
}