basic api calling interface
This commit is contained in:
commit
1253129403
|
@ -0,0 +1 @@
|
|||
/target
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "nonx-api"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
nonx = { path = "../nonx" }
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue