zod_core/rpc/
server.rs

1use std::collections::{BTreeMap, HashMap};
2use std::fmt::Write;
3
4use crate::NamespaceMemberDefinition;
5
6use crate::{
7    rpc::codegen::{self, RpcMember},
8    rpc::Request,
9    rpc::ResponseSender,
10};
11
12pub type StreamHandle = tokio::task::JoinHandle<()>;
13
14#[derive(Debug, Default)]
15pub struct SubscriberMap {
16    inner: HashMap<usize, StreamHandle>,
17}
18
19impl std::ops::Deref for SubscriberMap {
20    type Target = HashMap<usize, StreamHandle>;
21
22    fn deref(&self) -> &Self::Target {
23        &self.inner
24    }
25}
26
27impl std::ops::DerefMut for SubscriberMap {
28    fn deref_mut(&mut self) -> &mut Self::Target {
29        &mut self.inner
30    }
31}
32
33impl Drop for SubscriberMap {
34    fn drop(&mut self) {
35        for (_, jh) in self.inner.drain() {
36            jh.abort();
37        }
38    }
39}
40
41#[derive(Clone, Debug, Default)]
42pub struct CodegenOptions {
43    prefix_schema: String,
44    suffix_schema: String,
45
46    prefix_type: String,
47    suffix_type: String,
48
49    prefix_interface: String,
50    suffix_interface: String,
51}
52
53#[async_trait::async_trait]
54pub trait Backend {
55    const NS_NAMES: &'static [&'static str];
56
57    fn rpc_members() -> HashMap<&'static str, Vec<String>> {
58        let mut out = HashMap::<&'static str, Vec<String>>::new();
59        let members = inventory::iter::<RpcMember>()
60            .filter(|member| Self::NS_NAMES.contains(&member.ns_name()));
61
62        for member in members {
63            out.entry(member.ns_name()).or_default().push(member.decl());
64        }
65        out
66    }
67
68    fn zod_namespaces() -> HashMap<&'static str, Vec<&'static NamespaceMemberDefinition>> {
69        let mut out = HashMap::<&'static str, Vec<&'static NamespaceMemberDefinition>>::new();
70        let members = inventory::iter::<NamespaceMemberDefinition>()
71            .filter(|member| Self::NS_NAMES.contains(&member.namespace()));
72
73        for member in members {
74            out.entry(member.namespace()).or_default().push(member);
75        }
76        out
77    }
78    fn generate<T>() -> String
79    where
80        T: codegen::ClientCodegen,
81    {
82        Self::generate_with_options::<T>(Default::default())
83    }
84
85    fn generate_with_options<T>(options: CodegenOptions) -> String
86    where
87        T: codegen::ClientCodegen,
88    {
89        let rpc_records = inventory::iter::<RpcMember>()
90            .filter(|member| Self::NS_NAMES.contains(&member.ns_name()))
91            .map(|m| (m.ns_name(), m.decl()));
92
93        let mut records: BTreeMap<&'static str, String> =
94            crate::NamespaceMemberDefinition::collect()
95                .into_iter()
96                .filter(|(ns, _)| Self::NS_NAMES.contains(ns))
97                .map(|(ns, defs)| {
98                    (
99                        ns,
100                        defs.into_iter()
101                            .map(|def| {
102                                let td = match def.type_def() {
103                                    crate::TsTypeDef::Interface(inner) => {
104                                        format!(
105                                            "export interface {}{}{} {}",
106                                            options.prefix_interface,
107                                            def.name(),
108                                            options.suffix_interface,
109                                            inner
110                                        )
111                                    }
112
113                                    crate::TsTypeDef::Type(inner) => {
114                                        format!(
115                                            "export type {}{}{} = {};",
116                                            options.prefix_type,
117                                            def.name(),
118                                            options.suffix_type,
119                                            inner
120                                        )
121                                    }
122                                };
123
124                                format!(
125                                    "export const {}{}{}= {}\n{}\n\n",
126                                    options.prefix_schema,
127                                    def.name(),
128                                    options.suffix_schema,
129                                    def.schema(),
130                                    td
131                                )
132                            })
133                            .collect(),
134                    )
135                })
136                .collect();
137
138        for (name, code) in rpc_records {
139            let s = records.entry(name).or_default();
140            write!(s, "{}", code).unwrap();
141        }
142
143        let mut code = T::get();
144
145        for (ns, ns_code) in records.into_iter() {
146            write!(code, "export namespace {} {{ {} }}", ns, ns_code).expect("write failed");
147        }
148        code
149    }
150
151    async fn handle_request(
152        &mut self,
153        req: Request,
154        res: ResponseSender,
155        subscribers: &mut SubscriberMap,
156    );
157}