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