From 1253129403955045976dca216f268a66e0a4d5f1 Mon Sep 17 00:00:00 2001 From: pointer-to-bios Date: Mon, 23 Sep 2024 12:57:16 +0800 Subject: [PATCH] basic api calling interface --- .gitignore | 1 + Cargo.toml | 10 +++++ src/lib.rs | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e7cf6d0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "nonx-api" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +nonx = { path = "../nonx" } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..138adc5 --- /dev/null +++ b/src/lib.rs @@ -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::() + .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::().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 { + 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 +}