Skip to main content

sema_stdlib/
lib.rs

1#![allow(clippy::mutable_key_type, clippy::cloned_ref_to_slice_refs)]
2mod arithmetic;
3mod async_ops;
4mod bitwise;
5mod bytevector;
6mod comparison;
7mod context;
8mod crypto;
9mod csv_ops;
10mod datetime;
11#[cfg(not(target_arch = "wasm32"))]
12mod http;
13#[cfg(not(target_arch = "wasm32"))]
14mod io;
15pub(crate) mod json;
16#[cfg(not(target_arch = "wasm32"))]
17mod kv;
18mod list;
19mod map;
20mod math;
21mod meta;
22mod otel;
23#[cfg(not(target_arch = "wasm32"))]
24mod pdf;
25mod pio;
26mod predicates;
27mod regex_ops;
28#[cfg(not(target_arch = "wasm32"))]
29mod serial;
30#[cfg(not(target_arch = "wasm32"))]
31mod server;
32#[cfg(not(target_arch = "wasm32"))]
33mod sqlite;
34mod stream;
35mod string;
36#[cfg(not(target_arch = "wasm32"))]
37mod system;
38#[cfg(not(target_arch = "wasm32"))]
39mod terminal;
40mod text;
41mod toml_ops;
42mod typed_array;
43
44#[cfg(not(target_arch = "wasm32"))]
45use sema_core::Caps;
46use sema_core::{Env, Sandbox, Value};
47
48pub fn register_stdlib(env: &Env, sandbox: &Sandbox) {
49    #[cfg(target_arch = "wasm32")]
50    let _ = sandbox;
51
52    arithmetic::register(env);
53    comparison::register(env);
54    context::register(env);
55    list::register(env);
56    string::register(env);
57    predicates::register(env);
58    map::register(env);
59    #[cfg(not(target_arch = "wasm32"))]
60    io::register(env, sandbox);
61    math::register(env);
62    #[cfg(not(target_arch = "wasm32"))]
63    system::register(env, sandbox);
64    json::register(env);
65    toml_ops::register(env);
66    meta::register(env);
67    otel::register(env);
68    regex_ops::register(env);
69    #[cfg(not(target_arch = "wasm32"))]
70    http::register(env, sandbox);
71    #[cfg(not(target_arch = "wasm32"))]
72    server::register(env, sandbox);
73    bitwise::register(env);
74    crypto::register(env);
75    datetime::register(env);
76    csv_ops::register(env);
77    bytevector::register(env);
78    #[cfg(not(target_arch = "wasm32"))]
79    terminal::register(env);
80    text::register(env);
81    stream::register(env);
82    pio::register(env);
83    typed_array::register(env);
84    async_ops::register(env);
85    #[cfg(not(target_arch = "wasm32"))]
86    stream::register_io(env, sandbox);
87    #[cfg(not(target_arch = "wasm32"))]
88    kv::register(env, sandbox);
89    #[cfg(not(target_arch = "wasm32"))]
90    pdf::register(env, sandbox);
91    #[cfg(not(target_arch = "wasm32"))]
92    sqlite::register(env, sandbox);
93    #[cfg(not(target_arch = "wasm32"))]
94    serial::register(env, sandbox);
95}
96
97#[cfg(not(target_arch = "wasm32"))]
98fn register_fn_gated(
99    env: &Env,
100    sandbox: &Sandbox,
101    cap: Caps,
102    name: &str,
103    f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
104) {
105    if sandbox.is_unrestricted() {
106        register_fn(env, name, f);
107    } else {
108        let sandbox = sandbox.clone();
109        let fn_name = name.to_string();
110        register_fn(env, name, move |args| {
111            sandbox.check(cap, &fn_name)?;
112            f(args)
113        });
114    }
115}
116
117#[cfg(not(target_arch = "wasm32"))]
118fn register_fn_path_gated(
119    env: &Env,
120    sandbox: &Sandbox,
121    cap: Caps,
122    name: &str,
123    path_args: &[usize],
124    f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
125) {
126    if sandbox.is_unrestricted() {
127        register_fn(env, name, f);
128    } else {
129        let sandbox = sandbox.clone();
130        let fn_name = name.to_string();
131        let path_indices: Vec<usize> = path_args.to_vec();
132        register_fn(env, name, move |args| {
133            sandbox.check(cap, &fn_name)?;
134            for &idx in &path_indices {
135                if let Some(val) = args.get(idx) {
136                    if let Some(p) = val.as_str() {
137                        sandbox.check_path(p, &fn_name)?;
138                    }
139                }
140            }
141            f(args)
142        });
143    }
144}
145
146fn register_fn(
147    env: &Env,
148    name: &str,
149    f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
150) {
151    env.set(
152        sema_core::intern(name),
153        Value::native_fn(sema_core::NativeFn::simple(name, f)),
154    );
155}