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