1#![cfg_attr(test, allow(clippy::unwrap_used))]
3
4pub mod build_loader;
5pub mod channel;
6pub mod context;
7pub mod errors;
8pub mod escape;
9pub mod manifest;
10pub mod page;
11pub mod procedure;
12pub mod resolve;
13pub mod server;
14pub mod validation;
15
16pub use build_loader::{
18 BuildOutput, RpcHashMap, load_build, load_build_output, load_i18n_config, load_public_dir,
19 load_rpc_hash_map,
20};
21pub use channel::{ChannelDef, ChannelMeta, IncomingDef, IncomingMeta};
22pub use context::{
23 ContextConfig, ContextFieldDef, RawContextMap, context_has_extracts, context_keys_from_schema,
24 extract_raw_context, parse_cookie_header, resolve_context,
25};
26pub use errors::SeamError;
27pub use escape::ascii_escape_json;
28pub use page::I18nConfig;
29pub use procedure::{
30 BoxFuture, BoxStream, ProcedureDef, ProcedureType, SeamFileHandle, StreamDef, StreamHandlerFn,
31 StreamParams, SubscriptionDef, SubscriptionParams, UploadDef, UploadHandlerFn, map_stream_output,
32};
33pub use resolve::{
34 ResolveData, ResolveStrategy, default_strategies, from_accept_language, from_cookie,
35 from_url_prefix, from_url_query, resolve_chain,
36};
37pub use seam_macros::{SeamType, seam_command, seam_procedure, seam_subscription};
38pub use seam_macros::{seam_stream, seam_upload};
39pub use server::{SeamParts, SeamServer, TransportConfig};
40pub use validation::{
41 CompiledSchema, ValidationDetail, ValidationMode, compile_schema, should_validate,
42 validate_compiled, validate_input,
43};
44
45pub trait SeamType {
48 fn jtd_schema() -> serde_json::Value;
49}
50
51macro_rules! impl_seam_type_primitive {
54 ($rust_ty:ty, $jtd:expr_2021) => {
55 impl SeamType for $rust_ty {
56 fn jtd_schema() -> serde_json::Value {
57 serde_json::json!({ "type": $jtd })
58 }
59 }
60 };
61}
62
63impl_seam_type_primitive!(String, "string");
64impl_seam_type_primitive!(bool, "boolean");
65impl_seam_type_primitive!(i8, "int8");
66impl_seam_type_primitive!(i16, "int16");
67impl_seam_type_primitive!(i32, "int32");
68impl_seam_type_primitive!(u8, "uint8");
69impl_seam_type_primitive!(u16, "uint16");
70impl_seam_type_primitive!(u32, "uint32");
71impl_seam_type_primitive!(f32, "float32");
72impl_seam_type_primitive!(f64, "float64");
73
74impl<T: SeamType> SeamType for Vec<T> {
75 fn jtd_schema() -> serde_json::Value {
76 serde_json::json!({ "elements": T::jtd_schema() })
77 }
78}
79
80impl<T: SeamType> SeamType for Option<T> {
81 fn jtd_schema() -> serde_json::Value {
82 let mut schema = T::jtd_schema();
83 if let Some(obj) = schema.as_object_mut() {
84 obj.insert("nullable".to_string(), serde_json::Value::Bool(true));
85 }
86 schema
87 }
88}
89
90impl<T: SeamType> SeamType for std::collections::HashMap<String, T> {
91 fn jtd_schema() -> serde_json::Value {
92 serde_json::json!({ "values": T::jtd_schema() })
93 }
94}
95
96impl<T: SeamType> SeamType for std::collections::BTreeMap<String, T> {
97 fn jtd_schema() -> serde_json::Value {
98 serde_json::json!({ "values": T::jtd_schema() })
99 }
100}
101
102#[cfg(test)]
103extern crate self as seam_server;
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn primitive_schemas() {
111 assert_eq!(String::jtd_schema(), serde_json::json!({"type": "string"}));
112 assert_eq!(bool::jtd_schema(), serde_json::json!({"type": "boolean"}));
113 assert_eq!(i32::jtd_schema(), serde_json::json!({"type": "int32"}));
114 assert_eq!(u32::jtd_schema(), serde_json::json!({"type": "uint32"}));
115 assert_eq!(f64::jtd_schema(), serde_json::json!({"type": "float64"}));
116 }
117
118 #[test]
119 fn vec_schema() {
120 assert_eq!(Vec::<String>::jtd_schema(), serde_json::json!({"elements": {"type": "string"}}),);
121 }
122
123 #[test]
124 fn option_schema() {
125 assert_eq!(
126 Option::<String>::jtd_schema(),
127 serde_json::json!({"type": "string", "nullable": true}),
128 );
129 }
130
131 #[test]
132 fn hashmap_schema() {
133 assert_eq!(
134 std::collections::HashMap::<String, f64>::jtd_schema(),
135 serde_json::json!({"values": {"type": "float64"}}),
136 );
137 }
138
139 #[derive(SeamType)]
140 #[allow(dead_code)]
141 enum Role {
142 Admin,
143 Member,
144 Guest,
145 }
146
147 #[test]
148 fn enum_schema() {
149 assert_eq!(Role::jtd_schema(), serde_json::json!({"enum": ["admin", "member", "guest"]}),);
150 }
151}