Skip to main content

seam_server/
lib.rs

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