1#![deny(unsafe_code)]
4
5#[cfg(feature = "rpc")]
6pub mod rpc;
7
8mod build_ins;
9
10#[cfg(debug_assertions)]
11pub mod docs;
12
13use std::collections::BTreeMap;
14
15pub use build_ins::*;
16
17pub trait ZodType {
18 fn schema() -> String;
19 fn type_def() -> TsTypeDef;
20
21 fn docs() -> Option<&'static str> {
22 None
23 }
24
25 fn inline() -> InlinedType {
26 InlinedType::Literal(Self::type_def().to_string())
27 }
28}
29
30pub enum InlinedType {
31 Literal(String),
32 Ref {
33 ns_name: &'static str,
34 name: &'static str,
35 },
36}
37
38impl std::fmt::Display for InlinedType {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 match self {
41 Self::Literal(inner) => write!(f, "{}", inner),
42 Self::Ref { ns_name, name } => {
43 write!(f, "{}.{}", ns_name, name)
44 }
45 }
46 }
47}
48
49pub trait Namespace {
50 const NAME: &'static str;
51
52 fn docs() -> Option<&'static str> {
53 None
54 }
55
56 #[cfg(feature = "inventory")]
57 fn members() -> Vec<&'static NamespaceMemberDefinition> {
58 let members = inventory::iter::<NamespaceMemberDefinition>()
59 .filter(|namespace| namespace.ns_name == Self::NAME);
60
61 members.collect()
62 }
63}
64
65type RuntimeValue<T> = &'static (dyn Fn() -> T + Sync);
66
67pub struct NamespaceMemberDefinition {
68 ns_name: &'static str,
69 name: &'static str,
70 schema: RuntimeValue<String>,
71 type_def: RuntimeValue<TsTypeDef>,
72}
73
74impl NamespaceMemberDefinition {
75 #[doc(hidden)]
76 pub const fn new_for<T: ZodType + 'static>(ns_name: &'static str, name: &'static str) -> Self {
77 Self {
78 ns_name,
79 name,
80 schema: &<T as ZodType>::schema,
81 type_def: &<T as ZodType>::type_def,
82 }
83 }
84
85 pub fn namespace(&self) -> &'static str {
86 self.ns_name
87 }
88 pub fn name(&self) -> &'static str {
89 self.name
90 }
91
92 pub fn schema(&self) -> String {
93 (self.schema)()
94 }
95
96 pub fn type_def(&self) -> TsTypeDef {
97 (self.type_def)()
98 }
99
100 pub fn collect() -> BTreeMap<&'static str, Vec<&'static NamespaceMemberDefinition>> {
101 let mut out = BTreeMap::<&'static str, Vec<&'static NamespaceMemberDefinition>>::default();
102 for def in inventory::iter::<NamespaceMemberDefinition>() {
103 out.entry(def.namespace()).or_default().push(def);
104 }
105 out
106 }
107}
108
109#[derive(Debug, Clone, PartialEq)]
110pub enum TsTypeDef {
111 Interface(String),
112 Type(String),
113}
114
115impl std::ops::Deref for TsTypeDef {
116 type Target = String;
117
118 fn deref(&self) -> &Self::Target {
119 match self {
120 Self::Type(inner) => inner,
121 Self::Interface(inner) => inner,
122 }
123 }
124}
125
126impl std::fmt::Display for TsTypeDef {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 match self {
129 TsTypeDef::Interface(s) => write!(f, "{s}"),
130 TsTypeDef::Type(s) => write!(f, "{s}"),
131 }
132 }
133}
134
135impl std::cmp::PartialEq<&str> for TsTypeDef {
136 fn eq(&self, other: &&str) -> bool {
137 let s: &str = self;
138 (&s).eq(other)
139 }
140}
141
142impl std::cmp::PartialEq<str> for TsTypeDef {
143 fn eq(&self, other: &str) -> bool {
144 let s: &str = self;
145 s.eq(other)
146 }
147}
148
149impl std::cmp::PartialEq<String> for TsTypeDef {
150 fn eq(&self, other: &String) -> bool {
151 self.eq(other.as_str())
152 }
153}
154
155inventory::collect!(NamespaceMemberDefinition);
156
157pub trait TypeRegister<T> {}