shape_runtime/stdlib/
yaml.rs1use crate::module_exports::{ModuleExports, ModuleParam};
25use crate::typed_module_exports::{
26 ConcreteReturn, ConcreteType, TypedReturn, register_typed_function,
27};
28use shape_value::KindedSlot;
29use std::sync::Arc;
30
31fn slot_as_string(slot: &KindedSlot) -> Option<Arc<String>> {
34 let bits = slot.slot().raw();
35 if bits == 0 {
36 return None;
37 }
38 unsafe {
39 let arc = Arc::<String>::from_raw(bits as *const String);
40 let cloned = arc.clone();
41 std::mem::forget(arc);
42 Some(cloned)
43 }
44}
45
46pub fn create_yaml_module() -> ModuleExports {
48 let mut module = ModuleExports::new("std::core::yaml");
49 module.description = "YAML parsing and serialization".to_string();
50
51 register_typed_function(
53 &mut module,
54 "parse",
55 "Parse a YAML string into Shape values",
56 vec![ModuleParam {
57 name: "text".to_string(),
58 type_name: "string".to_string(),
59 required: true,
60 description: "YAML string to parse".to_string(),
61 ..Default::default()
62 }],
63 ConcreteType::Result(Box::new(ConcreteType::HashMap)),
64 |_args, _ctx| {
65 Ok(TypedReturn::Err(ConcreteReturn::String(
66 "yaml.parse() pending N6 (any-output marshal) — see ADR-006 §2.7.4".to_string(),
67 )))
68 },
69 );
70
71 register_typed_function(
73 &mut module,
74 "parse_all",
75 "Parse a multi-document YAML string into an array of Shape values",
76 vec![ModuleParam {
77 name: "text".to_string(),
78 type_name: "string".to_string(),
79 required: true,
80 description: "YAML string with one or more documents".to_string(),
81 ..Default::default()
82 }],
83 ConcreteType::Result(Box::new(ConcreteType::Array)),
84 |_args, _ctx| {
85 Ok(TypedReturn::Err(ConcreteReturn::String(
86 "yaml.parse_all() pending N6 (any-output marshal) — see ADR-006 §2.7.4"
87 .to_string(),
88 )))
89 },
90 );
91
92 register_typed_function(
94 &mut module,
95 "stringify",
96 "Serialize Shape values to a YAML string",
97 vec![ModuleParam {
98 name: "value".to_string(),
99 type_name: "any".to_string(),
100 required: true,
101 description: "Value to serialize".to_string(),
102 ..Default::default()
103 }],
104 ConcreteType::Result(Box::new(ConcreteType::String)),
105 |_args, _ctx| {
106 Ok(TypedReturn::Err(ConcreteReturn::String(
107 "yaml.stringify() pending N4 (any-input marshal) — see ADR-006 §2.7.4"
108 .to_string(),
109 )))
110 },
111 );
112
113 register_typed_function(
115 &mut module,
116 "is_valid",
117 "Check if a string is valid YAML",
118 vec![ModuleParam {
119 name: "text".to_string(),
120 type_name: "string".to_string(),
121 required: true,
122 description: "String to validate as YAML".to_string(),
123 ..Default::default()
124 }],
125 ConcreteType::Bool,
126 |args, _ctx| {
127 let slot = args
128 .first()
129 .ok_or_else(|| "yaml.is_valid() requires a string argument".to_string())?;
130 let text = slot_as_string(slot)
131 .ok_or_else(|| "yaml.is_valid() requires a string argument".to_string())?;
132 let valid = serde_yaml::from_str::<serde_yaml::Value>(text.as_str()).is_ok();
133 Ok(TypedReturn::Concrete(ConcreteReturn::Bool(valid)))
134 },
135 );
136
137 module
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn test_yaml_module_creation() {
146 let module = create_yaml_module();
147 assert_eq!(module.name, "std::core::yaml");
148 assert!(module.has_export("parse"));
149 assert!(module.has_export("parse_all"));
150 assert!(module.has_export("stringify"));
151 assert!(module.has_export("is_valid"));
152 }
153
154 #[test]
155 fn test_yaml_typed_registry_populated() {
156 let module = create_yaml_module();
157 let typed = module.typed_exports();
158 assert!(typed.get("parse").is_some());
159 assert!(typed.get("parse_all").is_some());
160 assert!(typed.get("stringify").is_some());
161 assert!(typed.get("is_valid").is_some());
162 }
163
164 }