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}