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