Skip to main content

tancore/
set.rs

1use std::collections::HashSet;
2
3use tan::{
4    context::Context,
5    error::Error,
6    expr::{expr_clone, Expr},
7    util::module_util::require_module,
8};
9
10// #insight there isn alternative implementation in `set-alt.rs`.
11
12pub fn set_new(_args: &[Expr]) -> Result<Expr, Error> {
13    // #todo Expr has interior mutability, not the best for a Set key.
14    let set: HashSet<Expr> = HashSet::new();
15    Ok(Expr::set(set))
16}
17
18pub fn set_put(args: &[Expr]) -> Result<Expr, Error> {
19    let [this, value] = args else {
20        return Err(Error::invalid_arguments(
21            "requires `this` and `value` arguments",
22            None,
23        ));
24    };
25
26    let Some(mut items) = this.as_set_mut() else {
27        return Err(Error::invalid_arguments(
28            "`this` argument should be a Set",
29            this.range(),
30        ));
31    };
32
33    // #insight don't put annotated values in the Set.
34
35    // #todo hmmm this clone!
36    items.insert(expr_clone(value.unpack()));
37
38    // #todo what should we return here?
39    Ok(Expr::None)
40}
41
42// #todo set_values is a _weird_ name!
43// #todo consider other names, e.g. items?
44pub fn set_values(args: &[Expr]) -> Result<Expr, Error> {
45    let [this] = args else {
46        return Err(Error::invalid_arguments("requires `this` argument", None));
47    };
48
49    let Some(items) = this.as_set_mut() else {
50        return Err(Error::invalid_arguments(
51            "`this` argument should be a Set",
52            this.range(),
53        ));
54    };
55
56    let values: Vec<_> = items.iter().map(expr_clone).collect();
57    Ok(Expr::array(values))
58}
59
60pub fn import_lib_set(context: &mut Context) {
61    // #tod op consider other paths, e.g. data/set, collections/set, collection/set, etc?
62    let module = require_module("set", context);
63
64    module.insert_invocable("Set", Expr::foreign_func(&set_new));
65
66    // #todo #hack temp fix!
67    // #todo really need to improve signature matching and e.g. support put$$Set$$Expr or put$$Set$$Any
68    module.insert_invocable("put$$Set$$Int", Expr::foreign_func(&set_put));
69    module.insert_invocable("put$$Set$$Float", Expr::foreign_func(&set_put));
70    module.insert_invocable("put$$Set$$String", Expr::foreign_func(&set_put));
71    // #todo investigate why this is needed!
72    // #todo better solution: use Expr::Method or Expr::Multi for foreign functions and functions.
73    module.insert_invocable("values-of", Expr::foreign_func(&set_values));
74    module.insert_invocable("values-of$$Set", Expr::foreign_func(&set_values));
75}