Skip to main content

shape_runtime/stdlib/
compress.rs

1//! Native `compress` module for data compression and decompression.
2//!
3//! Exports: compress.gzip, compress.gunzip, compress.zstd, compress.unzstd,
4//!          compress.deflate, compress.inflate
5//!
6//! Phase 4b: all 6 exports migrated to `TypedModuleExports`.
7//! Phase 2c: ported to the typed marshal layer (option β: owned `Vec<i64>`
8//! / `Vec<u8>` / `Arc<String>` via FromSlot, `TypedReturn::Concrete(
9//! ConcreteReturn::Bytes | ConcreteReturn::String)` outputs). The 3 compress
10//! functions return `ConcreteReturn::Bytes` (semantically `Array<int>` of
11//! u8 widened to i64); the 3 decompress functions return
12//! `ConcreteReturn::String`.
13
14use super::byte_utils::bytes_from_i64_slice;
15use crate::marshal::{register_typed_fn_1, register_typed_fn_2};
16use crate::module_exports::ModuleExports;
17use crate::typed_module_exports::{ConcreteReturn, ConcreteType, TypedReturn};
18use std::sync::Arc;
19
20/// Create the `compress` module with compression/decompression functions.
21pub fn create_compress_module() -> ModuleExports {
22    let mut module = ModuleExports::new("std::core::compress");
23    module.description = "Data compression and decompression (gzip, zstd, deflate)".to_string();
24
25    // compress.gzip(data: string) -> Array<int>
26    register_typed_fn_1::<_, Arc<String>>(
27        &mut module,
28        "gzip",
29        "Compress a string using gzip, returning a byte array",
30        "data",
31        "string",
32        ConcreteType::Bytes,
33        |data, _ctx| {
34            use flate2::Compression;
35            use flate2::write::GzEncoder;
36            use std::io::Write;
37
38            let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
39            encoder
40                .write_all(data.as_bytes())
41                .map_err(|e| format!("compress.gzip() failed: {}", e))?;
42            let compressed = encoder
43                .finish()
44                .map_err(|e| format!("compress.gzip() failed: {}", e))?;
45
46            Ok(TypedReturn::Concrete(ConcreteReturn::Bytes(compressed)))
47        },
48    );
49
50    // compress.gunzip(data: Array<int>) -> string
51    register_typed_fn_1::<_, Vec<i64>>(
52        &mut module,
53        "gunzip",
54        "Decompress a gzip byte array back to a string",
55        "data",
56        "Array<int>",
57        ConcreteType::String,
58        |data, _ctx| {
59            use flate2::read::GzDecoder;
60            use std::io::Read;
61
62            let bytes = bytes_from_i64_slice(&data)
63                .map_err(|e| format!("compress.gunzip(): {}", e))?;
64
65            let mut decoder = GzDecoder::new(&bytes[..]);
66            let mut output = String::new();
67            decoder
68                .read_to_string(&mut output)
69                .map_err(|e| format!("compress.gunzip() failed: {}", e))?;
70
71            Ok(TypedReturn::Concrete(ConcreteReturn::String(output)))
72        },
73    );
74
75    // compress.zstd(data: string, level?: int) -> Array<int>
76    register_typed_fn_2::<_, Arc<String>, i64>(
77        &mut module,
78        "zstd",
79        "Compress a string using Zstandard, returning a byte array",
80        [("data", "string"), ("level", "int")],
81        ConcreteType::Bytes,
82        |data, level, _ctx| {
83            let compressed = zstd::encode_all(data.as_bytes(), level as i32)
84                .map_err(|e| format!("compress.zstd() failed: {}", e))?;
85
86            Ok(TypedReturn::Concrete(ConcreteReturn::Bytes(compressed)))
87        },
88    );
89
90    // compress.unzstd(data: Array<int>) -> string
91    register_typed_fn_1::<_, Vec<i64>>(
92        &mut module,
93        "unzstd",
94        "Decompress a Zstandard byte array back to a string",
95        "data",
96        "Array<int>",
97        ConcreteType::String,
98        |data, _ctx| {
99            let bytes = bytes_from_i64_slice(&data)
100                .map_err(|e| format!("compress.unzstd(): {}", e))?;
101
102            let decompressed = zstd::decode_all(&bytes[..])
103                .map_err(|e| format!("compress.unzstd() failed: {}", e))?;
104
105            let output = String::from_utf8(decompressed)
106                .map_err(|e| format!("compress.unzstd() invalid UTF-8: {}", e))?;
107
108            Ok(TypedReturn::Concrete(ConcreteReturn::String(output)))
109        },
110    );
111
112    // compress.deflate(data: string) -> Array<int>
113    register_typed_fn_1::<_, Arc<String>>(
114        &mut module,
115        "deflate",
116        "Compress a string using raw deflate, returning a byte array",
117        "data",
118        "string",
119        ConcreteType::Bytes,
120        |data, _ctx| {
121            use flate2::Compression;
122            use flate2::write::DeflateEncoder;
123            use std::io::Write;
124
125            let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
126            encoder
127                .write_all(data.as_bytes())
128                .map_err(|e| format!("compress.deflate() failed: {}", e))?;
129            let compressed = encoder
130                .finish()
131                .map_err(|e| format!("compress.deflate() failed: {}", e))?;
132
133            Ok(TypedReturn::Concrete(ConcreteReturn::Bytes(compressed)))
134        },
135    );
136
137    // compress.inflate(data: Array<int>) -> string
138    register_typed_fn_1::<_, Vec<i64>>(
139        &mut module,
140        "inflate",
141        "Decompress a raw deflate byte array back to a string",
142        "data",
143        "Array<int>",
144        ConcreteType::String,
145        |data, _ctx| {
146            use flate2::read::DeflateDecoder;
147            use std::io::Read;
148
149            let bytes = bytes_from_i64_slice(&data)
150                .map_err(|e| format!("compress.inflate(): {}", e))?;
151
152            let mut decoder = DeflateDecoder::new(&bytes[..]);
153            let mut output = String::new();
154            decoder
155                .read_to_string(&mut output)
156                .map_err(|e| format!("compress.inflate() failed: {}", e))?;
157
158            Ok(TypedReturn::Concrete(ConcreteReturn::String(output)))
159        },
160    );
161
162    module
163}