Skip to main content

shape_runtime/stdlib/
msgpack_module.rs

1//! Native `msgpack` module for MessagePack encoding and decoding.
2//!
3//! Exports: msgpack.encode(value), msgpack.decode(data),
4//!          msgpack.encode_bytes(value), msgpack.decode_bytes(data)
5//!
6//! Phase 1.B (ADR-006 §2.7.4) status: ALL FOUR FUNCTIONS REMAIN
7//! DEFERRED pending the **N4** (any-input typed marshal) and **N6**
8//! (any-output typed marshal) architectural decisions per
9//! `docs/defections.md` HashMap-marshal cluster's sub-decision queue.
10//!
11//! - `msgpack.encode(value: any)` and `msgpack.encode_bytes(value: any)`
12//!   take a polymorphic `value: any` input parameter that maps to the
13//!   N4 architectural surface. There is no `FromSlot` impl for an
14//!   `any`-typed input in the post-bulldozer typed marshal layer
15//!   (`ConcreteType::Any` exists as a RETURN type only).
16//! - `msgpack.decode(data: string)` and
17//!   `msgpack.decode_bytes(data: Array<int>)` return `Result<any>` —
18//!   the decoded payload is a recursive `serde_json::Value`-equivalent
19//!   tree with no current `ConcreteReturn::Any` representation, mapping
20//!   to the N6 architectural surface.
21//!
22//! Until N4 + N6 land, the bodies use the variadic
23//! [`register_typed_function`] shape (per ADR-006 §2.7.4 ruling) but
24//! return `Err(...)` rather than emit a partial / unsound serializer.
25//! The schemas + `ModuleParam` declarations remain so the LSP surface
26//! is unaffected. New typed-marshal test fixtures arrive with the
27//! shape-vm cleanup workstream.
28
29use crate::module_exports::{ModuleExports, ModuleParam};
30use crate::typed_module_exports::{
31    ConcreteReturn, ConcreteType, TypedReturn, register_typed_function,
32};
33
34/// Create the `msgpack` module with MessagePack encoding and decoding functions.
35pub fn create_msgpack_module() -> ModuleExports {
36    let mut module = ModuleExports::new("std::core::msgpack");
37    module.description = "MessagePack binary serialization".to_string();
38
39    // msgpack.encode(value: any) -> Result<string>
40    register_typed_function(
41        &mut module,
42        "encode",
43        "Encode a value to MessagePack (hex-encoded string)",
44        vec![ModuleParam {
45            name: "value".to_string(),
46            type_name: "any".to_string(),
47            required: true,
48            description: "Value to encode".to_string(),
49            ..Default::default()
50        }],
51        ConcreteType::Result(Box::new(ConcreteType::String)),
52        |_args, _ctx| {
53            Ok(TypedReturn::Err(ConcreteReturn::String(
54                "msgpack.encode() pending N4 (any-input marshal) — see ADR-006 §2.7.4".to_string(),
55            )))
56        },
57    );
58
59    // msgpack.decode(data: string) -> Result<any>
60    register_typed_function(
61        &mut module,
62        "decode",
63        "Decode a hex-encoded MessagePack string to a value",
64        vec![ModuleParam {
65            name: "data".to_string(),
66            type_name: "string".to_string(),
67            required: true,
68            description: "Hex-encoded MessagePack data".to_string(),
69            ..Default::default()
70        }],
71        ConcreteType::Result(Box::new(ConcreteType::Any)),
72        |_args, _ctx| {
73            Ok(TypedReturn::Err(ConcreteReturn::String(
74                "msgpack.decode() pending N6 (any-output marshal) — see ADR-006 §2.7.4".to_string(),
75            )))
76        },
77    );
78
79    // msgpack.encode_bytes(value: any) -> Result<Array<int>>
80    register_typed_function(
81        &mut module,
82        "encode_bytes",
83        "Encode a value to MessagePack as a byte array",
84        vec![ModuleParam {
85            name: "value".to_string(),
86            type_name: "any".to_string(),
87            required: true,
88            description: "Value to encode".to_string(),
89            ..Default::default()
90        }],
91        ConcreteType::Result(Box::new(ConcreteType::ArrayInt)),
92        |_args, _ctx| {
93            Ok(TypedReturn::Err(ConcreteReturn::String(
94                "msgpack.encode_bytes() pending N4 (any-input marshal) — see ADR-006 §2.7.4"
95                    .to_string(),
96            )))
97        },
98    );
99
100    // msgpack.decode_bytes(data: Array<int>) -> Result<any>
101    register_typed_function(
102        &mut module,
103        "decode_bytes",
104        "Decode MessagePack from a byte array to a value",
105        vec![ModuleParam {
106            name: "data".to_string(),
107            type_name: "Array<int>".to_string(),
108            required: true,
109            description: "Array of byte values (0-255)".to_string(),
110            ..Default::default()
111        }],
112        ConcreteType::Result(Box::new(ConcreteType::Any)),
113        |_args, _ctx| {
114            Ok(TypedReturn::Err(ConcreteReturn::String(
115                "msgpack.decode_bytes() pending N6 (any-output marshal) — see ADR-006 §2.7.4"
116                    .to_string(),
117            )))
118        },
119    );
120
121    module
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127
128    #[test]
129    fn test_msgpack_module_creation() {
130        let module = create_msgpack_module();
131        assert_eq!(module.name, "std::core::msgpack");
132        assert!(module.has_export("encode"));
133        assert!(module.has_export("decode"));
134        assert!(module.has_export("encode_bytes"));
135        assert!(module.has_export("decode_bytes"));
136    }
137
138    #[test]
139    fn test_msgpack_typed_registry_populated() {
140        let module = create_msgpack_module();
141        let typed = module.typed_exports();
142        assert!(typed.get("encode").is_some());
143        assert!(typed.get("decode").is_some());
144        assert!(typed.get("encode_bytes").is_some());
145        assert!(typed.get("decode_bytes").is_some());
146    }
147
148    // Behavioural roundtrip tests deleted alongside `module.invoke_export()`
149    // and the deleted `ValueWord` constructors. They return when N4 + N6
150    // land and the bodies become real serializers.
151}