pidl_rust/
lib.rs

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, &params[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, &params[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}