Skip to main content

seam_server/
lib.rs

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