Skip to main content

seam_server/
lib.rs

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