trust_ident/
lib.rs

1#![no_std]
2use core::{borrow::Borrow, cmp::Ordering, fmt::{Debug, Display, Formatter}, marker::PhantomData, ops::Deref};
3
4use duplicate::duplicate_item;
5use nom::{
6    character::complete::digit1,
7    combinator::{map_res, recognize},
8    IResult, Parser,
9};
10#[macro_use]
11extern crate alloc;
12use alloc::vec::Vec;
13use alloc::{
14    borrow::{Cow, ToOwned},
15    string::String,
16};
17fn my_usize(input: &str) -> IResult<&str, usize> {
18    map_res(recognize(digit1), str::parse).parse(input)
19}
20fn my_u32(input: &str) -> IResult<&str, u32> {
21    map_res(recognize(digit1), str::parse).parse(input)
22}
23
24pub trait Cfg {
25    fn valid(ch: char) -> bool;
26    const EMBED: &'static str;
27    const SEP: &'static str;
28}
29pub struct CCfg {}
30impl Cfg for CCfg {
31    fn valid(k: char) -> bool {
32        k.is_ascii_alphanumeric() || k == '$'
33    }
34
35    const EMBED: &'static str = "$";
36
37    const SEP: &'static str = "c";
38}
39
40#[repr(transparent)]
41pub struct Ident<C: Cfg>(String, PhantomData<fn(&C) -> &C>);
42impl<C: Cfg> Clone for Ident<C>{
43    fn clone(&self) -> Self {
44        Self(self.0.clone(), self.1.clone())
45    }
46}
47#[repr(transparent)]
48pub struct IdentRef<C: Cfg>(PhantomData<fn(&C) -> &C>, str);
49impl<C: Cfg> Deref for Ident<C> {
50    type Target = IdentRef<C>;
51
52    fn deref(&self) -> &Self::Target {
53        unsafe { core::mem::transmute(self.0.as_str()) }
54    }
55}
56impl<C: Cfg> Deref for IdentRef<C> {
57    type Target = str;
58
59    fn deref(&self) -> &Self::Target {
60        &self.1
61    }
62}
63#[duplicate_item(
64    typ;
65    [Ident];
66    [IdentRef];
67)]
68const _: () = {
69    impl<C: Cfg> PartialEq for typ<C>{
70        fn eq(&self, other: &Self) -> bool{
71            return self.as_str() == other.as_str();
72        }
73    }
74    impl<C: Cfg> Eq for typ<C>{
75
76    }
77    impl<C: Cfg> PartialOrd for typ<C>{
78        fn partial_cmp(&self, other: &Self) -> Option<Ordering>{
79            self.as_str().partial_cmp(other.as_str())
80        }
81    }
82    impl<C: Cfg> Ord for typ<C>{
83        fn cmp(&self, other: &Self) -> Ordering{
84            self.as_str().cmp(other.as_str())
85        }
86    }
87    impl<C: Cfg> Debug for typ<C>{
88        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error>{
89            <str as Debug>::fmt(self.as_str(),f)
90        }   
91    }
92    impl<C: Cfg> Display for typ<C>{
93        fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error>{
94            <str as Display>::fmt(self.as_str(),f)
95        }   
96    }
97};
98
99impl<C: Cfg> IdentRef<C> {
100    pub fn as_str<'a>(&'a self) -> &'a str{
101        self
102    }
103    pub fn parse<'a>(a: &'a str) -> Option<&'a Self> {
104        if a.chars().all(|k| C::valid(k)) {
105            Some(unsafe { core::mem::transmute(a) })
106        } else {
107            None
108        }
109    }
110    pub fn demangle<'a>(&'a self) -> Option<Cow<'a, str>> {
111        let mut ch = vec![];
112        let a = self.1.split_once(C::EMBED);
113        let Some((a, mut x)) = a else {
114            return Some(Cow::Borrowed(&self.1));
115        };
116        ch.extend(a.chars());
117        loop {
118            let b;
119            let c;
120            (x, b) = my_usize(x).ok()?;
121            x = x.strip_prefix(C::SEP)?;
122            (x, c) = my_u32(x).ok()?;
123            ch.insert(b, char::from_u32(c)?);
124            x = match x.strip_prefix(C::EMBED) {
125                None => return Some(Cow::Owned(ch.into_iter().collect())),
126                Some(y) => y,
127            }
128        }
129    }
130}
131impl<C: Cfg> Ident<C> {
132    pub fn parse(a: String) -> Option<Self> {
133        if a.chars().all(|k| C::valid(k)) {
134            Some(Self(a, PhantomData))
135        } else {
136            None
137        }
138    }
139    pub fn mangle(a: &str) -> Self {
140        let mut v = vec![];
141        let mut x = a
142            .chars()
143            .enumerate()
144            .filter(|(i, k)| {
145                if C::valid(*k) && C::EMBED.chars().all(|e| e != *k) {
146                    return true;
147                };
148                v.push((*i, *k));
149                return false;
150            })
151            .map(|a| a.1)
152            .collect::<String>();
153        for (i, v) in v {
154            x.extend(format!("{}{i}{}{}", C::EMBED, C::SEP, v as u32).chars());
155        }
156        return Self(x, PhantomData);
157    }
158}
159impl<C: Cfg> ToOwned for IdentRef<C> {
160    type Owned = Ident<C>;
161
162    fn to_owned(&self) -> Self::Owned {
163        Ident(self.1.to_owned(), PhantomData)
164    }
165}
166impl<C: Cfg> Borrow<IdentRef<C>> for Ident<C> {
167    fn borrow(&self) -> &IdentRef<C> {
168        &**self
169    }
170}
171
172#[cfg(test)]
173#[macro_use]
174extern crate quickcheck;
175
176#[cfg(test)]
177mod tests {
178    use alloc::string::String;
179
180    use crate::{CCfg, Ident, IdentRef};
181
182    quickcheck! {
183        fn mangle_works(a: String) -> bool{
184            return Ident::<CCfg>::mangle(&a).demangle().map(|a|a.into()) == Some(a);
185        }
186    }
187}