aleph_syntax_tree/effects.rs
1use serde::{Deserialize, Serialize};
2use std::collections::BTreeSet;
3
4/// What a function is declared to be able to do. Attached to a subtree via
5/// `AlephTree::WithEffects`. A function whose effect row is `[Pure]` cannot
6/// call one whose row includes `Io`, `Net`, `Mut`, or `Act` — that check is
7/// the type/effect checker's job, not this crate's; this crate only defines
8/// the vocabulary.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
10pub enum Effect {
11 /// No observable side effect.
12 Pure,
13 /// Reads or writes outside the program (files, stdout, environment).
14 Io,
15 /// Network access.
16 Net,
17 /// Mutates shared/external state in place.
18 Mut,
19 /// Invokes the cognitive runtime (`Intend`/`Suggest`/`Act`/`Remember`/`Perceive`).
20 Act,
21}
22
23/// A function's declared effect row. `BTreeSet`, not `Vec`: duplicates are
24/// meaningless here, and — unlike `HashSet` — iteration order is fixed, so
25/// two structurally-identical effect rows always serialize to identical
26/// bytes (required for deterministic content hashing elsewhere in this crate).
27pub type EffectSet = BTreeSet<Effect>;
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32
33 #[test]
34 fn serializes_and_round_trips_through_json() {
35 let effects: EffectSet = EffectSet::from([Effect::Io, Effect::Act]);
36 let json = serde_json::to_string(&effects).unwrap();
37 let back: EffectSet = serde_json::from_str(&json).unwrap();
38 assert_eq!(effects, back);
39 }
40
41 #[test]
42 fn json_wire_format_is_locked() {
43 // Guards against an accidental #[serde(rename_all = ...)] or
44 // re-tagging change silently breaking non-Rust consumers.
45 assert_eq!(serde_json::to_string(&Effect::Io).unwrap(), "\"Io\"");
46 assert_eq!(serde_json::to_string(&Effect::Act).unwrap(), "\"Act\"");
47 }
48
49 #[test]
50 fn duplicates_collapse_and_serialization_order_is_stable() {
51 let a: EffectSet = EffectSet::from([Effect::Act, Effect::Io, Effect::Io]);
52 let b: EffectSet = EffectSet::from([Effect::Io, Effect::Act]);
53 assert_eq!(a, b);
54 assert_eq!(serde_json::to_string(&a).unwrap(), serde_json::to_string(&b).unwrap());
55 }
56}