Skip to main content

sema_stdlib/
lib.rs

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