Skip to main content

cairn_core/
ty.rs

1//! The value-level model: types, confidence, effects.
2//!
3//! These are the fixed, closed vocabularies from `docs/design.md` Section 4.
4//! They are deliberately small; nothing is added here that a check does not
5//! need.
6
7use serde::{Deserialize, Serialize};
8use std::collections::BTreeSet;
9
10/// The v1 type set. `Named` is a user-defined record or variant referenced
11/// by name; its definition is supplied via `define_type`/`TypeDefSpec`
12/// (shipped — records carry fields, variants carry cases, and the checker
13/// resolves them: field access is typed, `Match` is exhaustiveness-checked).
14/// `Named` is equal **by name** — nominal, monomorphic type identity. That
15/// is the *decided* design (§9, Principle 9: one canonical form), not a
16/// stopgap: there is no structural or generic type equality, by choice.
17#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
18pub enum Type {
19    Number,
20    /// An IEEE-754 double. Travels in the uniform i64 slot as its bit
21    /// pattern; only float operations reinterpret it.
22    Float,
23    /// Fixed-point decimal: an i64 scaled by 10_000 (four fractional
24    /// digits). Exact, no NaN — the money/review-safe non-integer type.
25    Decimal,
26    String,
27    Bool,
28    Bytes,
29    List(Box<Type>),
30    Map(Box<Type>, Box<Type>),
31    Option(Box<Type>),
32    Result(Box<Type>, Box<Type>),
33    Named(String),
34    /// A mutable cell holding a `T` (the `Mut` effect's value type).
35    Cell(Box<Type>),
36    /// A first-class function value. `effects` are what *calling* it
37    /// performs; they union into the caller at the call site. The bottom
38    /// confidence of a call's value is conservative (Structural), so the
39    /// produced confidence is not part of the type (a documented v0.4
40    /// simplification — it only ever under-claims, never over-claims).
41    Fn {
42        params: Vec<Type>,
43        ret: Box<Type>,
44        effects: BTreeSet<Effect>,
45    },
46    /// A type variable: a function's declared type parameter (e.g. `T`).
47    /// Within a generic function's body it is an opaque nominal type; at a
48    /// call site it is unified against the actual argument types.
49    Var(String),
50    /// The bottom type: the "type" of an expression that diverges (`fail`)
51    /// and never yields a value. Compatible with every type, because an
52    /// expression that never returns can stand wherever a value is expected.
53    Never,
54}
55
56/// Epistemic status. The derived `Ord` is the total order from Section 4 —
57/// declaration order is the order: `External < Structural < Validated <
58/// Persisted`. Weakest-input propagation is `min` over this order.
59#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)]
60pub enum Confidence {
61    External,
62    Structural,
63    Validated,
64    Persisted,
65}
66
67/// The nine effect primitives. `Ord` is derived so effect sets can be a
68/// `BTreeSet`, which keeps node serialization (and therefore hashing)
69/// deterministic.
70#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)]
71pub enum Effect {
72    Net,
73    Disk,
74    Db,
75    Mut,
76    Time,
77    Rand,
78    Log,
79    /// Out-of-band UI push (design.md §10): `publish(topic)` performs it.
80    /// Making liveness an effect keeps it visible in signatures and
81    /// checked — never a hidden default.
82    Live,
83    /// Response shaping: `set_header(name, value)` emits an extra HTTP
84    /// response header (e.g. `Set-Cookie`). Buffered per request on the
85    /// same thread-local seam as `publish`/`Live`, drained and emitted
86    /// by the host server. An effect, not a `Response` field, so it is
87    /// visible in signatures and checked — never a hidden default
88    /// (design.md §9).
89    Resp,
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn confidence_total_order_matches_section_4() {
98        use Confidence::*;
99        assert!(External < Structural);
100        assert!(Structural < Validated);
101        assert!(Validated < Persisted);
102        // weakest-input propagation is `min`
103        assert_eq!(std::cmp::min(Persisted, External), External);
104        assert_eq!(std::cmp::min(Validated, Structural), Structural);
105    }
106}