1use pidl_core::{Arg, Interface, Sig};
2use proc_macro2::{Span, TokenStream};
3use quasiquote::quasiquote;
4use quote::{format_ident, quote};
5pub struct Opts {
6 pub root: TokenStream,
7 pub rpc: Option<RpcOpts>,
8}
9pub struct RpcOpts {}
10pub fn ty(opts: &Opts, i: &Interface, tyx: &Arg, unsync: bool) -> syn::Result<TokenStream> {
11 match tyx {
12 Arg::Prim { name, ann, params } => match name.as_str() {
13 "option" => {
14 let p = ty(opts, i, ¶ms[0], unsync)?;
15 return Ok(quasiquote!(Option<#p>));
16 }
17 _ => name.parse().map_err(|e| {
18 syn::Error::new(
19 Span::call_site(),
20 format!("invalid primitive (rust parsing: {e})"),
21 )
22 }),
23 },
24 Arg::Resource { ty, ann } => {
25 let id = match ty {
26 pidl_core::ResTy::Of(a) => *a,
27 pidl_core::ResTy::This => i.rid(),
28 };
29 let id = hex::encode(id);
30 let name = format_ident!("{}R{id}", if unsync { "Async" } else { "" });
31 Ok(quasiquote! {
32 impl #name<C>
33 })
34 }
35 }
36}
37pub fn rpc_ty(opts: &Opts,rpc: &RpcOpts, i: &Interface, tyx: &Arg) -> syn::Result<TokenStream>{
38 match tyx{
39 Arg::Prim { name, ann, params } => match name.as_str(){
40 "option" => {
41 let p = rpc_ty(opts,rpc, i, ¶ms[0])?;
42 return Ok(quasiquote!(Option<#p>));
43 }
44 _ => name.parse().map_err(|e| {
45 syn::Error::new(
46 Span::call_site(),
47 format!("invalid primitive (rust parsing: {e})"),
48 )
49 }),
50 },
51 Arg::Resource { ty, ann } => {
52 let id = match ty {
53 pidl_core::ResTy::Of(a) => *a,
54 pidl_core::ResTy::This => i.rid(),
55 };
56 let id = hex::encode(id);
57 Ok(quasiquote!(#{format_ident!("R{id}RpcId")}))
58 },
59 }
60}
61pub fn meth(
62 opts: &Opts,
63 i: &Interface,
64 a: &str,
65 b: &Sig,
66 unsync: bool,
67) -> syn::Result<TokenStream> {
68 let ai = format_ident!("{a}");
69 let params = b
70 .params
71 .iter()
72 .map(|a| ty(opts, i, a, unsync))
73 .collect::<syn::Result<Vec<_>>>()?
74 .into_iter()
75 .enumerate()
76 .map(|(a, b)| {
77 quasiquote! {
78 #{format_ident!("p{a}")}: #b
79 }
80 });
81 let results = b
82 .rets
83 .iter()
84 .map(|a| ty(opts, i, a, unsync))
85 .collect::<syn::Result<Vec<_>>>()?;
86 Ok(quasiquote! {
87 fn #ai(&mut self,ctx: C::Of<'_>, #(#params),*) -> #{
88 let mut v = quote!{
89 (#(#results),*)
90 };
91 if unsync{
92 v = quote! {
93 impl Future<Output = #v> + Send
94 }
95 }
96 v
97 }
98 })
99}
100pub fn rpc_meth(
101 opts: &Opts,
102 rpc: &RpcOpts,
103 i: &Interface,
104 a: &str,
105 b: &Sig,
106 ty: RpcType,
107) -> syn::Result<TokenStream> {
108 let x = match ty {
109 RpcType::Request => &b.params,
110 RpcType::Response => &b.rets,
111 };
112 Ok(quasiquote! {
113 #{format_ident!("{a}")}(#{
114 let fields = x.iter().map(|a|rpc_ty(opts,rpc,i,a)).collect::<syn::Result<Vec<_>>>()?;
115 quote!{#(#fields),*}
116 })
117 })
118}
119pub enum RpcType {
120 Request,
121 Response,
122}
123pub fn rustify(opts: &Opts, i: &Interface) -> syn::Result<TokenStream> {
124 fn inner(opts: &Opts, i: &Interface, unsync: bool) -> syn::Result<TokenStream> {
125 let name = format_ident!("{}R{}", if unsync { "Async" } else { "" }, i.rid_str());
126
127 let methods = i.methods.iter().map(|(a, b)| meth(opts, i, a, b, unsync));
128 let methods = methods.collect::<syn::Result<Vec<_>>>()?;
129
130 Ok(quasiquote! {
131 pub trait #name<C: #{&opts.root}::Budding>: 'static{
132 #(#methods)*
133 }
134 })
135 }
136 fn rpc(opts: &Opts, i: &Interface) -> syn::Result<TokenStream> {
137 let Some(rpc) = opts.rpc.as_ref() else {
138 return Ok(quote! {});
139 };
140 Ok(quasiquote! {
141 pub struct #{format_ident!("R{}RpcId",i.rid_str())}{
142 pub uuuid: [u8;32]
143 }
144 pub enum #{format_ident!("R{}RpcReq",i.rid_str())}{
145 #{
146 let methods = i.methods.iter().map(|(a,b)|rpc_meth(opts,rpc,i,a,b,RpcType::Request)).collect::<syn::Result<Vec<_>>>()?;
147 quote!{
148 #(#methods),*
149 }
150 }
151 }
152 pub enum #{format_ident!("R{}RpcResp",i.rid_str())}{
153 #{
154 let methods = i.methods.iter().map(|(a,b)|rpc_meth(opts,rpc,i,a,b,RpcType::Response)).collect::<syn::Result<Vec<_>>>()?;
155 quote!{
156 #(#methods),*
157 }
158 }
159 }
160 })
161 }
162 Ok(quasiquote! {
163 #{inner(opts,i,true)?}
164 #{inner(opts,i,false)?}
165 #{rpc(opts,i)?}
166 })
167}