adana_std_process/
lib.rs

1use std::{collections::BTreeMap, io::Write, thread::JoinHandle, time::Duration};
2
3use adana_script_core::{
4    primitive::{Compiler, NativeFunctionCallResult, Primitive},
5    Value,
6};
7
8#[no_mangle]
9pub fn environ(params: Vec<Primitive>, _compiler: Box<Compiler>) -> NativeFunctionCallResult {
10    if params.is_empty() {
11        let s = std::env::vars()
12            .map(|(k, v)| (k, Primitive::String(v)))
13            .collect::<BTreeMap<_, _>>();
14        Ok(Primitive::Struct(s))
15    } else {
16        let r = std::env::var(params[0].to_string())
17            .ok()
18            .map(Primitive::String)
19            .unwrap_or_else(|| Primitive::Null);
20        Ok(r)
21    }
22}
23#[no_mangle]
24pub fn delay(mut params: Vec<Primitive>, mut compiler: Box<Compiler>) -> NativeFunctionCallResult {
25    if params.is_empty() {
26        Err(anyhow::anyhow!("at least one parameter must be provided"))
27    } else {
28        let delay = match params.remove(0) {
29            Primitive::Int(delay) if delay >= 0 => delay as u64,
30            Primitive::U8(delay) => delay as u64,
31            Primitive::I8(delay) if delay >= 0 => delay as u64,
32            e => {
33                return Err(anyhow::anyhow!(
34                    "first parameter must be the sleep duration (int) => {e}"
35                ))
36            }
37        };
38
39        if params.is_empty() {
40            std::thread::sleep(Duration::from_millis(delay as u64));
41            Ok(Primitive::Unit)
42        } else if params.len() == 2 {
43            let handle: JoinHandle<anyhow::Result<()>> = std::thread::spawn(move || {
44                std::thread::sleep(Duration::from_millis(delay as u64));
45
46                let f @ Primitive::Function { .. } = params.remove(0) else {
47                    return Err(anyhow::anyhow!("second parameter must be a function"));
48                };
49                let Primitive::Struct(ctx) = params.remove(0) else {
50                    return Err(anyhow::anyhow!(
51                        "third parameter must be the context (struct)"
52                    ));
53                };
54                let function = f.to_value()?;
55                let ctx = ctx
56                    .into_iter()
57                    .map(|(k, v)| (k, v.ref_prim()))
58                    .collect::<BTreeMap<_, _>>();
59
60                let parameters = ctx.keys().cloned().map(Value::String).collect::<Vec<_>>();
61                compiler(
62                    Value::FunctionCall {
63                        parameters: Box::new(Value::BlockParen(parameters)),
64                        function: Box::new(function),
65                    },
66                    ctx,
67                )?;
68                std::io::stdout().flush()?;
69                Ok(())
70            });
71            std::thread::spawn(move || match handle.join() {
72                Ok(Ok(())) => {}
73                e => eprintln!("{e:?}"),
74            });
75            Ok(Primitive::Unit)
76        } else {
77            Err(anyhow::anyhow!("too many arguments"))
78        }
79    }
80}
81/// Api description
82#[no_mangle]
83pub fn api_description(
84    _params: Vec<Primitive>,
85    _compiler: Box<Compiler>,
86) -> NativeFunctionCallResult {
87    Ok(Primitive::Struct(BTreeMap::from([(
88        "environ".into(),
89        Primitive::String(
90            "environ(string) -> struct | string, takes an optional key, return environment variable(s)"
91                .into(),
92        )),
93        ("delay".into(),
94        Primitive::String(
95            r#"delay(int, function, ctx) -> () | sleep for a specified amount of time. 
96            Takes optional function and immutable context (struct) as callback.
97            e.g : 
98               f = () => {
99                    e = process.environ("WEZTERM_PANE")
100                    if(e!= null) {
101                        println("found env: " + e)
102                    }
103               }
104               s = struct {}
105               process.delay(1000, f, s)
106               "#
107            .into(),
108        )),
109    ])))
110}