1use lex_bytecode::{MapKey, Value};
6use std::collections::{BTreeMap, BTreeSet, HashMap};
7use std::sync::{Mutex, OnceLock};
8
9pub fn is_pure_call(kind: &str, op: &str) -> bool {
13 if !is_pure_module(kind) { return false; }
14 !matches!(
15 (kind, op),
16 ("crypto", "random")
17 | ("crypto", "random_str_hex")
18 | ("crypto", "p256_generate")
21 | ("crypto", "secp256k1_generate")
23 | ("datetime", "now")
24 | ("http", "send")
25 | ("http", "get")
26 | ("http", "post")
27 | ("http", "stream_lines")
28 | ("arrow", "read_csv")
30 | ("arrow", "read_parquet")
32 | ("arrow", "read_parquet_cols")
33 | ("arrow", "write_parquet")
34 | ("arrow", "write_csv")
35 )
36}
37
38pub fn call_pure_builtin(kind: &str, op: &str, args: Vec<Value>) -> Result<Value, String> {
45 if (kind, op) == ("list", "cons") {
46 let mut it = args.into_iter();
47 let head = it.next().unwrap_or(Value::Unit);
48 let mut tail = match it.next() {
49 Some(Value::List(v)) => v,
50 Some(other) => return Err(format!("list.cons: expected List, got {other:?}")),
51 None => std::collections::VecDeque::new(),
52 };
53 tail.push_front(head);
54 return Ok(Value::List(tail));
55 }
56 dispatch(kind, op, &args)
57}
58
59pub fn try_pure_builtin(kind: &str, op: &str, args: &[Value]) -> Option<Result<Value, String>> {
66 if !is_pure_call(kind, op) { return None; }
67 Some(dispatch(kind, op, args))
68}
69
70pub fn is_pure_module(kind: &str) -> bool {
73 matches!(kind, "str" | "int" | "float" | "bool" | "list" | "iter"
74 | "option" | "result" | "tuple" | "json" | "bytes" | "flow" | "math"
75 | "map" | "set" | "crypto" | "regex" | "deque" | "datetime" | "duration" | "http"
76 | "toml" | "yaml" | "dotenv" | "csv" | "test" | "random" | "parser"
77 | "cli" | "arrow" | "df" | "decimal")
78}
79
80fn dispatch(kind: &str, op: &str, args: &[Value]) -> Result<Value, String> {
81 match (kind, op) {
82 ("str", "is_empty") => Ok(Value::Bool(expect_str(args.first())?.is_empty())),
84 ("str", "len") => Ok(Value::Int(expect_str(args.first())?.len() as i64)),
85 ("str", "concat") => {
86 let a = expect_str(args.first())?;
87 let b = expect_str(args.get(1))?;
88 Ok(Value::Str(format!("{a}{b}").into()))
89 }
90 ("str", "to_int") => {
91 let s = expect_str(args.first())?;
92 match s.parse::<i64>() {
93 Ok(n) => Ok(some(Value::Int(n))),
94 Err(_) => Ok(none()),
95 }
96 }
97 ("str", "split") => {
98 let s = expect_str(args.first())?;
99 let sep = expect_str(args.get(1))?;
100 let items: std::collections::VecDeque<Value> = if sep.is_empty() {
101 s.chars().map(|c| Value::Str(c.to_string().into())).collect()
102 } else {
103 s.split(sep.as_str()).map(|p| Value::Str(p.into())).collect()
104 };
105 Ok(Value::List(items))
106 }
107 ("str", "join") => {
108 let parts = expect_list(args.first())?;
109 let sep = expect_str(args.get(1))?;
110 let mut out = String::new();
111 for (i, p) in parts.iter().enumerate() {
112 if i > 0 { out.push_str(&sep); }
113 match p {
114 Value::Str(s) => out.push_str(s),
115 other => return Err(format!("str.join element must be Str, got {other:?}")),
116 }
117 }
118 Ok(Value::Str(out.into()))
119 }
120 ("str", "starts_with") => {
121 let s = expect_str(args.first())?;
122 let prefix = expect_str(args.get(1))?;
123 Ok(Value::Bool(s.starts_with(prefix.as_str())))
124 }
125 ("str", "ends_with") => {
126 let s = expect_str(args.first())?;
127 let suffix = expect_str(args.get(1))?;
128 Ok(Value::Bool(s.ends_with(suffix.as_str())))
129 }
130 ("str", "contains") => {
131 let s = expect_str(args.first())?;
132 let needle = expect_str(args.get(1))?;
133 Ok(Value::Bool(s.contains(needle.as_str())))
134 }
135 ("str", "cmp") => {
136 let a = expect_str(args.first())?;
137 let b = expect_str(args.get(1))?;
138 Ok(Value::Int(match a.as_str().cmp(b.as_str()) {
139 std::cmp::Ordering::Less => -1,
140 std::cmp::Ordering::Equal => 0,
141 std::cmp::Ordering::Greater => 1,
142 }))
143 }
144 ("str", "replace") => {
145 let s = expect_str(args.first())?;
146 let from = expect_str(args.get(1))?;
147 let to = expect_str(args.get(2))?;
148 Ok(Value::Str(s.replace(from.as_str(), to.as_str()).into()))
149 }
150 ("str", "trim") => Ok(Value::Str(expect_str(args.first())?.trim().into())),
151 ("str", "to_upper") => Ok(Value::Str(expect_str(args.first())?.to_uppercase().into())),
152 ("str", "to_lower") => Ok(Value::Str(expect_str(args.first())?.to_lowercase().into())),
153 ("str", "strip_prefix") => {
154 let s = expect_str(args.first())?;
155 let prefix = expect_str(args.get(1))?;
156 Ok(match s.strip_prefix(prefix.as_str()) {
157 Some(rest) => some(Value::Str(rest.into())),
158 None => none(),
159 })
160 }
161 ("str", "strip_suffix") => {
162 let s = expect_str(args.first())?;
163 let suffix = expect_str(args.get(1))?;
164 Ok(match s.strip_suffix(suffix.as_str()) {
165 Some(rest) => some(Value::Str(rest.into())),
166 None => none(),
167 })
168 }
169 ("str", "slice") => {
170 let s = expect_str(args.first())?;
175 let lo_i = expect_int(args.get(1))?;
176 let hi_i = expect_int(args.get(2))?;
177 let lo_cp = lo_i.max(0) as usize;
178 let hi_cp = hi_i.max(0) as usize;
179 if lo_cp > hi_cp {
180 return Err(format!(
181 "str.slice: reversed range [{lo_cp}..{hi_cp}]"));
182 }
183 let lo_byte = s.char_indices().nth(lo_cp).map(|(b, _)| b).unwrap_or(s.len());
186 let hi_byte = s.char_indices().nth(hi_cp).map(|(b, _)| b).unwrap_or(s.len());
187 Ok(Value::Str(s[lo_byte..hi_byte].into()))
188 }
189
190 ("int", "to_str") => Ok(Value::Str(expect_int(args.first())?.to_string().into())),
192 ("int", "to_float") => Ok(Value::Float(expect_int(args.first())? as f64)),
193 ("float", "to_int") => Ok(Value::Int(expect_float(args.first())? as i64)),
194 ("float", "to_str") => Ok(Value::Str(expect_float(args.first())?.to_string().into())),
195 ("str", "to_float") => {
196 let s = expect_str(args.first())?;
197 match s.parse::<f64>() {
198 Ok(f) => Ok(some(Value::Float(f))),
199 Err(_) => Ok(none()),
200 }
201 }
202
203 ("list", "len") => Ok(Value::Int(expect_list(args.first())?.len() as i64)),
205 ("list", "is_empty") => Ok(Value::Bool(expect_list(args.first())?.is_empty())),
206 ("list", "head") => {
207 let xs = expect_list(args.first())?;
208 match xs.front() {
209 Some(v) => Ok(some(v.clone())),
210 None => Ok(none()),
211 }
212 }
213 ("list", "tail") => {
214 let xs = expect_list(args.first())?;
215 if xs.is_empty() { Ok(Value::List(std::collections::VecDeque::new())) }
216 else { Ok(Value::List(xs.iter().skip(1).cloned().collect::<std::collections::VecDeque<_>>())) }
217 }
218 ("list", "range") => {
219 let lo = expect_int(args.first())?;
220 let hi = expect_int(args.get(1))?;
221 Ok(Value::List((lo..hi).map(Value::Int).collect::<std::collections::VecDeque<_>>()))
222 }
223 ("list", "concat") => {
224 let mut out = expect_list(args.first())?.clone();
225 out.extend(expect_list(args.get(1))?.iter().cloned());
226 Ok(Value::List(out))
227 }
228 ("list", "reverse") => {
229 let out = expect_list(args.first())?.clone();
230 let rev: std::collections::VecDeque<Value> = out.into_iter().rev().collect();
231 Ok(Value::List(rev))
232 }
233 ("list", "cons") => {
237 let head = args.first().cloned().unwrap_or(Value::Unit);
238 let mut out: std::collections::VecDeque<Value> =
239 expect_list(args.get(1))?.iter().cloned().collect();
240 out.push_front(head);
241 Ok(Value::List(out))
242 }
243 ("list", "enumerate") => {
244 let xs = expect_list(args.first())?;
245 let pairs = xs.iter().cloned().enumerate()
246 .map(|(i, v)| Value::Tuple(vec![Value::Int(i as i64), v]))
247 .collect::<std::collections::VecDeque<_>>();
248 Ok(Value::List(pairs))
249 }
250
251 ("tuple", "fst") => tuple_index(first_arg(args)?, 0),
256 ("tuple", "snd") => tuple_index(first_arg(args)?, 1),
257 ("tuple", "third") => tuple_index(first_arg(args)?, 2),
258 ("tuple", "len") => match first_arg(args)? {
259 Value::Tuple(items) => Ok(Value::Int(items.len() as i64)),
260 other => Err(format!("tuple.len: expected Tuple, got {other:?}")),
261 },
262
263 ("option", "unwrap_or") => {
265 let opt = first_arg(args)?;
266 let default = args.get(1).cloned().unwrap_or(Value::Unit);
267 match opt {
268 Value::Variant { name, args } if name == "Some" && !args.is_empty() => Ok(args[0].clone()),
269 Value::Variant { name, .. } if name == "None" => Ok(default),
270 other => Err(format!("option.unwrap_or expected Option, got {other:?}")),
271 }
272 }
273 ("option", "unwrap_or_else") => {
278 let opt = first_arg(args)?;
279 match opt {
280 Value::Variant { name, args } if name == "Some" && !args.is_empty() => Ok(args[0].clone()),
281 Value::Variant { name, .. } if name == "None" => {
282 Ok(args.get(1).cloned().unwrap_or(Value::Unit))
286 }
287 other => Err(format!("option.unwrap_or_else expected Option, got {other:?}")),
288 }
289 }
290 ("option", "is_some") => match first_arg(args)? {
291 Value::Variant { name, .. } => Ok(Value::Bool(name == "Some")),
292 other => Err(format!("option.is_some expected Option, got {other:?}")),
293 },
294 ("option", "is_none") => match first_arg(args)? {
295 Value::Variant { name, .. } => Ok(Value::Bool(name == "None")),
296 other => Err(format!("option.is_none expected Option, got {other:?}")),
297 },
298
299 ("result", "is_ok") => match first_arg(args)? {
301 Value::Variant { name, .. } => Ok(Value::Bool(name == "Ok")),
302 other => Err(format!("result.is_ok expected Result, got {other:?}")),
303 },
304 ("result", "is_err") => match first_arg(args)? {
305 Value::Variant { name, .. } => Ok(Value::Bool(name == "Err")),
306 other => Err(format!("result.is_err expected Result, got {other:?}")),
307 },
308 ("result", "unwrap_or") => {
309 let res = first_arg(args)?;
310 let default = args.get(1).cloned().unwrap_or(Value::Unit);
311 match res {
312 Value::Variant { name, args } if name == "Ok" && !args.is_empty() => Ok(args[0].clone()),
313 Value::Variant { name, .. } if name == "Err" => Ok(default),
314 other => Err(format!("result.unwrap_or expected Result, got {other:?}")),
315 }
316 }
317
318 ("json", "stringify") => {
320 let v = first_arg(args)?;
321 Ok(Value::Str(serde_json::to_string(&value_to_json(v)).unwrap_or_default().into()))
322 }
323 ("json", "parse") => {
324 let s = expect_str(args.first())?;
325 match serde_json::from_str::<serde_json::Value>(&s) {
326 Ok(v) => Ok(ok_v(json_to_value(&v))),
327 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
328 }
329 }
330 ("json", "parse_strict") => {
333 let s = expect_str(args.first())?;
334 let required = required_field_names(args.get(1))?;
335 let schema = extract_type_schema(args.get(2));
336 match serde_json::from_str::<serde_json::Value>(&s) {
337 Ok(v) => {
338 if let Err(e) = check_required_fields(&v, &required) {
339 return Ok(err_v(Value::Str(e.into())));
340 }
341 if let Err(e) = validate_field_types(&v, &schema) {
342 return Ok(err_v(Value::Str(e.into())));
343 }
344 Ok(ok_v(apply_option_wrapping(json_to_value(&v), &v, &schema)))
345 }
346 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
347 }
348 }
349
350 ("toml", "parse") => {
355 let s = expect_str(args.first())?;
356 match toml::from_str::<serde_json::Value>(&s) {
357 Ok(mut v) => {
358 unwrap_toml_datetime_markers(&mut v);
359 Ok(ok_v(json_to_value(&v)))
360 }
361 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
362 }
363 }
364 ("json", "parse_strict_typed") => {
368 let s = expect_str(args.first())?;
369 let required = required_field_names(args.get(1))?;
370 let schema = extract_type_schema(args.get(2));
371 match serde_json::from_str::<serde_json::Value>(&s) {
372 Ok(v) => {
373 if let Err(e) = check_required_fields(&v, &required) {
374 return Ok(err_v(Value::Str(e.into())));
375 }
376 if let Err(e) = validate_field_types(&v, &schema) {
377 return Ok(err_v(Value::Str(e.into())));
378 }
379 Ok(ok_v(apply_option_wrapping(json_to_value(&v), &v, &schema)))
380 }
381 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
382 }
383 }
384
385 ("toml", "parse_strict") => {
388 let s = expect_str(args.first())?;
389 let required = required_field_names(args.get(1))?;
390 let schema = extract_type_schema(args.get(2));
391 match toml::from_str::<serde_json::Value>(&s) {
392 Ok(mut v) => {
393 unwrap_toml_datetime_markers(&mut v);
394 if let Err(e) = check_required_fields(&v, &required) {
395 return Ok(err_v(Value::Str(e.into())));
396 }
397 if let Err(e) = validate_field_types(&v, &schema) {
398 return Ok(err_v(Value::Str(e.into())));
399 }
400 Ok(ok_v(apply_option_wrapping(json_to_value(&v), &v, &schema)))
401 }
402 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
403 }
404 }
405 ("toml", "parse_strict_typed") => {
406 let s = expect_str(args.first())?;
407 let required = required_field_names(args.get(1))?;
408 let schema = extract_type_schema(args.get(2));
409 match toml::from_str::<serde_json::Value>(&s) {
410 Ok(mut v) => {
411 unwrap_toml_datetime_markers(&mut v);
412 if let Err(e) = check_required_fields(&v, &required) {
413 return Ok(err_v(Value::Str(e.into())));
414 }
415 if let Err(e) = validate_field_types(&v, &schema) {
416 return Ok(err_v(Value::Str(e.into())));
417 }
418 Ok(ok_v(apply_option_wrapping(json_to_value(&v), &v, &schema)))
419 }
420 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
421 }
422 }
423 ("toml", "stringify") => {
424 let v = first_arg(args)?;
425 let json = value_to_json(v);
431 match toml::to_string(&json) {
432 Ok(s) => Ok(ok_v(Value::Str(s.into()))),
433 Err(e) => Ok(err_v(Value::Str(format!("toml.stringify: {e}").into()))),
434 }
435 }
436
437 ("yaml", "parse") => {
443 let s = expect_str(args.first())?;
444 match serde_yaml::from_str::<serde_json::Value>(&s) {
445 Ok(v) => Ok(ok_v(json_to_value(&v))),
446 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
447 }
448 }
449 ("yaml", "parse_strict") => {
452 let s = expect_str(args.first())?;
453 let required = required_field_names(args.get(1))?;
454 let schema = extract_type_schema(args.get(2));
455 match serde_yaml::from_str::<serde_json::Value>(&s) {
456 Ok(v) => {
457 if let Err(e) = check_required_fields(&v, &required) {
458 return Ok(err_v(Value::Str(e.into())));
459 }
460 if let Err(e) = validate_field_types(&v, &schema) {
461 return Ok(err_v(Value::Str(e.into())));
462 }
463 Ok(ok_v(json_to_value(&v)))
464 }
465 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
466 }
467 }
468 ("yaml", "parse_strict_typed") => {
469 let s = expect_str(args.first())?;
470 let required = required_field_names(args.get(1))?;
471 let schema = extract_type_schema(args.get(2));
472 match serde_yaml::from_str::<serde_json::Value>(&s) {
473 Ok(v) => {
474 if let Err(e) = check_required_fields(&v, &required) {
475 return Ok(err_v(Value::Str(e.into())));
476 }
477 if let Err(e) = validate_field_types(&v, &schema) {
478 return Ok(err_v(Value::Str(e.into())));
479 }
480 Ok(ok_v(json_to_value(&v)))
481 }
482 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
483 }
484 }
485 ("yaml", "stringify") => {
486 let v = first_arg(args)?;
487 let json = value_to_json(v);
488 match serde_yaml::to_string(&json) {
489 Ok(s) => Ok(ok_v(Value::Str(s.into()))),
490 Err(e) => Ok(err_v(Value::Str(format!("yaml.stringify: {e}").into()))),
491 }
492 }
493
494 ("dotenv", "parse") => {
502 use std::collections::BTreeMap;
503 use lex_bytecode::MapKey;
504 let s = expect_str(args.first())?;
505 match parse_dotenv(&s) {
506 Ok(map) => {
507 let mut bt: BTreeMap<MapKey, Value> = BTreeMap::new();
508 for (k, v) in map {
509 bt.insert(MapKey::Str(k), Value::Str(v.into()));
510 }
511 Ok(ok_v(Value::Map(bt)))
512 }
513 Err(e) => Ok(err_v(Value::Str(e.into()))),
514 }
515 }
516
517 ("csv", "parse") => {
522 let s = expect_str(args.first())?;
523 let mut rdr = csv::ReaderBuilder::new()
524 .has_headers(false)
525 .flexible(true)
526 .from_reader(s.as_bytes());
527 let mut rows: std::collections::VecDeque<Value> = std::collections::VecDeque::new();
528 for r in rdr.records() {
529 match r {
530 Ok(rec) => {
531 let row: std::collections::VecDeque<Value> = rec.iter()
532 .map(|f| Value::Str(f.into()))
533 .collect();
534 rows.push_back(Value::List(row));
535 }
536 Err(e) => return Ok(err_v(Value::Str(format!("csv.parse: {e}").into()))),
537 }
538 }
539 Ok(ok_v(Value::List(rows)))
540 }
541 ("csv", "stringify") => {
542 let v = first_arg(args)?;
547 let rows = match v {
548 Value::List(rs) => rs,
549 _ => return Ok(err_v(Value::Str("csv.stringify expects List[List[Str]]".into()))),
550 };
551 let mut out = Vec::new();
552 {
553 let mut wtr = csv::WriterBuilder::new()
554 .has_headers(false)
555 .from_writer(&mut out);
556 for row in rows {
557 let cells = match row {
558 Value::List(cs) => cs,
559 _ => return Ok(err_v(Value::Str("csv.stringify row must be List[Str]".into()))),
560 };
561 let strs: Vec<String> = cells.iter().map(|c| match c {
562 Value::Str(s) => s.to_string(),
563 other => serde_json::to_string(&other.to_json())
564 .unwrap_or_else(|_| String::new()),
565 }).collect();
566 if let Err(e) = wtr.write_record(&strs) {
567 return Ok(err_v(Value::Str(format!("csv.stringify: {e}").into())));
568 }
569 }
570 if let Err(e) = wtr.flush() {
571 return Ok(err_v(Value::Str(format!("csv.stringify flush: {e}").into())));
572 }
573 }
574 match String::from_utf8(out) {
575 Ok(s) => Ok(ok_v(Value::Str(s.into()))),
576 Err(e) => Ok(err_v(Value::Str(format!("csv.stringify utf8: {e}").into()))),
577 }
578 }
579
580 ("test", "assert_eq") => {
587 let a = first_arg(args)?;
588 let b = args.get(1).ok_or("test.assert_eq: missing second arg")?;
589 if a == b {
590 Ok(ok_v(Value::Unit))
591 } else {
592 Ok(err_v(Value::Str(format!("assert_eq: lhs {} != rhs {}",
593 value_to_json(a), value_to_json(b)).into())))
594 }
595 }
596 ("test", "assert_ne") => {
597 let a = first_arg(args)?;
598 let b = args.get(1).ok_or("test.assert_ne: missing second arg")?;
599 if a != b {
600 Ok(ok_v(Value::Unit))
601 } else {
602 Ok(err_v(Value::Str(format!("assert_ne: both sides are {}",
603 value_to_json(a)).into())))
604 }
605 }
606 ("test", "assert_true") => {
607 match first_arg(args)? {
608 Value::Bool(true) => Ok(ok_v(Value::Unit)),
609 Value::Bool(false) => Ok(err_v(Value::Str("assert_true: was false".into()))),
610 other => Err(format!("test.assert_true expects Bool, got {other:?}")),
611 }
612 }
613 ("test", "assert_false") => {
614 match first_arg(args)? {
615 Value::Bool(false) => Ok(ok_v(Value::Unit)),
616 Value::Bool(true) => Ok(err_v(Value::Str("assert_false: was true".into()))),
617 other => Err(format!("test.assert_false expects Bool, got {other:?}")),
618 }
619 }
620
621 ("bytes", "len") => {
623 let b = expect_bytes(args.first())?;
624 Ok(Value::Int(b.len() as i64))
625 }
626 ("bytes", "eq") => {
627 let a = expect_bytes(args.first())?;
628 let b = expect_bytes(args.get(1))?;
629 Ok(Value::Bool(a == b))
630 }
631 ("bytes", "from_str") => {
632 let s = expect_str(args.first())?;
633 Ok(Value::Bytes(s.into_bytes()))
634 }
635 ("bytes", "to_str") => {
636 let b = expect_bytes(args.first())?;
637 match String::from_utf8(b.to_vec()) {
638 Ok(s) => Ok(ok_v(Value::Str(s.into()))),
639 Err(e) => Ok(err_v(Value::Str(format!("{e}").into()))),
640 }
641 }
642 ("bytes", "slice") => {
643 let b = expect_bytes(args.first())?;
644 let lo = expect_int(args.get(1))? as usize;
645 let hi = expect_int(args.get(2))? as usize;
646 if lo > hi || hi > b.len() {
647 return Err(format!("bytes.slice: out of range [{lo}..{hi}] of {}", b.len()));
648 }
649 Ok(Value::Bytes(b[lo..hi].to_vec()))
650 }
651 ("bytes", "is_empty") => {
652 let b = expect_bytes(args.first())?;
653 Ok(Value::Bool(b.is_empty()))
654 }
655
656 ("math", "exp") => Ok(Value::Float(expect_float(args.first())?.exp())),
663 ("math", "log") => Ok(Value::Float(expect_float(args.first())?.ln())),
664 ("math", "log2") => Ok(Value::Float(expect_float(args.first())?.log2())),
665 ("math", "log10") => Ok(Value::Float(expect_float(args.first())?.log10())),
666 ("math", "sqrt") => Ok(Value::Float(expect_float(args.first())?.sqrt())),
667 ("math", "abs") => Ok(Value::Float(expect_float(args.first())?.abs())),
668 ("math", "sin") => Ok(Value::Float(expect_float(args.first())?.sin())),
669 ("math", "cos") => Ok(Value::Float(expect_float(args.first())?.cos())),
670 ("math", "tan") => Ok(Value::Float(expect_float(args.first())?.tan())),
671 ("math", "asin") => Ok(Value::Float(expect_float(args.first())?.asin())),
672 ("math", "acos") => Ok(Value::Float(expect_float(args.first())?.acos())),
673 ("math", "atan") => Ok(Value::Float(expect_float(args.first())?.atan())),
674 ("math", "floor") => Ok(Value::Float(expect_float(args.first())?.floor())),
675 ("math", "ceil") => Ok(Value::Float(expect_float(args.first())?.ceil())),
676 ("math", "round") => Ok(Value::Float(expect_float(args.first())?.round())),
677 ("math", "trunc") => Ok(Value::Float(expect_float(args.first())?.trunc())),
678 ("math", "pow") => {
679 let a = expect_float(args.first())?;
680 let b = expect_float(args.get(1))?;
681 Ok(Value::Float(a.powf(b)))
682 }
683 ("math", "atan2") => {
684 let y = expect_float(args.first())?;
685 let x = expect_float(args.get(1))?;
686 Ok(Value::Float(y.atan2(x)))
687 }
688 ("math", "min") => {
689 let a = expect_float(args.first())?;
690 let b = expect_float(args.get(1))?;
691 Ok(Value::Float(a.min(b)))
692 }
693 ("math", "max") => {
694 let a = expect_float(args.first())?;
695 let b = expect_float(args.get(1))?;
696 Ok(Value::Float(a.max(b)))
697 }
698 ("math", "zeros") => {
699 let r = expect_int(args.first())?;
700 let c = expect_int(args.get(1))?;
701 if r < 0 || c < 0 {
702 return Err(format!("math.zeros: negative dim {r}x{c}"));
703 }
704 let r = r as usize; let c = c as usize;
705 Ok(Value::F64Array { rows: r as u32, cols: c as u32, data: vec![0.0; r * c] })
706 }
707 ("math", "ones") => {
708 let r = expect_int(args.first())?;
709 let c = expect_int(args.get(1))?;
710 if r < 0 || c < 0 {
711 return Err(format!("math.ones: negative dim {r}x{c}"));
712 }
713 let r = r as usize; let c = c as usize;
714 Ok(Value::F64Array { rows: r as u32, cols: c as u32, data: vec![1.0; r * c] })
715 }
716 ("math", "from_lists") => {
717 let rows = expect_list(args.first())?;
718 let r = rows.len();
719 if r == 0 {
720 return Ok(Value::F64Array { rows: 0, cols: 0, data: Vec::new() });
721 }
722 let first_row = match &rows[0] {
723 Value::List(xs) => xs,
724 other => return Err(format!("math.from_lists: row 0 not List, got {other:?}")),
725 };
726 let c = first_row.len();
727 let mut data = Vec::with_capacity(r * c);
728 for (i, row) in rows.iter().enumerate() {
729 let row = match row {
730 Value::List(xs) => xs,
731 other => return Err(format!("math.from_lists: row {i} not List, got {other:?}")),
732 };
733 if row.len() != c {
734 return Err(format!("math.from_lists: row {i} has {} cols, expected {c}", row.len()));
735 }
736 for (j, v) in row.iter().enumerate() {
737 let f = match v {
738 Value::Float(f) => *f,
739 Value::Int(n) => *n as f64,
740 other => return Err(format!("math.from_lists: ({i},{j}) not numeric, got {other:?}")),
741 };
742 data.push(f);
743 }
744 }
745 Ok(Value::F64Array { rows: r as u32, cols: c as u32, data })
746 }
747 ("math", "from_flat") => {
748 let r = expect_int(args.first())?;
749 let c = expect_int(args.get(1))?;
750 let xs = expect_list(args.get(2))?;
751 if r < 0 || c < 0 {
752 return Err(format!("math.from_flat: negative dim {r}x{c}"));
753 }
754 let r = r as usize; let c = c as usize;
755 if xs.len() != r * c {
756 return Err(format!("math.from_flat: list len {} != {}*{}", xs.len(), r, c));
757 }
758 let mut data = Vec::with_capacity(r * c);
759 for v in xs {
760 data.push(match v {
761 Value::Float(f) => *f,
762 Value::Int(n) => *n as f64,
763 other => return Err(format!("math.from_flat: non-numeric element {other:?}")),
764 });
765 }
766 Ok(Value::F64Array { rows: r as u32, cols: c as u32, data })
767 }
768 ("math", "rows") => {
769 let (r, _, _) = unpack_matrix(first_arg(args)?)?;
770 Ok(Value::Int(r as i64))
771 }
772 ("math", "cols") => {
773 let (_, c, _) = unpack_matrix(first_arg(args)?)?;
774 Ok(Value::Int(c as i64))
775 }
776 ("math", "get") => {
777 let (r, c, data) = unpack_matrix(first_arg(args)?)?;
778 let i = expect_int(args.get(1))? as usize;
779 let j = expect_int(args.get(2))? as usize;
780 if i >= r || j >= c {
781 return Err(format!("math.get: ({i},{j}) out of {r}x{c}"));
782 }
783 Ok(Value::Float(data[i * c + j]))
784 }
785 ("math", "to_flat") => {
786 let (_, _, data) = unpack_matrix(first_arg(args)?)?;
787 Ok(Value::List(data.into_iter().map(Value::Float).collect()))
788 }
789 ("math", "transpose") => {
790 let (r, c, data) = unpack_matrix(first_arg(args)?)?;
791 let mut out = vec![0.0; r * c];
792 for i in 0..r {
793 for j in 0..c {
794 out[j * r + i] = data[i * c + j];
795 }
796 }
797 Ok(Value::F64Array { rows: c as u32, cols: r as u32, data: out })
798 }
799 ("math", "matmul") => {
800 let (m, k1, a) = unpack_matrix(first_arg(args)?)?;
801 let (k2, n, b) = unpack_matrix(args.get(1).ok_or("math.matmul: missing arg 1")?)?;
802 if k1 != k2 {
803 return Err(format!("math.matmul: dim mismatch {m}x{k1} · {k2}x{n}"));
804 }
805 let mut c = vec![0.0; m * n];
809 for i in 0..m {
810 for kk in 0..k1 {
811 let aik = a[i * k1 + kk];
812 for j in 0..n {
813 c[i * n + j] += aik * b[kk * n + j];
814 }
815 }
816 }
817 Ok(Value::F64Array { rows: m as u32, cols: n as u32, data: c })
818 }
819 ("math", "scale") => {
820 let s = expect_float(args.first())?;
821 let (r, c, mut data) = unpack_matrix(args.get(1).ok_or("math.scale: missing arg 1")?)?;
822 for x in &mut data { *x *= s; }
823 Ok(Value::F64Array { rows: r as u32, cols: c as u32, data })
824 }
825 ("math", "add") | ("math", "sub") => {
826 let (ar, ac, a) = unpack_matrix(first_arg(args)?)?;
827 let (br, bc, b) = unpack_matrix(args.get(1).ok_or("math.add/sub: missing arg 1")?)?;
828 if ar != br || ac != bc {
829 return Err(format!("math.{op}: shape mismatch {ar}x{ac} vs {br}x{bc}"));
830 }
831 let neg = op == "sub";
832 let mut out = a;
833 for (i, x) in out.iter_mut().enumerate() {
834 if neg { *x -= b[i] } else { *x += b[i] }
835 }
836 Ok(Value::F64Array { rows: ar as u32, cols: ac as u32, data: out })
837 }
838 ("math", "sigmoid") => {
839 let (r, c, mut data) = unpack_matrix(first_arg(args)?)?;
840 for x in &mut data { *x = 1.0 / (1.0 + (-*x).exp()); }
841 Ok(Value::F64Array { rows: r as u32, cols: c as u32, data })
842 }
843
844 ("map", "new") => Ok(Value::Map(BTreeMap::new())),
846 ("map", "size") => Ok(Value::Int(expect_map(args.first())?.len() as i64)),
847 ("map", "has") => {
848 let m = expect_map(args.first())?;
849 let k = MapKey::from_value(args.get(1).ok_or("map.has: missing key")?)?;
850 Ok(Value::Bool(m.contains_key(&k)))
851 }
852 ("map", "get") => {
853 let m = expect_map(args.first())?;
854 let k = MapKey::from_value(args.get(1).ok_or("map.get: missing key")?)?;
855 Ok(match m.get(&k) {
856 Some(v) => some(v.clone()),
857 None => none(),
858 })
859 }
860 ("map", "set") => {
861 let mut m = expect_map(args.first())?.clone();
862 let k = MapKey::from_value(args.get(1).ok_or("map.set: missing key")?)?;
863 let v = args.get(2).ok_or("map.set: missing value")?.clone();
864 m.insert(k, v);
865 Ok(Value::Map(m))
866 }
867 ("map", "delete") => {
868 let mut m = expect_map(args.first())?.clone();
869 let k = MapKey::from_value(args.get(1).ok_or("map.delete: missing key")?)?;
870 m.remove(&k);
871 Ok(Value::Map(m))
872 }
873 ("map", "keys") => {
874 let m = expect_map(args.first())?;
875 Ok(Value::List(m.keys().cloned().map(MapKey::into_value).collect()))
876 }
877 ("map", "values") => {
878 let m = expect_map(args.first())?;
879 Ok(Value::List(m.values().cloned().collect()))
880 }
881 ("map", "entries") => {
882 let m = expect_map(args.first())?;
883 Ok(Value::List(m.iter()
884 .map(|(k, v)| Value::Tuple(vec![k.as_value(), v.clone()]))
885 .collect()))
886 }
887 ("map", "from_list") => {
888 let pairs = expect_list(args.first())?;
889 let mut m = BTreeMap::new();
890 for p in pairs {
891 let items = match p {
892 Value::Tuple(items) if items.len() == 2 => items,
893 other => return Err(format!(
894 "map.from_list element must be a 2-tuple, got {other:?}")),
895 };
896 let k = MapKey::from_value(&items[0])?;
897 m.insert(k, items[1].clone());
898 }
899 Ok(Value::Map(m))
900 }
901
902 ("set", "new") => Ok(Value::Set(BTreeSet::new())),
904 ("set", "size") => Ok(Value::Int(expect_set(args.first())?.len() as i64)),
905 ("set", "has") => {
906 let s = expect_set(args.first())?;
907 let k = MapKey::from_value(args.get(1).ok_or("set.has: missing element")?)?;
908 Ok(Value::Bool(s.contains(&k)))
909 }
910 ("set", "add") => {
911 let mut s = expect_set(args.first())?.clone();
912 let k = MapKey::from_value(args.get(1).ok_or("set.add: missing element")?)?;
913 s.insert(k);
914 Ok(Value::Set(s))
915 }
916 ("set", "delete") => {
917 let mut s = expect_set(args.first())?.clone();
918 let k = MapKey::from_value(args.get(1).ok_or("set.delete: missing element")?)?;
919 s.remove(&k);
920 Ok(Value::Set(s))
921 }
922 ("set", "to_list") => {
923 let s = expect_set(args.first())?;
924 Ok(Value::List(s.iter().cloned().map(MapKey::into_value).collect()))
925 }
926 ("set", "from_list") => {
927 let xs = expect_list(args.first())?;
928 let mut s = BTreeSet::new();
929 for x in xs {
930 s.insert(MapKey::from_value(x)?);
931 }
932 Ok(Value::Set(s))
933 }
934 ("set", "union") => {
935 let a = expect_set(args.first())?;
936 let b = expect_set(args.get(1))?;
937 Ok(Value::Set(a.union(b).cloned().collect()))
938 }
939 ("set", "intersect") => {
940 let a = expect_set(args.first())?;
941 let b = expect_set(args.get(1))?;
942 Ok(Value::Set(a.intersection(b).cloned().collect()))
943 }
944 ("set", "diff") => {
945 let a = expect_set(args.first())?;
946 let b = expect_set(args.get(1))?;
947 Ok(Value::Set(a.difference(b).cloned().collect()))
948 }
949 ("set", "is_empty") => Ok(Value::Bool(expect_set(args.first())?.is_empty())),
950 ("set", "is_subset") => {
951 let a = expect_set(args.first())?;
952 let b = expect_set(args.get(1))?;
953 Ok(Value::Bool(a.is_subset(b)))
954 }
955
956 ("map", "merge") => {
958 let a = expect_map(args.first())?.clone();
961 let b = expect_map(args.get(1))?;
962 let mut out = a;
963 for (k, v) in b {
964 out.insert(k.clone(), v.clone());
965 }
966 Ok(Value::Map(out))
967 }
968 ("map", "is_empty") => Ok(Value::Bool(expect_map(args.first())?.is_empty())),
969
970 ("deque", "new") => Ok(Value::Deque(std::collections::VecDeque::new())),
972 ("deque", "size") => Ok(Value::Int(expect_deque(args.first())?.len() as i64)),
973 ("deque", "is_empty") => Ok(Value::Bool(expect_deque(args.first())?.is_empty())),
974 ("deque", "push_back") => {
975 let mut d = expect_deque(args.first())?.clone();
976 let x = args.get(1).ok_or("deque.push_back: missing value")?.clone();
977 d.push_back(x);
978 Ok(Value::Deque(d))
979 }
980 ("deque", "push_front") => {
981 let mut d = expect_deque(args.first())?.clone();
982 let x = args.get(1).ok_or("deque.push_front: missing value")?.clone();
983 d.push_front(x);
984 Ok(Value::Deque(d))
985 }
986 ("deque", "pop_back") => {
987 let mut d = expect_deque(args.first())?.clone();
988 match d.pop_back() {
989 Some(x) => Ok(Value::Variant {
990 name: "Some".into(),
991 args: vec![Value::Tuple(vec![x, Value::Deque(d)])],
992 }),
993 None => Ok(Value::Variant { name: "None".into(), args: vec![] }),
994 }
995 }
996 ("deque", "pop_front") => {
997 let mut d = expect_deque(args.first())?.clone();
998 match d.pop_front() {
999 Some(x) => Ok(Value::Variant {
1000 name: "Some".into(),
1001 args: vec![Value::Tuple(vec![x, Value::Deque(d)])],
1002 }),
1003 None => Ok(Value::Variant { name: "None".into(), args: vec![] }),
1004 }
1005 }
1006 ("deque", "peek_back") => {
1007 let d = expect_deque(args.first())?;
1008 match d.back() {
1009 Some(x) => Ok(Value::Variant {
1010 name: "Some".into(),
1011 args: vec![x.clone()],
1012 }),
1013 None => Ok(Value::Variant { name: "None".into(), args: vec![] }),
1014 }
1015 }
1016 ("deque", "peek_front") => {
1017 let d = expect_deque(args.first())?;
1018 match d.front() {
1019 Some(x) => Ok(Value::Variant {
1020 name: "Some".into(),
1021 args: vec![x.clone()],
1022 }),
1023 None => Ok(Value::Variant { name: "None".into(), args: vec![] }),
1024 }
1025 }
1026 ("deque", "from_list") => {
1027 let xs = expect_list(args.first())?;
1028 Ok(Value::Deque(xs.iter().cloned().collect()))
1029 }
1030 ("deque", "to_list") => {
1031 let d = expect_deque(args.first())?;
1032 Ok(Value::List(d.iter().cloned().collect()))
1033 }
1034
1035 ("crypto", "sha256") => {
1038 use sha2::{Digest, Sha256};
1039 let data = expect_bytes(args.first())?;
1040 let mut h = Sha256::new();
1041 h.update(data);
1042 Ok(Value::Bytes(h.finalize().to_vec()))
1043 }
1044 ("crypto", "sha512") => {
1045 use sha2::{Digest, Sha512};
1046 let data = expect_bytes(args.first())?;
1047 let mut h = Sha512::new();
1048 h.update(data);
1049 Ok(Value::Bytes(h.finalize().to_vec()))
1050 }
1051 ("crypto", "md5") => {
1052 use md5::{Digest, Md5};
1053 let data = expect_bytes(args.first())?;
1054 let mut h = Md5::new();
1055 h.update(data);
1056 Ok(Value::Bytes(h.finalize().to_vec()))
1057 }
1058 ("crypto", "blake2b") => {
1062 use blake2::{Blake2b512, Digest};
1063 let data = expect_bytes(args.first())?;
1064 let mut h = Blake2b512::new();
1065 h.update(data);
1066 Ok(Value::Bytes(h.finalize().to_vec()))
1067 }
1068 ("crypto", "keccak256") => {
1073 use sha3::{Digest, Keccak256};
1074 let data = expect_bytes(args.first())?;
1075 let mut h = Keccak256::new();
1076 h.update(data);
1077 Ok(Value::Bytes(h.finalize().to_vec()))
1078 }
1079 ("crypto", "sha256_str") => {
1083 use sha2::{Digest, Sha256};
1084 let s = expect_str(args.first())?;
1085 let mut h = Sha256::new();
1086 h.update(s.as_bytes());
1087 Ok(Value::Str(hex::encode(h.finalize()).into()))
1088 }
1089 ("crypto", "sha512_str") => {
1090 use sha2::{Digest, Sha512};
1091 let s = expect_str(args.first())?;
1092 let mut h = Sha512::new();
1093 h.update(s.as_bytes());
1094 Ok(Value::Str(hex::encode(h.finalize()).into()))
1095 }
1096 ("crypto", "hmac_sha256") => {
1097 use hmac::{Hmac, KeyInit, Mac};
1098 type HmacSha256 = Hmac<sha2::Sha256>;
1099 let key = expect_bytes(args.first())?;
1100 let data = expect_bytes(args.get(1))?;
1101 let mut mac = HmacSha256::new_from_slice(key)
1102 .map_err(|e| format!("hmac_sha256 key: {e}"))?;
1103 mac.update(data);
1104 Ok(Value::Bytes(mac.finalize().into_bytes().to_vec()))
1105 }
1106 ("crypto", "hmac_sha512") => {
1107 use hmac::{Hmac, KeyInit, Mac};
1108 type HmacSha512 = Hmac<sha2::Sha512>;
1109 let key = expect_bytes(args.first())?;
1110 let data = expect_bytes(args.get(1))?;
1111 let mut mac = HmacSha512::new_from_slice(key)
1112 .map_err(|e| format!("hmac_sha512 key: {e}"))?;
1113 mac.update(data);
1114 Ok(Value::Bytes(mac.finalize().into_bytes().to_vec()))
1115 }
1116 ("crypto", "ed25519_public_key") => {
1120 use ed25519_dalek::SigningKey;
1121 let secret = expect_bytes(args.first())?;
1122 let seed: [u8; 32] = match secret.as_slice().try_into() {
1123 Ok(s) => s,
1124 Err(_) => return Ok(err_v(Value::Str("ed25519_public_key: secret must be 32 bytes".into()))),
1125 };
1126 let sk = SigningKey::from_bytes(&seed);
1127 Ok(ok_v(Value::Bytes(sk.verifying_key().to_bytes().to_vec())))
1128 }
1129 ("crypto", "ed25519_sign") => {
1130 use ed25519_dalek::{Signer, SigningKey};
1131 let secret = expect_bytes(args.first())?;
1132 let message = expect_bytes(args.get(1))?;
1133 let seed: [u8; 32] = match secret.as_slice().try_into() {
1134 Ok(s) => s,
1135 Err(_) => return Ok(err_v(Value::Str("ed25519_sign: secret must be 32 bytes".into()))),
1136 };
1137 let sk = SigningKey::from_bytes(&seed);
1138 Ok(ok_v(Value::Bytes(sk.sign(message).to_bytes().to_vec())))
1139 }
1140 ("crypto", "ed25519_verify") => {
1141 use ed25519_dalek::{Signature, Verifier, VerifyingKey};
1142 let public = expect_bytes(args.first())?;
1143 let message = expect_bytes(args.get(1))?;
1144 let sig_bytes = expect_bytes(args.get(2))?;
1145 let pk_arr: [u8; 32] = match public.as_slice().try_into() {
1146 Ok(p) => p,
1147 Err(_) => return Ok(Value::Bool(false)),
1148 };
1149 let sig_arr: [u8; 64] = match sig_bytes.as_slice().try_into() {
1150 Ok(s) => s,
1151 Err(_) => return Ok(Value::Bool(false)),
1152 };
1153 let vk = match VerifyingKey::from_bytes(&pk_arr) {
1154 Ok(v) => v,
1155 Err(_) => return Ok(Value::Bool(false)),
1156 };
1157 let sig = Signature::from_bytes(&sig_arr);
1158 Ok(Value::Bool(vk.verify(message, &sig).is_ok()))
1159 }
1160 ("crypto", "p256_public_key") => {
1172 use p256::ecdsa::SigningKey;
1173 let secret = expect_bytes(args.first())?;
1174 let sk = match SigningKey::from_slice(secret) {
1175 Ok(k) => k,
1176 Err(_) => return Ok(err_v(Value::Str(
1177 "p256_public_key: secret must be a 32-byte P-256 scalar".into()))),
1178 };
1179 let point = sk.verifying_key().to_encoded_point(true);
1180 Ok(ok_v(Value::Bytes(point.as_bytes().to_vec())))
1181 }
1182 ("crypto", "p256_sign") => {
1183 use p256::ecdsa::{signature::Signer, Signature, SigningKey};
1184 let secret = expect_bytes(args.first())?;
1185 let message = expect_bytes(args.get(1))?;
1186 let sk = match SigningKey::from_slice(secret) {
1187 Ok(k) => k,
1188 Err(_) => return Ok(err_v(Value::Str(
1189 "p256_sign: secret must be a 32-byte P-256 scalar".into()))),
1190 };
1191 let sig: Signature = sk.sign(message);
1192 Ok(ok_v(Value::Bytes(sig.to_der().as_bytes().to_vec())))
1193 }
1194 ("crypto", "p256_verify") => {
1195 use p256::ecdsa::{signature::Verifier, Signature, VerifyingKey};
1196 let public = expect_bytes(args.first())?;
1197 let message = expect_bytes(args.get(1))?;
1198 let sig_bytes = expect_bytes(args.get(2))?;
1199 let vk = match VerifyingKey::from_sec1_bytes(public) {
1200 Ok(v) => v,
1201 Err(_) => return Ok(Value::Bool(false)),
1202 };
1203 let sig = match Signature::from_der(sig_bytes) {
1204 Ok(s) => s,
1205 Err(_) => return Ok(Value::Bool(false)),
1206 };
1207 Ok(Value::Bool(vk.verify(message, &sig).is_ok()))
1208 }
1209 ("crypto", "secp256k1_public_key") => {
1220 use k256::ecdsa::SigningKey;
1221 let secret = expect_bytes(args.first())?;
1222 let sk = match SigningKey::from_slice(secret) {
1223 Ok(k) => k,
1224 Err(_) => return Ok(err_v(Value::Str(
1225 "secp256k1_public_key: secret must be a 32-byte secp256k1 scalar".into()))),
1226 };
1227 let point = sk.verifying_key().to_encoded_point(false);
1230 Ok(ok_v(Value::Bytes(point.as_bytes().to_vec())))
1231 }
1232 ("crypto", "secp256k1_sign_digest") => {
1233 use k256::ecdsa::SigningKey;
1234 let secret = expect_bytes(args.first())?;
1235 let digest = expect_bytes(args.get(1))?;
1236 if digest.len() != 32 {
1237 return Ok(err_v(Value::Str(
1238 "secp256k1_sign_digest: digest must be exactly 32 bytes".into())));
1239 }
1240 let sk = match SigningKey::from_slice(secret) {
1241 Ok(k) => k,
1242 Err(_) => return Ok(err_v(Value::Str(
1243 "secp256k1_sign_digest: secret must be a 32-byte secp256k1 scalar".into()))),
1244 };
1245 match sk.sign_prehash_recoverable(digest) {
1248 Ok((sig, recid)) => {
1249 let mut out = sig.to_bytes().to_vec(); out.push(27u8 + recid.to_byte());
1251 Ok(ok_v(Value::Bytes(out)))
1252 }
1253 Err(e) => Ok(err_v(Value::Str(
1254 format!("secp256k1_sign_digest: {e}").into()))),
1255 }
1256 }
1257 ("crypto", "secp256k1_recover") => {
1258 use k256::ecdsa::{RecoveryId, Signature, VerifyingKey};
1259 let digest = expect_bytes(args.first())?;
1260 let sig_bytes = expect_bytes(args.get(1))?;
1261 if digest.len() != 32 {
1262 return Ok(err_v(Value::Str(
1263 "secp256k1_recover: digest must be exactly 32 bytes".into())));
1264 }
1265 if sig_bytes.len() != 65 {
1266 return Ok(err_v(Value::Str(
1267 "secp256k1_recover: signature must be 65 bytes (r‖s‖v)".into())));
1268 }
1269 let sig = match Signature::from_slice(&sig_bytes[..64]) {
1270 Ok(s) => s,
1271 Err(_) => return Ok(err_v(Value::Str(
1272 "secp256k1_recover: malformed r‖s".into()))),
1273 };
1274 let v = sig_bytes[64];
1276 let recid_byte = if v >= 27 { v - 27 } else { v };
1277 let recid = match RecoveryId::from_byte(recid_byte) {
1278 Some(r) => r,
1279 None => return Ok(err_v(Value::Str(
1280 "secp256k1_recover: invalid recovery id".into()))),
1281 };
1282 match VerifyingKey::recover_from_prehash(digest, &sig, recid) {
1283 Ok(vk) => Ok(ok_v(Value::Bytes(
1284 vk.to_encoded_point(false).as_bytes().to_vec()))),
1285 Err(e) => Ok(err_v(Value::Str(
1286 format!("secp256k1_recover: {e}").into()))),
1287 }
1288 }
1289 ("crypto", "secp256k1_verify") => {
1290 use k256::ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey};
1291 let public = expect_bytes(args.first())?;
1292 let digest = expect_bytes(args.get(1))?;
1293 let sig_bytes = expect_bytes(args.get(2))?;
1294 if digest.len() != 32 {
1295 return Ok(Value::Bool(false));
1296 }
1297 let vk = match VerifyingKey::from_sec1_bytes(public) {
1298 Ok(v) => v,
1299 Err(_) => return Ok(Value::Bool(false)),
1300 };
1301 let rs = if sig_bytes.len() == 65 { &sig_bytes[..64] } else { sig_bytes.as_slice() };
1303 let sig = match Signature::from_slice(rs) {
1304 Ok(s) => s,
1305 Err(_) => return Ok(Value::Bool(false)),
1306 };
1307 Ok(Value::Bool(vk.verify_prehash(digest, &sig).is_ok()))
1308 }
1309 ("crypto", "base64_encode") => {
1310 use base64::{Engine, engine::general_purpose::STANDARD};
1311 let data = expect_bytes(args.first())?;
1312 Ok(Value::Str(STANDARD.encode(data).into()))
1313 }
1314 ("crypto", "base64_decode") => {
1315 use base64::{Engine, engine::general_purpose::STANDARD};
1316 let s = expect_str(args.first())?;
1317 match STANDARD.decode(s) {
1318 Ok(b) => Ok(ok_v(Value::Bytes(b))),
1319 Err(e) => Ok(err_v(Value::Str(format!("base64: {e}").into()))),
1320 }
1321 }
1322 ("crypto", "base64url_encode") => {
1326 use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
1327 let data = expect_bytes(args.first())?;
1328 Ok(Value::Str(URL_SAFE_NO_PAD.encode(data).into()))
1329 }
1330 ("crypto", "base64url_decode") => {
1331 use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
1332 let s = expect_str(args.first())?;
1333 match URL_SAFE_NO_PAD.decode(s) {
1334 Ok(b) => Ok(ok_v(Value::Bytes(b))),
1335 Err(e) => Ok(err_v(Value::Str(format!("base64url: {e}").into()))),
1336 }
1337 }
1338 ("crypto", "hex_encode") => {
1339 let data = expect_bytes(args.first())?;
1340 Ok(Value::Str(hex::encode(data).into()))
1341 }
1342 ("crypto", "hex_decode") => {
1343 let s = expect_str(args.first())?;
1344 match hex::decode(s) {
1345 Ok(b) => Ok(ok_v(Value::Bytes(b))),
1346 Err(e) => Ok(err_v(Value::Str(format!("hex: {e}").into()))),
1347 }
1348 }
1349 ("crypto", "base58_encode") => {
1353 let data = expect_bytes(args.first())?;
1354 Ok(Value::Str(bs58::encode(data).into_string().into()))
1355 }
1356 ("crypto", "base58_decode") => {
1357 let s = expect_str(args.first())?;
1358 match bs58::decode(s).into_vec() {
1359 Ok(b) => Ok(ok_v(Value::Bytes(b))),
1360 Err(e) => Ok(err_v(Value::Str(format!("base58: {e}").into()))),
1361 }
1362 }
1363 ("crypto", "constant_time_eq") | ("crypto", "eq") => {
1364 use subtle::ConstantTimeEq;
1365 let a = expect_bytes(args.first())?;
1366 let b = expect_bytes(args.get(1))?;
1367 let eq = if a.len() == b.len() {
1376 a.ct_eq(b).into()
1377 } else {
1378 false
1379 };
1380 Ok(Value::Bool(eq))
1381 }
1382 ("crypto", "eq_str") => {
1385 use subtle::ConstantTimeEq;
1386 let a = expect_str(args.first())?;
1387 let b = expect_str(args.get(1))?;
1388 let eq = if a.len() == b.len() {
1389 a.as_bytes().ct_eq(b.as_bytes()).into()
1390 } else {
1391 false
1392 };
1393 Ok(Value::Bool(eq))
1394 }
1395
1396 ("crypto", "aes_gcm_seal") => Ok(aes_gcm_seal_impl(args)),
1406 ("crypto", "aes_gcm_open") => Ok(aes_gcm_open_impl(args)),
1407 ("crypto", "chacha20_poly1305_seal") => Ok(chacha20_seal_impl(args)),
1408 ("crypto", "chacha20_poly1305_open") => Ok(chacha20_open_impl(args)),
1409 ("crypto", "pbkdf2_sha256") => Ok(pbkdf2_sha256_impl(args)),
1410 ("crypto", "hkdf_sha256") => Ok(hkdf_sha256_impl(args)),
1411 ("crypto", "argon2id") => Ok(argon2id_impl(args)),
1412
1413 ("random", "seed") => {
1420 let s = args.first().ok_or("random.seed: missing arg")?.as_int();
1421 let mixed = splitmix64(s as u64).0;
1426 Ok(rng_value(mixed))
1427 }
1428 ("random", "int") => {
1429 let state = rng_decode(args.first())?;
1430 let lo = args.get(1).ok_or("random.int: missing lo")?.as_int();
1431 let hi = args.get(2).ok_or("random.int: missing hi")?.as_int();
1432 if hi < lo {
1433 return Err(format!(
1434 "random.int: hi ({hi}) must be >= lo ({lo})"));
1435 }
1436 let span = (hi as i128) - (lo as i128) + 1;
1437 let (raw, next_state) = splitmix64(state);
1438 let drawn = lo as i128 + (raw as u128 % span as u128) as i128;
1443 Ok(Value::Tuple(vec![
1444 Value::Int(drawn as i64),
1445 rng_value(next_state),
1446 ]))
1447 }
1448 ("random", "float") => {
1449 let state = rng_decode(args.first())?;
1450 let (raw, next_state) = splitmix64(state);
1451 let f = ((raw >> 11) as f64) / ((1u64 << 53) as f64);
1454 Ok(Value::Tuple(vec![Value::Float(f), rng_value(next_state)]))
1455 }
1456 ("random", "choose") => {
1457 let state = rng_decode(args.first())?;
1458 let xs = match args.get(1) {
1459 Some(Value::List(xs)) => xs,
1460 _ => return Err("random.choose: expected List".into()),
1461 };
1462 if xs.is_empty() {
1463 return Ok(Value::Variant {
1464 name: "None".into(), args: vec![],
1465 });
1466 }
1467 let (raw, next_state) = splitmix64(state);
1468 let idx = (raw as usize) % xs.len();
1469 let pick = xs[idx].clone();
1470 Ok(Value::Variant {
1471 name: "Some".into(),
1472 args: vec![Value::Tuple(vec![pick, rng_value(next_state)])],
1473 })
1474 }
1475
1476 ("parser", "char") => {
1481 let s = expect_str(args.first())?;
1482 if s.chars().count() != 1 {
1483 return Err(format!(
1484 "parser.char: expected 1-character string, got {s:?}"));
1485 }
1486 Ok(parser_node("Char", &[("ch", Value::Str(s.into()))]))
1487 }
1488 ("parser", "string") => {
1489 let s = expect_str(args.first())?;
1490 Ok(parser_node("String", &[("s", Value::Str(s.into()))]))
1491 }
1492 ("parser", "digit") => Ok(parser_node("Digit", &[])),
1493 ("parser", "alpha") => Ok(parser_node("Alpha", &[])),
1494 ("parser", "whitespace") => Ok(parser_node("Whitespace", &[])),
1495 ("parser", "eof") => Ok(parser_node("Eof", &[])),
1496 ("parser", "seq") => {
1497 let a = args.first().cloned()
1498 .ok_or_else(|| "parser.seq: missing first parser".to_string())?;
1499 let b = args.get(1).cloned()
1500 .ok_or_else(|| "parser.seq: missing second parser".to_string())?;
1501 Ok(parser_node("Seq", &[("a", a), ("b", b)]))
1502 }
1503 ("parser", "alt") => {
1504 let a = args.first().cloned()
1505 .ok_or_else(|| "parser.alt: missing first parser".to_string())?;
1506 let b = args.get(1).cloned()
1507 .ok_or_else(|| "parser.alt: missing second parser".to_string())?;
1508 Ok(parser_node("Alt", &[("a", a), ("b", b)]))
1509 }
1510 ("parser", "many") => {
1511 let p = args.first().cloned()
1512 .ok_or_else(|| "parser.many: missing inner parser".to_string())?;
1513 Ok(parser_node("Many", &[("p", p)]))
1514 }
1515 ("parser", "optional") => {
1516 let p = args.first().cloned()
1517 .ok_or_else(|| "parser.optional: missing inner parser".to_string())?;
1518 Ok(parser_node("Optional", &[("p", p)]))
1519 }
1520 ("parser", "map") => {
1524 let p = args.first().cloned()
1525 .ok_or_else(|| "parser.map: missing parser".to_string())?;
1526 let f = args.get(1).cloned()
1527 .ok_or_else(|| "parser.map: missing closure".to_string())?;
1528 Ok(parser_node("Map", &[("p", p), ("f", f)]))
1529 }
1530 ("parser", "and_then") => {
1531 let p = args.first().cloned()
1532 .ok_or_else(|| "parser.and_then: missing parser".to_string())?;
1533 let f = args.get(1).cloned()
1534 .ok_or_else(|| "parser.and_then: missing closure".to_string())?;
1535 Ok(parser_node("AndThen", &[("p", p), ("f", f)]))
1536 }
1537 ("regex", "compile") => {
1547 let pat = expect_str(args.first())?;
1548 match get_or_compile_regex(&pat) {
1549 Ok(_) => Ok(ok_v(Value::Str(pat.into()))),
1550 Err(e) => Ok(err_v(Value::Str(e.into()))),
1551 }
1552 }
1553 ("regex", "is_match") => {
1554 let pat = expect_str(args.first())?;
1555 let s = expect_str(args.get(1))?;
1556 let re = get_or_compile_regex(&pat).map_err(|e| format!("regex.is_match: {e}"))?;
1557 Ok(Value::Bool(re.is_match(&s)))
1558 }
1559 ("regex", "is_match_str") => {
1564 let pat = expect_str(args.first())?;
1565 let s = expect_str(args.get(1))?;
1566 match get_or_compile_regex(&pat) {
1567 Ok(re) => Ok(Value::Bool(re.is_match(&s))),
1568 Err(_) => Ok(Value::Bool(false)),
1569 }
1570 }
1571 ("regex", "find") => {
1572 let pat = expect_str(args.first())?;
1573 let s = expect_str(args.get(1))?;
1574 let re = get_or_compile_regex(&pat).map_err(|e| format!("regex.find: {e}"))?;
1575 match re.captures(&s) {
1576 Some(caps) => Ok(Value::Variant {
1577 name: "Some".into(),
1578 args: vec![match_value(&caps)],
1579 }),
1580 None => Ok(Value::Variant { name: "None".into(), args: vec![] }),
1581 }
1582 }
1583 ("regex", "find_all") => {
1584 let pat = expect_str(args.first())?;
1585 let s = expect_str(args.get(1))?;
1586 let re = get_or_compile_regex(&pat).map_err(|e| format!("regex.find_all: {e}"))?;
1587 let items: std::collections::VecDeque<Value> = re.captures_iter(&s).map(|caps| match_value(&caps)).collect();
1588 Ok(Value::List(items))
1589 }
1590 ("regex", "replace") => {
1591 let pat = expect_str(args.first())?;
1592 let s = expect_str(args.get(1))?;
1593 let rep = expect_str(args.get(2))?;
1594 let re = get_or_compile_regex(&pat).map_err(|e| format!("regex.replace: {e}"))?;
1595 Ok(Value::Str(re.replace(&s, rep.as_str()).into_owned().into()))
1596 }
1597 ("regex", "replace_all") => {
1598 let pat = expect_str(args.first())?;
1599 let s = expect_str(args.get(1))?;
1600 let rep = expect_str(args.get(2))?;
1601 let re = get_or_compile_regex(&pat).map_err(|e| format!("regex.replace_all: {e}"))?;
1602 Ok(Value::Str(re.replace_all(&s, rep.as_str()).into_owned().into()))
1603 }
1604 ("datetime", "parse_iso") => {
1607 let s = expect_str(args.first())?;
1608 match chrono::DateTime::parse_from_rfc3339(&s) {
1609 Ok(dt) => Ok(ok_v(Value::Int(instant_from_chrono(dt)))),
1610 Err(e) => Ok(err_v(Value::Str(format!("parse_iso: {e}").into()))),
1611 }
1612 }
1613 ("datetime", "format_iso") => {
1614 let n = expect_int(args.first())?;
1615 Ok(Value::Str(format_iso(n).into()))
1616 }
1617 ("datetime", "parse") => {
1618 let s = expect_str(args.first())?;
1619 let fmt = expect_str(args.get(1))?;
1620 match chrono::NaiveDateTime::parse_from_str(&s, &fmt) {
1621 Ok(naive) => {
1622 use chrono::TimeZone;
1623 match chrono::Utc.from_local_datetime(&naive).single() {
1624 Some(dt) => Ok(ok_v(Value::Int(instant_from_chrono(dt)))),
1625 None => Ok(err_v(Value::Str("parse: ambiguous local time".into()))),
1626 }
1627 }
1628 Err(e) => Ok(err_v(Value::Str(format!("parse: {e}").into()))),
1629 }
1630 }
1631 ("datetime", "format") => {
1632 let n = expect_int(args.first())?;
1633 let fmt = expect_str(args.get(1))?;
1634 let dt = chrono_from_instant(n);
1635 Ok(Value::Str(dt.format(&fmt).to_string().into()))
1636 }
1637 ("datetime", "to_components") => {
1638 let n = expect_int(args.first())?;
1639 let tz = match parse_tz_arg(args.get(1)) {
1640 Ok(t) => t,
1641 Err(e) => return Ok(err_v(Value::Str(e.into()))),
1642 };
1643 match resolve_tz_to_components(n, &tz) {
1644 Ok(rec) => Ok(ok_v(rec)),
1645 Err(e) => Ok(err_v(Value::Str(e.into()))),
1646 }
1647 }
1648 ("datetime", "from_components") => {
1649 let rec = match args.first() {
1650 Some(Value::Record { fields: r, .. }) => r.clone(),
1651 _ => return Err("from_components: expected DateTime record".into()),
1652 };
1653 match instant_from_components(&rec) {
1654 Ok(n) => Ok(ok_v(Value::Int(n))),
1655 Err(e) => Ok(err_v(Value::Str(e.into()))),
1656 }
1657 }
1658 ("datetime", "add") => {
1659 let a = expect_int(args.first())?;
1660 let d = expect_int(args.get(1))?;
1661 Ok(Value::Int(a.saturating_add(d)))
1662 }
1663 ("datetime", "diff") => {
1664 let a = expect_int(args.first())?;
1665 let b = expect_int(args.get(1))?;
1666 Ok(Value::Int(a.saturating_sub(b)))
1667 }
1668 ("datetime", "duration_seconds") => {
1669 let s = expect_float(args.first())?;
1670 let nanos = (s * 1_000_000_000.0) as i64;
1671 Ok(Value::Int(nanos))
1672 }
1673 ("datetime", "duration_minutes") => {
1674 let m = expect_int(args.first())?;
1675 Ok(Value::Int(m.saturating_mul(60_000_000_000)))
1676 }
1677 ("datetime", "duration_days") => {
1678 let d = expect_int(args.first())?;
1679 Ok(Value::Int(d.saturating_mul(86_400_000_000_000)))
1680 }
1681 ("datetime", "before") => {
1683 let a = expect_int(args.first())?;
1684 let b = expect_int(args.get(1))?;
1685 Ok(Value::Bool(a < b))
1686 }
1687 ("datetime", "after") => {
1688 let a = expect_int(args.first())?;
1689 let b = expect_int(args.get(1))?;
1690 Ok(Value::Bool(a > b))
1691 }
1692 ("datetime", "compare") => {
1693 let a = expect_int(args.first())?;
1694 let b = expect_int(args.get(1))?;
1695 Ok(Value::Int(a.cmp(&b) as i64))
1696 }
1697 ("duration", "seconds") => {
1699 let nanos = expect_int(args.first())?;
1700 Ok(Value::Int(nanos / 1_000_000_000))
1701 }
1702
1703 ("regex", "split") => {
1704 let pat = expect_str(args.first())?;
1705 let s = expect_str(args.get(1))?;
1706 let re = get_or_compile_regex(&pat).map_err(|e| format!("regex.split: {e}"))?;
1707 let parts: std::collections::VecDeque<Value> = re.split(&s).map(|p| Value::Str(p.into())).collect();
1708 Ok(Value::List(parts))
1709 }
1710
1711 ("http", "with_header") => {
1714 let req = expect_record_pure(args.first())?.clone();
1715 let k = expect_str(args.get(1))?;
1716 let v = expect_str(args.get(2))?;
1717 Ok(Value::record_interned(http_set_header(req, &k, &v)))
1718 }
1719 ("http", "with_auth") => {
1720 let req = expect_record_pure(args.first())?.clone();
1721 let scheme = expect_str(args.get(1))?;
1722 let token = expect_str(args.get(2))?;
1723 let value = format!("{scheme} {token}");
1724 Ok(Value::record_interned(http_set_header(req, "Authorization", &value)))
1725 }
1726 ("http", "with_query") => {
1727 let req = expect_record_pure(args.first())?.clone();
1728 let params = match args.get(1) {
1729 Some(Value::Map(m)) => m.clone(),
1730 Some(other) => return Err(format!(
1731 "http.with_query: params must be Map[Str, Str], got {other:?}")),
1732 None => return Err("http.with_query: missing params argument".into()),
1733 };
1734 Ok(Value::record_interned(http_append_query(req, ¶ms)))
1735 }
1736 ("http", "with_timeout_ms") => {
1737 let req = expect_record_pure(args.first())?.clone();
1738 let ms = expect_int(args.get(1))?;
1739 let mut out = req;
1740 out.insert("timeout_ms".into(), Value::Variant {
1741 name: "Some".into(),
1742 args: vec![Value::Int(ms)],
1743 });
1744 Ok(Value::record_interned(out))
1745 }
1746 ("http", "json_body") => {
1747 let resp = expect_record_pure(args.first())?;
1748 let body = match resp.get("body") {
1749 Some(Value::Bytes(b)) => b.clone(),
1750 _ => return Err("http.json_body: HttpResponse.body must be Bytes".into()),
1751 };
1752 let s = match std::str::from_utf8(&body) {
1753 Ok(s) => s,
1754 Err(e) => return Ok(http_decode_err_pure(format!("body not UTF-8: {e}"))),
1755 };
1756 match serde_json::from_str::<serde_json::Value>(s) {
1757 Ok(j) => Ok(ok_v(Value::from_json(&j))),
1758 Err(e) => Ok(http_decode_err_pure(format!("json parse: {e}"))),
1759 }
1760 }
1761 ("http", "text_body") => {
1762 let resp = expect_record_pure(args.first())?;
1763 let body = match resp.get("body") {
1764 Some(Value::Bytes(b)) => b.clone(),
1765 _ => return Err("http.text_body: HttpResponse.body must be Bytes".into()),
1766 };
1767 match String::from_utf8(body) {
1768 Ok(s) => Ok(ok_v(Value::Str(s.into()))),
1769 Err(e) => Ok(http_decode_err_pure(format!("body not UTF-8: {e}"))),
1770 }
1771 }
1772
1773 ("cli", "flag") => {
1777 let name = expect_str(args.first())?;
1778 let short = opt_str(args.get(1));
1779 let help = expect_str(args.get(2))?;
1780 Ok(value_from_json(crate::cli::flag_spec(&name, short.as_deref(), &help)))
1781 }
1782 ("cli", "option") => {
1783 let name = expect_str(args.first())?;
1784 let short = opt_str(args.get(1));
1785 let help = expect_str(args.get(2))?;
1786 let default = opt_str(args.get(3));
1787 Ok(value_from_json(crate::cli::option_spec(&name, short.as_deref(), &help, default.as_deref())))
1788 }
1789 ("cli", "positional") => {
1790 let name = expect_str(args.first())?;
1791 let help = expect_str(args.get(1))?;
1792 let required = expect_bool(args.get(2))?;
1793 Ok(value_from_json(crate::cli::positional_spec(&name, &help, required)))
1794 }
1795 ("cli", "spec") => {
1796 let name = expect_str(args.first())?;
1797 let help = expect_str(args.get(1))?;
1798 let arg_specs: Vec<serde_json::Value> = expect_list(args.get(2))?
1799 .iter().map(value_to_json).collect();
1800 let subs: Vec<serde_json::Value> = expect_list(args.get(3))?
1801 .iter().map(value_to_json).collect();
1802 Ok(value_from_json(crate::cli::build_spec(&name, &help, arg_specs, subs)))
1803 }
1804 ("cli", "parse") => {
1805 let spec = value_to_json(args.first().unwrap_or(&Value::Unit));
1806 let argv: Vec<String> = expect_list(args.get(1))?
1807 .iter().map(|v| match v {
1808 Value::Str(s) => Ok(s.to_string()),
1809 other => Err(format!("cli.parse: argv must be List[Str], got {other:?}")),
1810 }).collect::<Result<_, _>>()?;
1811 match crate::cli::parse(&spec, &argv) {
1812 Ok(parsed) => Ok(ok_v(value_from_json(parsed))),
1813 Err(msg) => Ok(err_v(Value::Str(msg.into()))),
1814 }
1815 }
1816 ("cli", "envelope") => {
1817 let ok = expect_bool(args.first())?;
1818 let cmd = expect_str(args.get(1))?;
1819 let data = value_to_json(args.get(2).unwrap_or(&Value::Unit));
1820 Ok(value_from_json(crate::cli::envelope(ok, &cmd, data)))
1821 }
1822 ("cli", "describe") => {
1823 let spec = value_to_json(args.first().unwrap_or(&Value::Unit));
1824 Ok(value_from_json(crate::cli::describe(&spec)))
1825 }
1826 ("cli", "help") => {
1827 let spec = value_to_json(args.first().unwrap_or(&Value::Unit));
1828 Ok(Value::Str(crate::cli::help_text(&spec).into()))
1829 }
1830
1831 ("arrow", op) => match crate::arrow::dispatch(op, args) {
1833 Some(r) => r,
1834 None => Err(format!("unknown pure builtin: arrow.{op}")),
1835 },
1836 #[cfg(feature = "df")]
1840 ("df", op) => match crate::df::dispatch(op, args) {
1841 Some(r) => r,
1842 None => Err(format!("unknown pure builtin: df.{op}")),
1843 },
1844 #[cfg(not(feature = "df"))]
1845 ("df", op) => Err(format!(
1846 "df.{op}: this build was compiled without the `df` feature; \
1847 Polars-backed dataframe query ops are unavailable"
1848 )),
1849
1850 ("decimal", "decimal") => {
1857 let coef = expect_int(args.first())?;
1858 let exp = expect_int(args.get(1))?;
1859 Ok(make_decimal(coef, exp))
1860 }
1861 ("decimal", "zero") => Ok(make_decimal(0, 0)),
1862 ("decimal", "one") => Ok(make_decimal(1, 0)),
1863 ("decimal", "from_int") => {
1864 Ok(make_decimal(expect_int(args.first())?, 0))
1865 }
1866 ("decimal", "pow10") => {
1867 Ok(Value::Int(decimal_pow10(expect_int(args.first())?)?))
1868 }
1869 ("decimal", "add") => {
1870 let (ca, ea) = expect_decimal(args.first())?;
1871 let (cb, eb) = expect_decimal(args.get(1))?;
1872 let (a2, b2, e) = decimal_align(ca, ea, cb, eb)?;
1873 Ok(make_decimal(
1874 a2.checked_add(b2).ok_or("decimal.add: overflow")?, e))
1875 }
1876 ("decimal", "sub") => {
1877 let (ca, ea) = expect_decimal(args.first())?;
1878 let (cb, eb) = expect_decimal(args.get(1))?;
1879 let (a2, b2, e) = decimal_align(ca, ea, cb, eb)?;
1880 Ok(make_decimal(
1881 a2.checked_sub(b2).ok_or("decimal.sub: overflow")?, e))
1882 }
1883 ("decimal", "mul") => {
1884 let (ca, ea) = expect_decimal(args.first())?;
1885 let (cb, eb) = expect_decimal(args.get(1))?;
1886 Ok(make_decimal(
1887 ca.checked_mul(cb).ok_or("decimal.mul: overflow")?,
1888 ea.checked_add(eb).ok_or("decimal.mul: exponent overflow")?,
1889 ))
1890 }
1891 ("decimal", "compare") => {
1892 let (ca, ea) = expect_decimal(args.first())?;
1893 let (cb, eb) = expect_decimal(args.get(1))?;
1894 let (a2, b2, _) = decimal_align(ca, ea, cb, eb)?;
1895 Ok(Value::Int(if a2 < b2 { -1 } else if a2 > b2 { 1 } else { 0 }))
1896 }
1897 ("decimal", "is_zero") => {
1898 let (c, _) = expect_decimal(args.first())?;
1899 Ok(Value::Bool(c == 0))
1900 }
1901 ("decimal", "is_positive") => {
1902 let (c, _) = expect_decimal(args.first())?;
1903 Ok(Value::Bool(c > 0))
1904 }
1905 ("decimal", "is_negative") => {
1906 let (c, _) = expect_decimal(args.first())?;
1907 Ok(Value::Bool(c < 0))
1908 }
1909 ("decimal", "negate") => {
1910 let (c, e) = expect_decimal(args.first())?;
1911 Ok(make_decimal(-c, e))
1912 }
1913 ("decimal", "abs") => {
1914 let (c, e) = expect_decimal(args.first())?;
1915 Ok(make_decimal(c.abs(), e))
1916 }
1917 ("decimal", "normalize") => {
1918 let (mut c, mut e) = expect_decimal(args.first())?;
1919 if c == 0 { return Ok(make_decimal(0, 0)); }
1920 while c % 10 == 0 { c /= 10; e += 1; }
1921 Ok(make_decimal(c, e))
1922 }
1923 ("decimal", "round_to") => {
1924 let (c, e) = expect_decimal(args.first())?;
1925 let target_e = expect_int(args.get(1))?;
1926 let mode = expect_str(args.get(2))?;
1927 Ok(make_decimal(decimal_round(c, e, target_e, &mode)?, target_e))
1928 }
1929 ("decimal", "to_str") => {
1930 let (c, e) = expect_decimal(args.first())?;
1931 Ok(Value::Str(decimal_to_str(c, e)?.into()))
1932 }
1933
1934 _ => Err(format!("unknown pure builtin: {kind}.{op}")),
1935 }
1936}
1937
1938fn expect_decimal(v: Option<&Value>) -> Result<(i64, i64), String> {
1942 match v {
1943 Some(Value::Record { fields, .. }) => {
1944 let coef = match fields.get("coefficient") {
1945 Some(Value::Int(n)) => *n,
1946 _ => return Err("decimal: missing or invalid 'coefficient' field".into()),
1947 };
1948 let exp = match fields.get("exponent") {
1949 Some(Value::Int(n)) => *n,
1950 _ => return Err("decimal: missing or invalid 'exponent' field".into()),
1951 };
1952 Ok((coef, exp))
1953 }
1954 Some(other) => Err(format!("decimal: expected {{ coefficient, exponent }} record, got {other:?}")),
1955 None => Err("decimal: missing argument".into()),
1956 }
1957}
1958
1959fn make_decimal(coefficient: i64, exponent: i64) -> Value {
1961 let mut fields = indexmap::IndexMap::new();
1962 fields.insert("coefficient".into(), Value::Int(coefficient));
1963 fields.insert("exponent".into(), Value::Int(exponent));
1964 Value::record_interned(fields)
1965}
1966
1967fn decimal_pow10(n: i64) -> Result<i64, String> {
1969 if n < 0 { return Err(format!("decimal.pow10: negative exponent {n}")); }
1970 if n > 18 { return Err(format!("decimal.pow10: exponent {n} exceeds max (18)")); }
1971 Ok(10i64.pow(n as u32))
1972}
1973
1974fn decimal_align(ca: i64, ea: i64, cb: i64, eb: i64) -> Result<(i64, i64, i64), String> {
1977 if ea == eb { return Ok((ca, cb, ea)); }
1978 if ea > eb {
1979 let scale = decimal_pow10(ea - eb)?;
1980 let ca2 = ca.checked_mul(scale)
1981 .ok_or_else(|| format!("decimal: overflow aligning (shift {})", ea - eb))?;
1982 Ok((ca2, cb, eb))
1983 } else {
1984 let scale = decimal_pow10(eb - ea)?;
1985 let cb2 = cb.checked_mul(scale)
1986 .ok_or_else(|| format!("decimal: overflow aligning (shift {})", eb - ea))?;
1987 Ok((ca, cb2, ea))
1988 }
1989}
1990
1991fn decimal_round(c: i64, e: i64, target_e: i64, mode: &str) -> Result<i64, String> {
1996 if e >= target_e {
1997 let shift = e - target_e;
1999 let scale = decimal_pow10(shift)?;
2000 return c.checked_mul(scale)
2001 .ok_or_else(|| format!("decimal.round_to: overflow scaling (shift {shift})"));
2002 }
2003 let shift = target_e - e;
2005 let divisor = decimal_pow10(shift)?;
2006 let q = c / divisor;
2007 let r = c % divisor; if r == 0 { return Ok(q); }
2010
2011 let abs_r = r.abs();
2012 let positive = r > 0; let rounded = match mode {
2015 "Down" => q,
2016 "Up" => if positive { q + 1 } else { q - 1 },
2017 "Floor" => if positive { q } else { q - 1 },
2018 "Ceiling" => if positive { q + 1 } else { q },
2019 "HalfUp" => {
2020 if abs_r * 2 >= divisor {
2021 if positive { q + 1 } else { q - 1 }
2022 } else { q }
2023 }
2024 "HalfDown" => {
2025 if abs_r * 2 > divisor {
2026 if positive { q + 1 } else { q - 1 }
2027 } else { q }
2028 }
2029 "HalfEven" => {
2030 if abs_r * 2 > divisor {
2031 if positive { q + 1 } else { q - 1 }
2032 } else if abs_r * 2 == divisor {
2033 if q % 2 == 0 { q } else { if positive { q + 1 } else { q - 1 } }
2035 } else { q }
2036 }
2037 other => return Err(format!(
2038 "decimal.round_to: unknown rounding mode {other:?}; \
2039 valid modes: HalfUp HalfDown HalfEven Down Up Ceiling Floor")),
2040 };
2041 Ok(rounded)
2042}
2043
2044fn decimal_to_str(c: i64, e: i64) -> Result<String, String> {
2047 if e == 0 { return Ok(c.to_string()); }
2048 if e > 0 {
2049 let scale = decimal_pow10(e)?;
2050 let val = c.checked_mul(scale)
2051 .ok_or("decimal.to_str: overflow")?;
2052 return Ok(val.to_string());
2053 }
2054 let scale = decimal_pow10(-e)?;
2056 let sign = if c < 0 { "-" } else { "" };
2057 let abs_c = c.abs();
2058 let int_part = abs_c / scale;
2059 let frac_part = abs_c % scale;
2060 let decimal_places = (-e) as usize;
2061 Ok(format!("{sign}{int_part}.{frac_part:0>decimal_places$}"))
2062}
2063
2064fn opt_str(arg: Option<&Value>) -> Option<String> {
2068 match arg {
2069 Some(Value::Variant { name, args }) if name == "Some" => {
2070 args.first().and_then(|v| match v {
2071 Value::Str(s) => Some(s.to_string()),
2072 _ => None,
2073 })
2074 }
2075 _ => None,
2076 }
2077}
2078
2079fn value_from_json(v: serde_json::Value) -> Value { Value::from_json(&v) }
2080
2081fn regex_cache() -> &'static Mutex<HashMap<String, regex::Regex>> {
2086 static CACHE: OnceLock<Mutex<HashMap<String, regex::Regex>>> = OnceLock::new();
2087 CACHE.get_or_init(|| Mutex::new(HashMap::new()))
2088}
2089
2090fn get_or_compile_regex(pattern: &str) -> Result<regex::Regex, String> {
2091 let cache = regex_cache();
2092 {
2093 let guard = cache.lock().unwrap();
2094 if let Some(re) = guard.get(pattern) {
2095 return Ok(re.clone());
2096 }
2097 }
2098 let re = regex::Regex::new(pattern).map_err(|e| format!("invalid regex: {e}"))?;
2099 let mut guard = cache.lock().unwrap();
2100 guard.insert(pattern.to_string(), re.clone());
2101 Ok(re)
2102}
2103
2104fn match_value(caps: ®ex::Captures) -> Value {
2108 let m0 = caps.get(0).expect("regex match always has group 0");
2109 let mut rec = indexmap::IndexMap::new();
2110 rec.insert("text".into(), Value::Str(m0.as_str().into()));
2111 rec.insert("start".into(), Value::Int(m0.start() as i64));
2112 rec.insert("end".into(), Value::Int(m0.end() as i64));
2113 let groups: std::collections::VecDeque<Value> = (1..caps.len())
2114 .map(|i| {
2115 Value::Str(
2116 caps.get(i)
2117 .map(|m| m.as_str())
2118 .unwrap_or_default()
2119 .into(),
2120 )
2121 })
2122 .collect();
2123 rec.insert("groups".into(), Value::List(groups));
2124 Value::record_dynamic(rec)
2125}
2126
2127fn expect_map(v: Option<&Value>) -> Result<&BTreeMap<MapKey, Value>, String> {
2128 match v {
2129 Some(Value::Map(m)) => Ok(m),
2130 other => Err(format!("expected Map, got {other:?}")),
2131 }
2132}
2133
2134fn expect_set(v: Option<&Value>) -> Result<&BTreeSet<MapKey>, String> {
2135 match v {
2136 Some(Value::Set(s)) => Ok(s),
2137 other => Err(format!("expected Set, got {other:?}")),
2138 }
2139}
2140
2141fn unpack_matrix(v: &Value) -> Result<(usize, usize, Vec<f64>), String> {
2145 if let Value::F64Array { rows, cols, data } = v {
2146 return Ok((*rows as usize, *cols as usize, data.clone()));
2147 }
2148 let rec = match v {
2149 Value::Record { fields: r, .. } => r,
2150 other => return Err(format!("expected matrix, got {other:?}")),
2151 };
2152 let rows = match rec.get("rows") {
2153 Some(Value::Int(n)) => *n as usize,
2154 _ => return Err("matrix: missing/invalid `rows`".into()),
2155 };
2156 let cols = match rec.get("cols") {
2157 Some(Value::Int(n)) => *n as usize,
2158 _ => return Err("matrix: missing/invalid `cols`".into()),
2159 };
2160 let data = match rec.get("data") {
2161 Some(Value::List(items)) => {
2162 let mut out = Vec::with_capacity(items.len());
2163 for it in items {
2164 out.push(match it {
2165 Value::Float(f) => *f,
2166 Value::Int(n) => *n as f64,
2167 other => return Err(format!("matrix data: not numeric, got {other:?}")),
2168 });
2169 }
2170 out
2171 }
2172 _ => return Err("matrix: missing/invalid `data`".into()),
2173 };
2174 if data.len() != rows * cols {
2175 return Err(format!("matrix: data len {} != {rows}*{cols}", data.len()));
2176 }
2177 Ok((rows, cols, data))
2178}
2179
2180fn expect_bytes(v: Option<&Value>) -> Result<&Vec<u8>, String> {
2181 match v {
2182 Some(Value::Bytes(b)) => Ok(b),
2183 Some(other) => Err(format!("expected Bytes, got {other:?}")),
2184 None => Err("missing argument".into()),
2185 }
2186}
2187
2188fn first_arg(args: &[Value]) -> Result<&Value, String> {
2189 args.first().ok_or_else(|| "missing argument".into())
2190}
2191
2192fn tuple_index(v: &Value, i: usize) -> Result<Value, String> {
2193 match v {
2194 Value::Tuple(items) => items.get(i).cloned()
2195 .ok_or_else(|| format!("tuple index {i} out of range (len={})", items.len())),
2196 other => Err(format!("expected Tuple, got {other:?}")),
2197 }
2198}
2199
2200fn expect_str(v: Option<&Value>) -> Result<String, String> {
2201 match v {
2202 Some(Value::Str(s)) => Ok(s.to_string()),
2203 Some(other) => Err(format!("expected Str, got {other:?}")),
2204 None => Err("missing argument".into()),
2205 }
2206}
2207
2208fn expect_int(v: Option<&Value>) -> Result<i64, String> {
2209 match v {
2210 Some(Value::Int(n)) => Ok(*n),
2211 Some(other) => Err(format!("expected Int, got {other:?}")),
2212 None => Err("missing argument".into()),
2213 }
2214}
2215
2216fn expect_float(v: Option<&Value>) -> Result<f64, String> {
2217 match v {
2218 Some(Value::Float(f)) => Ok(*f),
2219 Some(other) => Err(format!("expected Float, got {other:?}")),
2220 None => Err("missing argument".into()),
2221 }
2222}
2223
2224fn expect_list(v: Option<&Value>) -> Result<&std::collections::VecDeque<Value>, String> {
2225 match v {
2226 Some(Value::List(xs)) => Ok(xs),
2227 Some(other) => Err(format!("expected List, got {other:?}")),
2228 None => Err("missing argument".into()),
2229 }
2230}
2231
2232fn expect_bool(v: Option<&Value>) -> Result<bool, String> {
2233 match v {
2234 Some(Value::Bool(b)) => Ok(*b),
2235 Some(other) => Err(format!("expected Bool, got {other:?}")),
2236 None => Err("missing argument".into()),
2237 }
2238}
2239
2240fn expect_deque(v: Option<&Value>) -> Result<&std::collections::VecDeque<Value>, String> {
2241 match v {
2242 Some(Value::Deque(d)) => Ok(d),
2243 Some(other) => Err(format!("expected Deque, got {other:?}")),
2244 None => Err("missing argument".into()),
2245 }
2246}
2247
2248fn some(v: Value) -> Value { Value::Variant { name: "Some".into(), args: vec![v] } }
2249fn none() -> Value { Value::Variant { name: "None".into(), args: Vec::new() } }
2250fn ok_v(v: Value) -> Value { Value::Variant { name: "Ok".into(), args: vec![v] } }
2251fn err_v(v: Value) -> Value { Value::Variant { name: "Err".into(), args: vec![v] } }
2252
2253fn parser_node(kind: &str, fields: &[(&str, Value)]) -> Value {
2261 let mut r = indexmap::IndexMap::new();
2262 r.insert("kind".into(), Value::Str(kind.into()));
2263 for (k, v) in fields {
2264 r.insert((*k).into(), v.clone());
2265 }
2266 Value::record_dynamic(r)
2267}
2268
2269fn splitmix64(state: u64) -> (u64, u64) {
2280 let next = state.wrapping_add(0x9E37_79B9_7F4A_7C15);
2281 let mut z = next;
2282 z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
2283 z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
2284 let z = z ^ (z >> 31);
2285 (z, next)
2286}
2287
2288fn rng_value(state: u64) -> Value {
2292 let mut fields = indexmap::IndexMap::new();
2293 fields.insert("state".into(), Value::Int(state as i64));
2294 Value::record_dynamic(fields)
2295}
2296
2297fn rng_decode(v: Option<&Value>) -> Result<u64, String> {
2299 let rec = match v {
2300 Some(Value::Record { fields: r, .. }) => r,
2301 Some(other) => return Err(format!("expected Rng, got {other:?}")),
2302 None => return Err("missing Rng arg".into()),
2303 };
2304 match rec.get("state") {
2305 Some(Value::Int(n)) => Ok(*n as u64),
2306 _ => Err("malformed Rng: missing `state :: Int`".into()),
2307 }
2308}
2309
2310fn expect_record_pure(v: Option<&Value>) -> Result<&indexmap::IndexMap<smol_str::SmolStr, Value>, String> {
2313 match v {
2314 Some(Value::Record { fields: r, .. }) => Ok(r),
2315 Some(other) => Err(format!("expected Record, got {other:?}")),
2316 None => Err("missing Record argument".into()),
2317 }
2318}
2319
2320fn http_decode_err_pure(msg: String) -> Value {
2321 let inner = Value::Variant {
2322 name: "DecodeError".into(),
2323 args: vec![Value::Str(msg.into())],
2324 };
2325 err_v(inner)
2326}
2327
2328fn http_set_header(
2333 mut req: indexmap::IndexMap<smol_str::SmolStr, Value>,
2334 name: &str,
2335 value: &str,
2336) -> indexmap::IndexMap<smol_str::SmolStr, Value> {
2337 use lex_bytecode::MapKey;
2338 let mut headers = match req.shift_remove("headers") {
2339 Some(Value::Map(m)) => m,
2340 _ => std::collections::BTreeMap::new(),
2341 };
2342 let key = MapKey::Str(name.to_lowercase());
2343 let lowered = name.to_lowercase();
2346 headers.retain(|k, _| match k {
2347 MapKey::Str(s) => s.to_lowercase() != lowered,
2348 _ => true,
2349 });
2350 headers.insert(key, Value::Str(value.into()));
2351 req.insert("headers".into(), Value::Map(headers));
2352 req
2353}
2354
2355fn http_append_query(
2361 mut req: indexmap::IndexMap<smol_str::SmolStr, Value>,
2362 params: &std::collections::BTreeMap<lex_bytecode::MapKey, Value>,
2363) -> indexmap::IndexMap<smol_str::SmolStr, Value> {
2364 use lex_bytecode::MapKey;
2365 let url = match req.get("url") {
2366 Some(Value::Str(s)) => s.clone(),
2367 _ => return req,
2368 };
2369 let mut pieces = Vec::new();
2370 for (k, v) in params {
2371 let kk = match k { MapKey::Str(s) => s.to_string(), _ => continue };
2372 let vv = match v { Value::Str(s) => s.to_string(), _ => continue };
2373 pieces.push(format!("{}={}", url_encode(&kk), url_encode(&vv)));
2374 }
2375 if pieces.is_empty() { return req; }
2376 let sep = if url.contains('?') { '&' } else { '?' };
2377 let new_url = format!("{url}{sep}{}", pieces.join("&"));
2378 req.insert("url".into(), Value::Str(new_url.into()));
2379 req
2380}
2381
2382fn url_encode(s: &str) -> String {
2387 let mut out = String::with_capacity(s.len());
2388 for b in s.bytes() {
2389 match b {
2390 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
2391 out.push(b as char);
2392 }
2393 _ => out.push_str(&format!("%{:02X}", b)),
2394 }
2395 }
2396 out
2397}
2398
2399fn value_to_json(v: &Value) -> serde_json::Value { v.to_json() }
2400
2401fn unwrap_toml_datetime_markers(v: &mut serde_json::Value) {
2409 use serde_json::Value as J;
2410 match v {
2411 J::Object(map) => {
2412 if map.len() == 1 {
2416 if let Some(J::String(s)) = map.get("$__toml_private_datetime") {
2417 let s = s.clone();
2418 *v = J::String(s);
2419 return;
2420 }
2421 }
2422 for (_, child) in map.iter_mut() {
2423 unwrap_toml_datetime_markers(child);
2424 }
2425 }
2426 J::Array(items) => {
2427 for item in items.iter_mut() {
2428 unwrap_toml_datetime_markers(item);
2429 }
2430 }
2431 _ => {}
2432 }
2433}
2434
2435fn json_to_value(v: &serde_json::Value) -> Value { Value::from_json(v) }
2436
2437fn required_field_names(arg: Option<&Value>) -> Result<Vec<String>, String> {
2442 let list = expect_list(arg)?;
2443 let mut out = Vec::with_capacity(list.len());
2444 for v in list {
2445 match v {
2446 Value::Str(s) => out.push(s.to_string()),
2447 other => return Err(format!(
2448 "parse_strict: required-fields list must contain Str, got {other:?}"
2449 )),
2450 }
2451 }
2452 Ok(out)
2453}
2454
2455fn check_required_fields(
2476 value: &serde_json::Value,
2477 required: &[String],
2478) -> Result<(), String> {
2479 if required.is_empty() {
2480 return Ok(());
2481 }
2482 if !matches!(value, serde_json::Value::Object(_)) {
2483 return Err(format!(
2484 "parse_strict: expected top-level object with fields {:?}, got {value}",
2485 required
2486 ));
2487 }
2488 let mut missing: Vec<String> = Vec::new();
2489 for path in required {
2490 if !path_exists(value, path) {
2491 missing.push(path.clone());
2492 }
2493 }
2494 if missing.is_empty() {
2495 Ok(())
2496 } else {
2497 Err(format!("missing required field(s): {}", missing.join(", ")))
2498 }
2499}
2500
2501fn path_exists(value: &serde_json::Value, path: &str) -> bool {
2506 let mut cursor = value;
2507 let segments = split_dotted_path(path);
2508 for seg in &segments {
2509 match cursor {
2510 serde_json::Value::Object(o) => match o.get(seg.as_str()) {
2511 Some(next) => cursor = next,
2512 None => return false,
2513 },
2514 _ => return false,
2515 }
2516 }
2517 true
2518}
2519
2520fn split_dotted_path(path: &str) -> Vec<String> {
2524 let mut out: Vec<String> = Vec::new();
2525 let mut cur = String::new();
2526 let mut iter = path.chars().peekable();
2527 while let Some(c) = iter.next() {
2528 if c == '\\' {
2529 if let Some(&'.') = iter.peek() {
2531 cur.push('.');
2532 iter.next();
2533 continue;
2534 }
2535 cur.push(c);
2536 } else if c == '.' {
2537 out.push(std::mem::take(&mut cur));
2538 } else {
2539 cur.push(c);
2540 }
2541 }
2542 out.push(cur);
2543 out
2544}
2545
2546fn extract_type_schema(v: Option<&Value>) -> Vec<(String, String)> {
2550 match v {
2551 Some(Value::List(pairs)) => pairs.iter().filter_map(|p| {
2552 if let Value::Tuple(items) = p {
2553 if items.len() == 2 {
2554 if let (Value::Str(name), Value::Str(tag)) = (&items[0], &items[1]) {
2555 return Some((name.to_string(), tag.to_string()));
2556 }
2557 }
2558 }
2559 None
2560 }).collect(),
2561 _ => vec![],
2562 }
2563}
2564
2565fn validate_field_types(
2571 json: &serde_json::Value,
2572 schema: &[(String, String)],
2573) -> Result<(), String> {
2574 if schema.is_empty() {
2575 return Ok(());
2576 }
2577 let obj = match json.as_object() {
2578 Some(o) => o,
2579 None => return Ok(()), };
2581 for (field, tag) in schema {
2582 if let Some(val) = obj.get(field) {
2583 if let Err(e) = check_json_type(val, tag) {
2584 return Err(format!("field `{field}`: {e}"));
2585 }
2586 }
2587 }
2588 Ok(())
2589}
2590
2591fn apply_option_wrapping(v: Value, json: &serde_json::Value, schema: &[(String, String)]) -> Value {
2596 if schema.is_empty() {
2597 return v;
2598 }
2599 let fields = match v {
2600 Value::Record { fields, .. } => *fields,
2601 other => return other,
2602 };
2603 let json_obj = match json.as_object() {
2604 Some(o) => o,
2605 None => return Value::record_interned(fields),
2606 };
2607 let mut new_fields = fields;
2608 for (field_name, tag) in schema {
2609 if tag.starts_with("Option[") && tag.ends_with(']') {
2610 let json_val = json_obj.get(field_name.as_str());
2611 let wrapped = match json_val {
2612 None | Some(serde_json::Value::Null) => none(),
2613 Some(_) => {
2614 let inner = new_fields
2615 .get(field_name.as_str())
2616 .cloned()
2617 .unwrap_or(Value::Unit);
2618 some(inner)
2619 }
2620 };
2621 new_fields.insert(smol_str::SmolStr::from(field_name.as_str()), wrapped);
2622 }
2623 }
2624 Value::record_interned(new_fields)
2625}
2626
2627fn check_json_type(val: &serde_json::Value, tag: &str) -> Result<(), String> {
2629 use serde_json::Value as J;
2630 match (tag, val) {
2631 ("Int", J::Number(n)) if n.is_i64() || n.is_u64() => Ok(()),
2632 ("Int", other) => Err(format!("expected Int, got {}", json_type_name(other))),
2633 ("Float", J::Number(_)) => Ok(()),
2634 ("Float", other) => Err(format!("expected Float, got {}", json_type_name(other))),
2635 ("Bool", J::Bool(_)) => Ok(()),
2636 ("Bool", other) => Err(format!("expected Bool, got {}", json_type_name(other))),
2637 ("Str", J::String(_)) => Ok(()),
2638 ("Str", other) => Err(format!("expected Str, got {}", json_type_name(other))),
2639 (tag, J::Null) if tag.starts_with("Option[") => Ok(()),
2641 (tag, val) if tag.starts_with("Option[") && tag.ends_with(']') => {
2642 let inner = &tag[7..tag.len() - 1]; check_json_type(val, inner)
2644 }
2645 (tag, J::Array(items)) if tag.starts_with("List[") && tag.ends_with(']') => {
2647 let inner = &tag[5..tag.len() - 1]; for (i, item) in items.iter().enumerate() {
2649 if let Err(e) = check_json_type(item, inner) {
2650 return Err(format!("[{i}]: {e}"));
2651 }
2652 }
2653 Ok(())
2654 }
2655 ("Record", _) => Ok(()), ("Any", _) => Ok(()), _ => Ok(()), }
2659}
2660
2661fn json_type_name(v: &serde_json::Value) -> &'static str {
2662 match v {
2663 serde_json::Value::Null => "null",
2664 serde_json::Value::Bool(_) => "Bool",
2665 serde_json::Value::Number(_) => "Number",
2666 serde_json::Value::String(_) => "Str",
2667 serde_json::Value::Array(_) => "Array",
2668 serde_json::Value::Object(_) => "Object",
2669 }
2670}
2671
2672fn parse_dotenv(src: &str) -> Result<indexmap::IndexMap<String, String>, String> {
2683 let mut out = indexmap::IndexMap::new();
2684 for (idx, raw) in src.lines().enumerate() {
2685 let line = raw.trim();
2686 if line.is_empty() || line.starts_with('#') {
2687 continue;
2688 }
2689 let after_export = line.strip_prefix("export ").unwrap_or(line);
2692 let (k, v) = match after_export.split_once('=') {
2693 Some(kv) => kv,
2694 None => return Err(format!("dotenv.parse line {}: missing `=`", idx + 1)),
2695 };
2696 let key = k.trim();
2697 if key.is_empty() {
2698 return Err(format!("dotenv.parse line {}: empty key", idx + 1));
2699 }
2700 let v_trim = v.trim();
2701 let value = if let Some(q) = v_trim.strip_prefix('"').and_then(|s| s.strip_suffix('"')) {
2702 q.to_string()
2703 } else if let Some(q) = v_trim.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) {
2704 q.to_string()
2705 } else {
2706 v_trim.to_string()
2707 };
2708 out.insert(key.to_string(), value);
2709 }
2710 Ok(out)
2711}
2712
2713fn instant_from_chrono<Tz: chrono::TimeZone>(dt: chrono::DateTime<Tz>) -> i64 {
2719 dt.timestamp_nanos_opt().unwrap_or(i64::MAX)
2720}
2721
2722fn chrono_from_instant(n: i64) -> chrono::DateTime<chrono::Utc> {
2723 let secs = n.div_euclid(1_000_000_000);
2724 let nanos = n.rem_euclid(1_000_000_000) as u32;
2725 use chrono::TimeZone;
2726 chrono::Utc
2727 .timestamp_opt(secs, nanos)
2728 .single()
2729 .unwrap_or_else(chrono::Utc::now)
2730}
2731
2732fn format_iso(n: i64) -> String {
2733 chrono_from_instant(n).to_rfc3339()
2734}
2735
2736enum TzArg {
2739 Utc,
2740 Local,
2741 Offset(i32),
2743 Iana(String),
2745}
2746
2747fn parse_tz_arg(v: Option<&Value>) -> Result<TzArg, String> {
2748 match v {
2749 Some(Value::Variant { name, args }) => match (name.as_str(), args.as_slice()) {
2750 ("Utc", []) => Ok(TzArg::Utc),
2751 ("Local", []) => Ok(TzArg::Local),
2752 ("Offset", [Value::Int(m)]) => {
2753 let m = i32::try_from(*m).map_err(|_| {
2754 format!("Tz::Offset: minutes out of range: {m}")
2755 })?;
2756 Ok(TzArg::Offset(m))
2757 }
2758 ("Iana", [Value::Str(s)]) => Ok(TzArg::Iana(s.to_string())),
2759 (other, _) => Err(format!(
2760 "expected Tz variant (Utc | Local | Offset(Int) | Iana(Str)), got `{other}` with {} arg(s)",
2761 args.len()
2762 )),
2763 },
2764 Some(other) => Err(format!("expected Tz variant, got {other:?}")),
2765 None => Err("missing Tz argument".into()),
2766 }
2767}
2768
2769fn resolve_tz_to_components(n: i64, tz: &TzArg) -> Result<Value, String> {
2770 use chrono::{TimeZone, Datelike, Timelike, Offset};
2771 let utc_dt = chrono_from_instant(n);
2772 let (y, m, d, hh, mm, ss, ns, off_min) = match tz {
2773 TzArg::Utc => {
2774 let d = utc_dt;
2775 (d.year(), d.month() as i32, d.day() as i32,
2776 d.hour() as i32, d.minute() as i32, d.second() as i32,
2777 d.nanosecond() as i32, 0)
2778 }
2779 TzArg::Local => {
2780 let d = utc_dt.with_timezone(&chrono::Local);
2781 let off = d.offset().fix().local_minus_utc() / 60;
2782 (d.year(), d.month() as i32, d.day() as i32,
2783 d.hour() as i32, d.minute() as i32, d.second() as i32,
2784 d.nanosecond() as i32, off)
2785 }
2786 TzArg::Offset(off_min) => {
2787 let off_secs = off_min.saturating_mul(60);
2788 let fixed = chrono::FixedOffset::east_opt(off_secs)
2789 .ok_or("to_components: offset out of range")?;
2790 let d = utc_dt.with_timezone(&fixed);
2791 (d.year(), d.month() as i32, d.day() as i32,
2792 d.hour() as i32, d.minute() as i32, d.second() as i32,
2793 d.nanosecond() as i32, *off_min)
2794 }
2795 TzArg::Iana(name) => {
2796 let tz: chrono_tz::Tz = name.parse()
2797 .map_err(|e| format!("to_components: unknown timezone `{name}`: {e}"))?;
2798 let d = utc_dt.with_timezone(&tz);
2799 let off = d.offset().fix().local_minus_utc() / 60;
2800 (d.year(), d.month() as i32, d.day() as i32,
2801 d.hour() as i32, d.minute() as i32, d.second() as i32,
2802 d.nanosecond() as i32, off)
2803 }
2804 };
2805 let mut rec = indexmap::IndexMap::new();
2806 rec.insert("year".into(), Value::Int(y as i64));
2807 rec.insert("month".into(), Value::Int(m as i64));
2808 rec.insert("day".into(), Value::Int(d as i64));
2809 rec.insert("hour".into(), Value::Int(hh as i64));
2810 rec.insert("minute".into(), Value::Int(mm as i64));
2811 rec.insert("second".into(), Value::Int(ss as i64));
2812 rec.insert("nano".into(), Value::Int(ns as i64));
2813 rec.insert("tz_offset_minutes".into(), Value::Int(off_min as i64));
2814 let _ = chrono::Utc.timestamp_opt(0, 0); Ok(Value::record_dynamic(rec))
2816}
2817
2818
2819fn instant_from_components(rec: &indexmap::IndexMap<smol_str::SmolStr, Value>) -> Result<i64, String> {
2820 use chrono::TimeZone;
2821 fn get_int(rec: &indexmap::IndexMap<smol_str::SmolStr, Value>, k: &str) -> Result<i64, String> {
2822 match rec.get(k) {
2823 Some(Value::Int(n)) => Ok(*n),
2824 other => Err(format!("from_components: missing or non-int field `{k}`: {other:?}")),
2825 }
2826 }
2827 let y = get_int(rec, "year")? as i32;
2828 let m = get_int(rec, "month")? as u32;
2829 let d = get_int(rec, "day")? as u32;
2830 let hh = get_int(rec, "hour")? as u32;
2831 let mm = get_int(rec, "minute")? as u32;
2832 let ss = get_int(rec, "second")? as u32;
2833 let ns = get_int(rec, "nano")? as u32;
2834 let off_min = get_int(rec, "tz_offset_minutes")? as i32;
2835 let off = chrono::FixedOffset::east_opt(off_min * 60)
2836 .ok_or("from_components: offset out of range")?;
2837 let dt = off
2838 .with_ymd_and_hms(y, m, d, hh, mm, ss)
2839 .single()
2840 .ok_or("from_components: invalid or ambiguous date/time")?;
2841 let dt = dt + chrono::Duration::nanoseconds(ns as i64);
2842 Ok(instant_from_chrono(dt))
2843}
2844
2845type Aead4<'a> = (&'a Vec<u8>, &'a Vec<u8>, &'a Vec<u8>, &'a Vec<u8>);
2862
2863type Aead5<'a> = (&'a Vec<u8>, &'a Vec<u8>, &'a Vec<u8>, &'a Vec<u8>, &'a Vec<u8>);
2866
2867fn unpack4_bytes<'a>(
2868 args: &'a [Value],
2869 op: &str,
2870) -> Result<Aead4<'a>, String> {
2871 let pick = |i: usize, name: &str| -> Result<&'a Vec<u8>, String> {
2872 match args.get(i) {
2873 Some(Value::Bytes(b)) => Ok(b),
2874 Some(other) => Err(format!("{op}: {name} must be Bytes, got {other:?}")),
2875 None => Err(format!("{op}: missing {name} argument")),
2876 }
2877 };
2878 Ok((pick(0, "key")?, pick(1, "nonce")?, pick(2, "aad")?, pick(3, "plaintext")?))
2879}
2880
2881fn unpack5_bytes<'a>(
2882 args: &'a [Value],
2883 op: &str,
2884) -> Result<Aead5<'a>, String> {
2885 let pick = |i: usize, name: &str| -> Result<&'a Vec<u8>, String> {
2886 match args.get(i) {
2887 Some(Value::Bytes(b)) => Ok(b),
2888 Some(other) => Err(format!("{op}: {name} must be Bytes, got {other:?}")),
2889 None => Err(format!("{op}: missing {name} argument")),
2890 }
2891 };
2892 Ok((
2893 pick(0, "key")?,
2894 pick(1, "nonce")?,
2895 pick(2, "aad")?,
2896 pick(3, "ciphertext")?,
2897 pick(4, "tag")?,
2898 ))
2899}
2900
2901fn aead_result(ciphertext: Vec<u8>, tag: Vec<u8>) -> Value {
2902 let mut rec = indexmap::IndexMap::new();
2903 rec.insert("ciphertext".into(), Value::Bytes(ciphertext));
2904 rec.insert("tag".into(), Value::Bytes(tag));
2905 Value::record_dynamic(rec)
2906}
2907
2908fn aead_err(msg: impl Into<String>) -> Value {
2909 let s: String = msg.into();
2910 err_v(Value::Str(s.into()))
2911}
2912
2913fn aes_gcm_seal_impl(args: &[Value]) -> Value {
2914 use aes_gcm::aead::{Aead, KeyInit, Payload};
2915 use aes_gcm::{Aes128Gcm, Aes256Gcm, Nonce};
2916 let (key, nonce, aad, plaintext) = match unpack4_bytes(args, "aes_gcm_seal") {
2917 Ok(t) => t,
2918 Err(e) => return aead_err(e),
2919 };
2920 if nonce.len() != 12 {
2921 return aead_err(format!(
2922 "aes_gcm_seal: nonce must be exactly 12 bytes, got {}", nonce.len()
2923 ));
2924 }
2925 let n = Nonce::from_slice(nonce);
2926 let payload = Payload { msg: plaintext, aad };
2927 let combined = match key.len() {
2930 16 => {
2931 let cipher = Aes128Gcm::new_from_slice(key)
2932 .map_err(|e| e.to_string());
2933 match cipher {
2934 Ok(c) => c.encrypt(n, payload).map_err(|e| format!("aes_gcm_seal: {e}")),
2935 Err(e) => Err(format!("aes_gcm_seal: {e}")),
2936 }
2937 }
2938 32 => {
2939 let cipher = Aes256Gcm::new_from_slice(key)
2940 .map_err(|e| e.to_string());
2941 match cipher {
2942 Ok(c) => c.encrypt(n, payload).map_err(|e| format!("aes_gcm_seal: {e}")),
2943 Err(e) => Err(format!("aes_gcm_seal: {e}")),
2944 }
2945 }
2946 other => return aead_err(format!(
2949 "aes_gcm_seal: key must be 16 or 32 bytes, got {other}"
2950 )),
2951 };
2952 match combined {
2953 Ok(mut buf) => {
2954 let tag_start = buf.len() - 16;
2956 let tag = buf.split_off(tag_start);
2957 ok_v(aead_result(buf, tag))
2958 }
2959 Err(e) => aead_err(e),
2960 }
2961}
2962
2963fn aes_gcm_open_impl(args: &[Value]) -> Value {
2964 use aes_gcm::aead::{Aead, KeyInit, Payload};
2965 use aes_gcm::{Aes128Gcm, Aes256Gcm, Nonce};
2966 let (key, nonce, aad, ciphertext, tag) = match unpack5_bytes(args, "aes_gcm_open") {
2967 Ok(t) => t,
2968 Err(e) => return err_v(Value::Str(e.into())),
2969 };
2970 if nonce.len() != 12 {
2971 return err_v(Value::Str(format!(
2972 "aes_gcm_open: nonce must be exactly 12 bytes, got {}", nonce.len()
2973 ).into()));
2974 }
2975 if tag.len() != 16 {
2976 return err_v(Value::Str(format!(
2977 "aes_gcm_open: tag must be exactly 16 bytes, got {}", tag.len()
2978 ).into()));
2979 }
2980 let mut combined = Vec::with_capacity(ciphertext.len() + tag.len());
2982 combined.extend_from_slice(ciphertext);
2983 combined.extend_from_slice(tag);
2984 let n = Nonce::from_slice(nonce);
2985 let payload = Payload { msg: &combined, aad };
2986 let plaintext = match key.len() {
2987 16 => Aes128Gcm::new_from_slice(key)
2988 .map_err(|e| format!("aes_gcm_open: {e}"))
2989 .and_then(|c| c.decrypt(n, payload).map_err(|e| format!("aes_gcm_open: {e}"))),
2990 32 => Aes256Gcm::new_from_slice(key)
2991 .map_err(|e| format!("aes_gcm_open: {e}"))
2992 .and_then(|c| c.decrypt(n, payload).map_err(|e| format!("aes_gcm_open: {e}"))),
2993 other => return err_v(Value::Str(format!(
2994 "aes_gcm_open: key must be 16 or 32 bytes, got {other}"
2995 ).into())),
2996 };
2997 match plaintext {
2998 Ok(p) => ok_v(Value::Bytes(p)),
2999 Err(e) => err_v(Value::Str(e.into())),
3000 }
3001}
3002
3003fn chacha20_seal_impl(args: &[Value]) -> Value {
3004 use chacha20poly1305::aead::{Aead, KeyInit, Payload};
3005 use chacha20poly1305::{ChaCha20Poly1305, Nonce};
3006 let (key, nonce, aad, plaintext) = match unpack4_bytes(args, "chacha20_poly1305_seal") {
3007 Ok(t) => t,
3008 Err(e) => return aead_err(e),
3009 };
3010 if key.len() != 32 {
3011 return aead_err(format!(
3012 "chacha20_poly1305_seal: key must be exactly 32 bytes, got {}", key.len()
3013 ));
3014 }
3015 if nonce.len() != 12 {
3016 return aead_err(format!(
3017 "chacha20_poly1305_seal: nonce must be exactly 12 bytes, got {}", nonce.len()
3018 ));
3019 }
3020 let cipher = ChaCha20Poly1305::new_from_slice(key)
3021 .map_err(|e| format!("chacha20_poly1305_seal: {e}"));
3022 let n = Nonce::from_slice(nonce);
3023 let payload = Payload { msg: plaintext, aad };
3024 let combined = match cipher {
3025 Ok(c) => c.encrypt(n, payload).map_err(|e| format!("chacha20_poly1305_seal: {e}")),
3026 Err(e) => Err(e),
3027 };
3028 match combined {
3029 Ok(mut buf) => {
3030 let tag_start = buf.len() - 16;
3031 let tag = buf.split_off(tag_start);
3032 ok_v(aead_result(buf, tag))
3033 }
3034 Err(e) => aead_err(e),
3035 }
3036}
3037
3038fn chacha20_open_impl(args: &[Value]) -> Value {
3039 use chacha20poly1305::aead::{Aead, KeyInit, Payload};
3040 use chacha20poly1305::{ChaCha20Poly1305, Nonce};
3041 let (key, nonce, aad, ciphertext, tag) = match unpack5_bytes(args, "chacha20_poly1305_open") {
3042 Ok(t) => t,
3043 Err(e) => return err_v(Value::Str(e.into())),
3044 };
3045 if key.len() != 32 {
3046 return err_v(Value::Str(format!(
3047 "chacha20_poly1305_open: key must be exactly 32 bytes, got {}", key.len()
3048 ).into()));
3049 }
3050 if nonce.len() != 12 {
3051 return err_v(Value::Str(format!(
3052 "chacha20_poly1305_open: nonce must be exactly 12 bytes, got {}", nonce.len()
3053 ).into()));
3054 }
3055 if tag.len() != 16 {
3056 return err_v(Value::Str(format!(
3057 "chacha20_poly1305_open: tag must be exactly 16 bytes, got {}", tag.len()
3058 ).into()));
3059 }
3060 let mut combined = Vec::with_capacity(ciphertext.len() + tag.len());
3061 combined.extend_from_slice(ciphertext);
3062 combined.extend_from_slice(tag);
3063 let cipher = ChaCha20Poly1305::new_from_slice(key)
3064 .map_err(|e| format!("chacha20_poly1305_open: {e}"));
3065 let n = Nonce::from_slice(nonce);
3066 let payload = Payload { msg: &combined, aad };
3067 match cipher.and_then(|c| c.decrypt(n, payload).map_err(|e| format!("chacha20_poly1305_open: {e}"))) {
3068 Ok(p) => ok_v(Value::Bytes(p)),
3069 Err(e) => err_v(Value::Str(e.into())),
3070 }
3071}
3072
3073type Kdf4<'a> = (&'a Vec<u8>, &'a Vec<u8>, i64, i64);
3083
3084type Hkdf4<'a> = (&'a Vec<u8>, &'a Vec<u8>, &'a Vec<u8>, i64);
3087
3088type Argon5<'a> = (&'a Vec<u8>, &'a Vec<u8>, i64, i64, i64);
3091
3092fn pick_bytes<'a>(args: &'a [Value], i: usize, op: &str, name: &str)
3093 -> Result<&'a Vec<u8>, String>
3094{
3095 match args.get(i) {
3096 Some(Value::Bytes(b)) => Ok(b),
3097 Some(other) => Err(format!("{op}: {name} must be Bytes, got {other:?}")),
3098 None => Err(format!("{op}: missing {name} argument")),
3099 }
3100}
3101
3102fn pick_int(args: &[Value], i: usize, op: &str, name: &str) -> Result<i64, String> {
3103 match args.get(i) {
3104 Some(Value::Int(n)) => Ok(*n),
3105 Some(other) => Err(format!("{op}: {name} must be Int, got {other:?}")),
3106 None => Err(format!("{op}: missing {name} argument")),
3107 }
3108}
3109
3110fn unpack_kdf4<'a>(args: &'a [Value], op: &str) -> Result<Kdf4<'a>, String> {
3111 Ok((
3112 pick_bytes(args, 0, op, "password")?,
3113 pick_bytes(args, 1, op, "salt")?,
3114 pick_int(args, 2, op, "iterations")?,
3115 pick_int(args, 3, op, "len")?,
3116 ))
3117}
3118
3119fn unpack_hkdf4<'a>(args: &'a [Value], op: &str) -> Result<Hkdf4<'a>, String> {
3120 Ok((
3121 pick_bytes(args, 0, op, "ikm")?,
3122 pick_bytes(args, 1, op, "salt")?,
3123 pick_bytes(args, 2, op, "info")?,
3124 pick_int(args, 3, op, "len")?,
3125 ))
3126}
3127
3128fn unpack_argon5<'a>(args: &'a [Value], op: &str) -> Result<Argon5<'a>, String> {
3129 Ok((
3130 pick_bytes(args, 0, op, "password")?,
3131 pick_bytes(args, 1, op, "salt")?,
3132 pick_int(args, 2, op, "t_cost")?,
3133 pick_int(args, 3, op, "m_cost")?,
3134 pick_int(args, 4, op, "len")?,
3135 ))
3136}
3137
3138const KDF_MAX_LEN: usize = 1024 * 1024;
3143
3144fn check_len(op: &str, len: i64) -> Result<usize, String> {
3145 if len <= 0 {
3146 return Err(format!("{op}: len must be > 0, got {len}"));
3147 }
3148 if (len as u64) > KDF_MAX_LEN as u64 {
3149 return Err(format!(
3150 "{op}: len must be <= {KDF_MAX_LEN}, got {len}"
3151 ));
3152 }
3153 Ok(len as usize)
3154}
3155
3156fn pbkdf2_sha256_impl(args: &[Value]) -> Value {
3157 use hmac::Hmac;
3158 use sha2::Sha256;
3159 let op = "pbkdf2_sha256";
3160 let (password, salt, iterations, len) = match unpack_kdf4(args, op) {
3161 Ok(t) => t,
3162 Err(e) => return err_v(Value::Str(e.into())),
3163 };
3164 if iterations <= 0 {
3165 return err_v(Value::Str(format!(
3166 "{op}: iterations must be > 0, got {iterations}"
3167 ).into()));
3168 }
3169 let out_len = match check_len(op, len) {
3170 Ok(n) => n,
3171 Err(e) => return err_v(Value::Str(e.into())),
3172 };
3173 let rounds = match u32::try_from(iterations) {
3174 Ok(r) => r,
3175 Err(_) => {
3176 return err_v(Value::Str(format!(
3177 "{op}: iterations must fit in u32, got {iterations}"
3178 ).into()))
3179 }
3180 };
3181 let mut out = vec![0u8; out_len];
3182 if let Err(e) = pbkdf2::pbkdf2::<Hmac<Sha256>>(password, salt, rounds, &mut out) {
3183 return err_v(Value::Str(format!("{op}: {e}").into()));
3184 }
3185 ok_v(Value::Bytes(out))
3186}
3187
3188fn hkdf_sha256_impl(args: &[Value]) -> Value {
3189 use hkdf::Hkdf;
3190 use sha2::Sha256;
3191 let op = "hkdf_sha256";
3192 let (ikm, salt, info, len) = match unpack_hkdf4(args, op) {
3193 Ok(t) => t,
3194 Err(e) => return err_v(Value::Str(e.into())),
3195 };
3196 let out_len = match check_len(op, len) {
3197 Ok(n) => n,
3198 Err(e) => return err_v(Value::Str(e.into())),
3199 };
3200 let salt_opt: Option<&[u8]> = if salt.is_empty() { None } else { Some(salt) };
3203 let hk = Hkdf::<Sha256>::new(salt_opt, ikm);
3204 let mut out = vec![0u8; out_len];
3205 match hk.expand(info, &mut out) {
3206 Ok(()) => ok_v(Value::Bytes(out)),
3207 Err(e) => err_v(Value::Str(format!("{op}: {e}").into())),
3208 }
3209}
3210
3211fn argon2id_impl(args: &[Value]) -> Value {
3212 use argon2::{Algorithm, Argon2, Params, Version};
3213 let op = "argon2id";
3214 let (password, salt, t_cost, m_cost, len) = match unpack_argon5(args, op) {
3215 Ok(t) => t,
3216 Err(e) => return err_v(Value::Str(e.into())),
3217 };
3218 let out_len = match check_len(op, len) {
3219 Ok(n) => n,
3220 Err(e) => return err_v(Value::Str(e.into())),
3221 };
3222 let t = match u32::try_from(t_cost) {
3223 Ok(n) if n >= 1 => n,
3224 _ => return err_v(Value::Str(format!(
3225 "{op}: t_cost must be a u32 >= 1, got {t_cost}"
3226 ).into())),
3227 };
3228 let m = match u32::try_from(m_cost) {
3229 Ok(n) if n >= Params::MIN_M_COST => n,
3230 _ => return err_v(Value::Str(format!(
3231 "{op}: m_cost must be a u32 >= {}, got {m_cost}",
3232 Params::MIN_M_COST
3233 ).into())),
3234 };
3235 let params = match Params::new(m, t, 1, Some(out_len)) {
3240 Ok(p) => p,
3241 Err(e) => return err_v(Value::Str(format!("{op}: {e}").into())),
3242 };
3243 let hasher = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
3244 let mut out = vec![0u8; out_len];
3245 if let Err(e) = hasher.hash_password_into(password, salt, &mut out) {
3246 return err_v(Value::Str(format!("{op}: {e}").into()));
3247 }
3248 ok_v(Value::Bytes(out))
3249}