mirror of
https://github.com/Start9Labs/rpc-toolkit.git
synced 2026-03-26 02:11:56 +00:00
wip: metadata
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -1745,9 +1745,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "visit-rs"
|
name = "visit-rs"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbd4baf031bf580bc7ba411f4625a304909c975bf3d3e8d9c43ed88d23be1b8e"
|
checksum = "f89c27f644c3e4ce302bc7bce5144e295405d569784e5f4921271404e600cecf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream",
|
"async-stream",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -1757,9 +1757,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "visit-rs-derive"
|
name = "visit-rs-derive"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2336cc680cfb205620939f0fa62348a4b6da37d1e727670f3d7d77aebc50b611"
|
checksum = "2a3bfb04fd13da4fc8df24709b7a0949667f43c63691d9fecddf1d3be8af5099"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
authors = ["Aiden McClelland <me@drbonez.dev>"]
|
||||||
description = "A toolkit for creating JSON-RPC 2.0 servers with automatic cli bindings"
|
description = "A toolkit for creating JSON-RPC 2.0 servers with automatic cli bindings"
|
||||||
documentation = "https://docs.rs/rpc-toolkit"
|
documentation = "https://docs.rs/rpc-toolkit"
|
||||||
edition = "2018"
|
edition = "2024"
|
||||||
keywords = ["cli", "json", "rpc"]
|
keywords = ["cli", "json", "rpc"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "rpc-toolkit"
|
name = "rpc-toolkit"
|
||||||
@@ -39,5 +39,5 @@ thiserror = "2.0"
|
|||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tokio-stream = { version = "0.1", features = ["io-util", "net"] }
|
tokio-stream = { version = "0.1", features = ["io-util", "net"] }
|
||||||
url = "2"
|
url = "2"
|
||||||
visit-rs = { version = "0.1.8", optional = true }
|
visit-rs = { version = "0.1.9", optional = true }
|
||||||
yajrc = "0.1"
|
yajrc = "0.1"
|
||||||
|
|||||||
@@ -50,11 +50,11 @@ impl<Context: crate::Context> Server<Context> {
|
|||||||
&self,
|
&self,
|
||||||
method: &str,
|
method: &str,
|
||||||
params: Value,
|
params: Value,
|
||||||
) -> impl Future<Output = Result<Value, RpcError>> + Send + 'static {
|
) -> impl Future<Output = Result<Value, RpcError>> + Send + 'static + use<Context> {
|
||||||
let (make_ctx, root_handler, method) = (
|
let (make_ctx, root_handler, method) = (
|
||||||
self.make_ctx.clone(),
|
self.make_ctx.clone(),
|
||||||
self.root_handler.clone(),
|
self.root_handler.clone(),
|
||||||
self.root_handler.method_from_dots(method),
|
self.root_handler.method_from_dots(method.as_ref()),
|
||||||
);
|
);
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
@@ -74,14 +74,11 @@ impl<Context: crate::Context> Server<Context> {
|
|||||||
&self,
|
&self,
|
||||||
RpcRequest { id, method, params }: RpcRequest,
|
RpcRequest { id, method, params }: RpcRequest,
|
||||||
) -> impl Future<Output = RpcResponse> + Send + 'static {
|
) -> impl Future<Output = RpcResponse> + Send + 'static {
|
||||||
let handle = (|| Ok::<_, RpcError>(self.handle_command(method.as_str(), params)))();
|
let handle = self.handle_command(method.as_str(), params);
|
||||||
async move {
|
async move {
|
||||||
RpcResponse {
|
RpcResponse {
|
||||||
id,
|
id,
|
||||||
result: match handle {
|
result: handle.await,
|
||||||
Ok(handle) => handle.await,
|
|
||||||
Err(e) => Err(e),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
153
src/ts.rs
153
src/ts.rs
@@ -6,7 +6,11 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use imbl_value::imbl::{OrdMap, Vector};
|
use imbl_value::imbl::{OrdMap, Vector};
|
||||||
use imbl_value::InternedString;
|
use imbl_value::InternedString;
|
||||||
use visit_rs::{Named, Static, Visit, VisitFieldsStaticNamed, Visitor};
|
use visit_rs::{
|
||||||
|
Named, Static, StructInfo, StructInfoData, Variant, Visit, VisitFieldsStatic,
|
||||||
|
VisitFieldsStaticNamed, VisitVariantFieldsStatic, VisitVariantFieldsStaticNamed,
|
||||||
|
VisitVariantsStatic, Visitor,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{Adapter, FromFn, FromFnAsync, FromFnAsyncLocal, HandlerTypes, ParentHandler};
|
use crate::{Adapter, FromFn, FromFnAsync, FromFnAsyncLocal, HandlerTypes, ParentHandler};
|
||||||
|
|
||||||
@@ -315,6 +319,96 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SerdeTag {
|
||||||
|
pub tag: Option<syn::LitStr>,
|
||||||
|
pub contents: Option<syn::LitStr>,
|
||||||
|
}
|
||||||
|
impl SerdeTag {
|
||||||
|
pub fn apply_meta(this: &mut Option<Self>, meta: &syn::Meta) {
|
||||||
|
if meta.path().is_ident("untagged") {
|
||||||
|
*this = None;
|
||||||
|
} else if meta.path().is_ident("tag") {
|
||||||
|
if let Some(tag) = meta.require_name_value().ok() {
|
||||||
|
if let syn::Expr::Lit(syn::ExprLit {
|
||||||
|
lit: syn::Lit::Str(tag),
|
||||||
|
..
|
||||||
|
}) = &tag.value
|
||||||
|
{
|
||||||
|
this.get_or_insert_default().tag = Some(tag.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if meta.path().is_ident("contents") {
|
||||||
|
if let Some(tag) = meta.require_name_value().ok() {
|
||||||
|
if let syn::Expr::Lit(syn::ExprLit {
|
||||||
|
lit: syn::Lit::Str(tag),
|
||||||
|
..
|
||||||
|
}) = &tag.value
|
||||||
|
{
|
||||||
|
this.get_or_insert_default().contents = Some(tag.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_metas(metas: &[syn::Meta]) -> Option<Self> {
|
||||||
|
let mut res = Some(SerdeTag::default());
|
||||||
|
for meta in metas.into_iter().filter_map(|m| m.require_list().ok()) {
|
||||||
|
if meta.path.is_ident("serde") {
|
||||||
|
syn::parse2::<syn::Meta>(meta.tokens.clone())
|
||||||
|
.ok()
|
||||||
|
.as_ref()
|
||||||
|
.map(|meta| Self::apply_meta(&mut res, meta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for meta in metas.into_iter().filter_map(|m| m.require_list().ok()) {
|
||||||
|
if meta.path.is_ident("visit") {
|
||||||
|
if let Some(meta) = syn::parse2::<syn::Meta>(meta.tokens.clone())
|
||||||
|
.ok()
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|m| m.require_list().ok())
|
||||||
|
{
|
||||||
|
if meta.path.is_ident("ts") {
|
||||||
|
syn::parse2::<syn::Meta>(meta.tokens.clone())
|
||||||
|
.ok()
|
||||||
|
.as_ref()
|
||||||
|
.map(|meta| Self::apply_meta(&mut res, meta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Visit<TSVisitor> for Variant<'a, Static<T>>
|
||||||
|
where
|
||||||
|
T: TS,
|
||||||
|
T: VisitVariantFieldsStaticNamed<TSVisitor> + VisitVariantFieldsStatic<TSVisitor>,
|
||||||
|
{
|
||||||
|
fn visit(&self, visitor: &mut TSVisitor) -> <TSVisitor as Visitor>::Result {
|
||||||
|
// TODO: handle serde tagging
|
||||||
|
let tag = Some(SerdeTag {
|
||||||
|
tag: None,
|
||||||
|
contents: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
if T::DATA.variant_count > 1 {
|
||||||
|
visitor.ts.push('|');
|
||||||
|
}
|
||||||
|
visit_struct_impl(
|
||||||
|
&self.info,
|
||||||
|
|name, visitor| {
|
||||||
|
if name {
|
||||||
|
T::visit_variant_fields_static_named(&self.info, visitor).for_each(drop);
|
||||||
|
} else {
|
||||||
|
T::visit_variant_fields_static(&self.info, visitor).for_each(drop);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
visitor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct LiteralTS(Cow<'static, str>);
|
pub struct LiteralTS(Cow<'static, str>);
|
||||||
impl Visit<TSVisitor> for LiteralTS {
|
impl Visit<TSVisitor> for LiteralTS {
|
||||||
fn visit(&self, visitor: &mut TSVisitor) -> <TSVisitor as Visitor>::Result {
|
fn visit(&self, visitor: &mut TSVisitor) -> <TSVisitor as Visitor>::Result {
|
||||||
@@ -347,21 +441,43 @@ impl_ts!(u64,u128,i64,i128 => "bigint");
|
|||||||
impl_ts!(Unknown,imbl_value::Value,serde_json::Value,serde_cbor::Value => "unknown");
|
impl_ts!(Unknown,imbl_value::Value,serde_json::Value,serde_cbor::Value => "unknown");
|
||||||
impl_ts!(Never => "never");
|
impl_ts!(Never => "never");
|
||||||
|
|
||||||
|
fn visit_struct_impl(
|
||||||
|
info: &StructInfoData,
|
||||||
|
fields: impl FnOnce(bool, &mut TSVisitor),
|
||||||
|
visitor: &mut TSVisitor,
|
||||||
|
) {
|
||||||
|
if !info.named_fields && info.field_count == 1 {
|
||||||
|
fields(false, visitor)
|
||||||
|
} else {
|
||||||
|
if info.named_fields {
|
||||||
|
visitor.ts.push_str("{");
|
||||||
|
} else {
|
||||||
|
visitor.ts.push_str("[");
|
||||||
|
}
|
||||||
|
fields(true, visitor);
|
||||||
|
if info.named_fields {
|
||||||
|
visitor.ts.push_str("}");
|
||||||
|
} else {
|
||||||
|
visitor.ts.push_str("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn visit_struct<T>(visitor: &mut TSVisitor)
|
pub fn visit_struct<T>(visitor: &mut TSVisitor)
|
||||||
where
|
where
|
||||||
T: VisitFieldsStaticNamed<TSVisitor>,
|
T: VisitFieldsStaticNamed<TSVisitor> + VisitFieldsStatic<TSVisitor>,
|
||||||
{
|
{
|
||||||
if T::NAMED_FIELDS {
|
visit_struct_impl(
|
||||||
visitor.ts.push_str("{");
|
&T::DATA,
|
||||||
} else {
|
|named, visitor| {
|
||||||
visitor.ts.push_str("[");
|
if named {
|
||||||
}
|
T::visit_fields_static_named(visitor).for_each(drop);
|
||||||
T::visit_fields_static_named(visitor).for_each(drop);
|
} else {
|
||||||
if T::NAMED_FIELDS {
|
T::visit_fields_static(visitor).for_each(drop);
|
||||||
visitor.ts.push_str("}");
|
}
|
||||||
} else {
|
},
|
||||||
visitor.ts.push_str("]");
|
visitor,
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@@ -376,6 +492,17 @@ macro_rules! impl_ts_struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn visit_enum<T>(visitor: &mut TSVisitor)
|
||||||
|
where
|
||||||
|
T: VisitVariantsStatic<TSVisitor>,
|
||||||
|
{
|
||||||
|
if T::DATA.variant_count == 0 {
|
||||||
|
visitor.append_type::<Never>()
|
||||||
|
} else {
|
||||||
|
T::visit_variants_static(visitor).for_each(drop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn visit_map<K, V>(visitor: &mut TSVisitor)
|
pub fn visit_map<K, V>(visitor: &mut TSVisitor)
|
||||||
where
|
where
|
||||||
K: TS,
|
K: TS,
|
||||||
|
|||||||
Reference in New Issue
Block a user