initial commit
This commit is contained in:
1
lib/inferium/proc/.gitignore
vendored
Normal file
1
lib/inferium/proc/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
target/
|
7
lib/inferium/proc/Cargo.lock
generated
Normal file
7
lib/inferium/proc/Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "proc"
|
||||
version = "0.1.0"
|
9
lib/inferium/proc/Cargo.toml
Normal file
9
lib/inferium/proc/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "proc"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
175
lib/inferium/proc/src/lib.rs
Normal file
175
lib/inferium/proc/src/lib.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
use proc_macro::{Delimiter, TokenStream, TokenTree};
|
||||
extern crate proc_macro;
|
||||
|
||||
#[proc_macro_derive(AutoimplHkeys)]
|
||||
pub fn autoimpl_hkeys(item: TokenStream) -> TokenStream {
|
||||
let mut iter = item.into_iter();
|
||||
let data = autoimpl_names_get_idents(&mut iter).expect("could not parse the name enum");
|
||||
|
||||
let obj_ident = data.obj_ident;
|
||||
let mut cases_from = String::new();
|
||||
let mut cases_into = String::new();
|
||||
let mut cases_text = String::new();
|
||||
let mut cases_display = String::new();
|
||||
for entry in data.names {
|
||||
let entry_transformed = autoimpl_hkeys_transform(&entry);
|
||||
cases_from.push_str(&format!("{entry_transformed:?} => Self::{entry},\n"));
|
||||
cases_into.push_str(&format!(
|
||||
"{obj_ident}::{entry} => String::from({entry_transformed:?}),\n"
|
||||
));
|
||||
cases_text.push_str(&format!("{obj_ident}::{entry} => b{entry_transformed:?},\n"));
|
||||
cases_display.push_str(
|
||||
&format!("{obj_ident}::{entry} => write!(f, {entry_transformed:?}),")
|
||||
);
|
||||
}
|
||||
|
||||
format!("impl From<&str> for {obj_ident} {{
|
||||
fn from(s: &str) -> Self {{
|
||||
match s.to_lowercase().as_str() {{
|
||||
{cases_from}
|
||||
v => Self::OTHER(v.to_string()),
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
|
||||
impl From<{obj_ident}> for String {{
|
||||
fn from(val: {obj_ident}) -> Self {{
|
||||
match val {{
|
||||
{cases_into}
|
||||
{obj_ident}::OTHER(v) => v.clone(),
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
|
||||
impl {obj_ident} {{
|
||||
pub(crate) fn text(&self) -> &[u8] {{
|
||||
match self {{
|
||||
{cases_text}
|
||||
Self::OTHER(v) => v.as_bytes(),
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
|
||||
impl std::fmt::Display for {obj_ident} {{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {{
|
||||
match self {{
|
||||
{cases_display}
|
||||
Self::OTHER(v) => write!(f, \"{{v}}\"),
|
||||
}}
|
||||
}}
|
||||
}}").parse().expect("could not parse the created autoimpl")
|
||||
}
|
||||
|
||||
#[proc_macro_derive(AutoimplMethods)]
|
||||
pub fn autoimpl_methods(item: TokenStream) -> TokenStream {
|
||||
let mut iter = item.into_iter();
|
||||
let data = autoimpl_names_get_idents(&mut iter).expect("could not parse the name enum");
|
||||
|
||||
let obj_ident = data.obj_ident;
|
||||
let mut cases_from = String::new();
|
||||
let mut cases_into = String::new();
|
||||
let mut cases_text = String::new();
|
||||
for entry in data.names {
|
||||
cases_from.push_str(&format!("{entry:?} => Ok(Self::{entry}),\n"));
|
||||
cases_into.push_str(&format!("{obj_ident}::{entry} => {entry:?},\n"));
|
||||
cases_text.push_str(&format!("{obj_ident}::{entry} => b{entry:?},\n"));
|
||||
}
|
||||
|
||||
format!("impl std::str::FromStr for {obj_ident} {{
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {{
|
||||
match s {{
|
||||
{cases_from}
|
||||
_ => Err(()),
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
|
||||
impl From<{obj_ident}> for &'static str {{
|
||||
fn from(val: {obj_ident}) -> Self {{
|
||||
match val {{
|
||||
{cases_into}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
|
||||
impl {obj_ident} {{
|
||||
pub(crate) fn text(&self) -> &'static [u8] {{
|
||||
match self {{
|
||||
{cases_text}
|
||||
}}
|
||||
}}
|
||||
}}").parse().expect("could not parse the created autoimpl")
|
||||
}
|
||||
|
||||
fn autoimpl_hkeys_transform(name: &str) -> String {
|
||||
name.to_lowercase().replace("_", "-")
|
||||
}
|
||||
|
||||
macro_rules! get_tok {
|
||||
(req $($rest:tt)+) => {
|
||||
get_tok!($($rest)+)?.ok_or(())?
|
||||
};
|
||||
|
||||
($iter:ident == $t:ident $val:literal) => {{
|
||||
get_tok!($t $iter).map(
|
||||
|v| v.map(|v| v.to_string() == $val)
|
||||
).unwrap_or_else(|_| Some(false))
|
||||
}};
|
||||
|
||||
($iter:ident != $t:ident $val:literal) => {
|
||||
get_tok!($t $iter).map(
|
||||
|v| v.map(|v| v.to_string() != $val)
|
||||
).unwrap_or_else(|_| Some(false))
|
||||
};
|
||||
|
||||
($t:ident $iter:ident) => {{
|
||||
match $iter.next() {
|
||||
Some(TokenTree::$t(val)) => Ok(Some(val)),
|
||||
None => Ok(None),
|
||||
_ => Err(()),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
struct NameData {
|
||||
obj_ident: String,
|
||||
names: Vec<String>,
|
||||
}
|
||||
|
||||
fn autoimpl_names_get_idents<I: Iterator<Item = TokenTree>>(
|
||||
iter: &mut I
|
||||
) -> Result<NameData, ()> {
|
||||
while let Some(is_enum_start) = get_tok!(iter == Ident "enum") {
|
||||
if is_enum_start {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let obj_ident = get_tok!(req Ident iter).to_string();
|
||||
let mut iter = {
|
||||
let group = get_tok!(req Group iter);
|
||||
if group.delimiter() != Delimiter::Brace {
|
||||
return Err(());
|
||||
}
|
||||
group.stream().into_iter()
|
||||
};
|
||||
|
||||
let mut names = Vec::new();
|
||||
loop {
|
||||
let Some(name) = get_tok!(Ident iter)? else {
|
||||
break;
|
||||
};
|
||||
if name.to_string() == "OTHER" {
|
||||
break;
|
||||
}
|
||||
names.push(name.to_string());
|
||||
match get_tok!(iter == Punct ",") {
|
||||
Some(true) => {},
|
||||
Some(false) => Err(())?,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(NameData { obj_ident, names })
|
||||
}
|
Reference in New Issue
Block a user