Skip to main content

seam_server/
lib.rs

1/* src/server/core/rust/src/lib.rs */
2#![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
16// Re-exports for ergonomic use
17pub 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
45/// Trait for types that can describe themselves as a JTD schema.
46/// Derive with `#[derive(SeamType)]` or implement manually.
47pub trait SeamType {
48	fn jtd_schema() -> serde_json::Value;
49}
50
51// -- Primitive SeamType impls --
52
53macro_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}