basic api calling interface

This commit is contained in:
pointer-to-bios 2024-09-23 12:57:16 +08:00
commit 1253129403
3 changed files with 128 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

10
Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "nonx-api"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
nonx = { path = "../nonx" }

117
src/lib.rs Normal file
View File

@ -0,0 +1,117 @@
extern crate alloc;
use alloc::{string::ToString, vec::Vec};
use proc_macro::{token_stream::IntoIter, Delimiter, Group, TokenStream, TokenTree};
fn insert_stream_at(ident: &str, stream: TokenStream, rhs: TokenStream) -> TokenStream {
let mut res = TokenStream::new();
for tree in stream.into_iter() {
if let TokenTree::Ident(i) = &tree {
if i.to_string() == ident {
res.extend(rhs.clone());
} else {
res.extend([TokenTree::Ident(i.clone())]);
}
} else if let TokenTree::Group(g) = &tree {
res.extend([TokenTree::Group(Group::new(
g.delimiter(),
insert_stream_at(ident, g.stream(), rhs.clone()),
))]);
} else {
res.extend([tree]);
}
}
res
}
#[proc_macro]
pub fn nonx_api(input: TokenStream) -> TokenStream {
if !nonx::utils::api_map_inited() {
nonx::utils::api_remap();
}
let medium = "{
use crate::plugin::api_bus::APIBus;
(*((*APIBus::get()).api(__api_name) as *mut fn(__api_arguments) -> __api_return))(__args)
}"
.parse::<TokenStream>()
.unwrap();
let mut input_iter = input.into_iter();
let api_name = gen_api_name(&mut input_iter);
let api_path = gen_api_path(&api_name);
let api_name_str_tokenstream = gen_api_name_str_tokenstream(&api_name);
let args = gen_args(&mut input_iter);
let medium = insert_stream_at("__api_name", medium, api_name_str_tokenstream);
let medium = insert_stream_at(
"__api_arguments",
medium,
nonx::utils::api_map_get(&api_path).args.parse().unwrap(),
);
let medium = insert_stream_at(
"__api_return",
medium,
nonx::utils::api_map_get(&api_path).rets.parse().unwrap(),
);
let medium = insert_stream_at("__args", medium, args);
medium
}
fn gen_args(input_iter: &mut IntoIter) -> TokenStream {
let mut res = TokenStream::new();
while let Some(ref t) = input_iter.next() {
res.extend([t.clone()]);
}
res
}
fn gen_api_name_str_tokenstream(api_name: &TokenStream) -> TokenStream {
let mut res = "stringify!".parse::<TokenStream>().unwrap();
res.extend([TokenTree::Group(Group::new(
Delimiter::Parenthesis,
api_name.clone(),
))]);
res
}
fn gen_api_name(input_iter: &mut IntoIter) -> TokenStream {
let mut res = TokenStream::new();
while let Some(ref t) = input_iter.next() {
if let TokenTree::Punct(p) = t {
if p.as_char() == ',' {
break;
}
}
res.extend([t.clone()]);
}
res
}
fn gen_api_path(api_name: &TokenStream) -> Vec<String> {
let mut res = Vec::new();
let mut single = false;
for t in api_name.clone() {
match t {
TokenTree::Group(_) => panic!("Unexpected token, api path expected."),
TokenTree::Ident(i) => {
if single {
panic!("Path spliter \'::\' expected, only single \':\'.");
}
res.push(i.to_string());
}
TokenTree::Punct(p) => {
if p.as_char() != ':' {
panic!("Unexpected token \'{}\' in api path.", p.as_char())
}
if !single {
single = true;
} else {
single = false
}
}
TokenTree::Literal(_) => panic!("Unexpected token, api path expected."),
}
}
if res.len() != 3 {
panic!("Api path's depth must be 3.");
}
res
}