Skip to main content

ranvier_core/
metadata.rs

1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5pub struct StepMetadata {
6    pub id: Uuid,
7    pub label: String,
8    pub description: Option<String>,
9    pub inputs: Vec<TypeInfo>,
10    pub outputs: Vec<TypeInfo>,
11}
12
13impl StepMetadata {
14    pub fn to_json(&self) -> serde_json::Value {
15        serde_json::to_value(self).unwrap_or(serde_json::Value::Null)
16    }
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct TypeInfo {
21    pub name: String,
22    /// Optional JSON Schema describing this type's structure.
23    /// Populated via `.with_input_schema::<T>()` / `.with_output_schema::<T>()` or `#[transition(schema)]`.
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub json_schema: Option<serde_json::Value>,
26}
27
28impl TypeInfo {
29    pub fn new(name: impl Into<String>) -> Self {
30        Self {
31            name: name.into(),
32            json_schema: None,
33        }
34    }
35
36    pub fn with_json_schema(mut self, schema: serde_json::Value) -> Self {
37        self.json_schema = Some(schema);
38        self
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use serde_json::json;
46
47    #[test]
48    fn type_info_new_has_no_schema() {
49        let info = TypeInfo::new("i32");
50        assert_eq!(info.name, "i32");
51        assert!(info.json_schema.is_none());
52    }
53
54    #[test]
55    fn type_info_with_json_schema_builder() {
56        let schema = json!({"type": "object", "properties": {"x": {"type": "integer"}}});
57        let info = TypeInfo::new("MyStruct").with_json_schema(schema.clone());
58        assert_eq!(info.json_schema.unwrap(), schema);
59    }
60
61    #[test]
62    fn type_info_json_schema_omitted_when_none() {
63        let info = TypeInfo::new("i32");
64        let json = serde_json::to_value(&info).unwrap();
65        assert!(!json.as_object().unwrap().contains_key("json_schema"));
66    }
67
68    #[test]
69    fn type_info_json_schema_present_when_some() {
70        let schema = json!({"type": "string"});
71        let info = TypeInfo::new("String").with_json_schema(schema.clone());
72        let json = serde_json::to_value(&info).unwrap();
73        assert_eq!(json["json_schema"], schema);
74    }
75
76    #[test]
77    fn type_info_deserializes_without_json_schema_field() {
78        let json = r#"{"name": "u64"}"#;
79        let info: TypeInfo = serde_json::from_str(json).unwrap();
80        assert_eq!(info.name, "u64");
81        assert!(info.json_schema.is_none());
82    }
83
84    #[test]
85    fn type_info_roundtrip_with_schema() {
86        let schema = json!({"type": "array", "items": {"type": "integer"}});
87        let info = TypeInfo::new("Vec<i32>").with_json_schema(schema.clone());
88        let serialized = serde_json::to_string(&info).unwrap();
89        let deserialized: TypeInfo = serde_json::from_str(&serialized).unwrap();
90        assert_eq!(deserialized.name, "Vec<i32>");
91        assert_eq!(deserialized.json_schema.unwrap(), schema);
92    }
93}