Skip to main content

eure_document/
value.rs

1use num_bigint::BigInt;
2
3use crate::{prelude_internal::*, text::Text};
4
5#[derive(Debug, Clone, PartialEq, Copy)]
6pub enum ValueKind {
7    Hole,
8    Null,
9    Bool,
10    Integer,
11    F32,
12    F64,
13    Text,
14    Array,
15    Tuple,
16    Map,
17}
18
19impl core::fmt::Display for ValueKind {
20    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
21        match self {
22            Self::Hole => write!(f, "hole"),
23            Self::Null => write!(f, "null"),
24            Self::Bool => write!(f, "bool"),
25            Self::Integer => write!(f, "integer"),
26            Self::F32 => write!(f, "f32"),
27            Self::F64 => write!(f, "f64"),
28            Self::Text => write!(f, "text"),
29            Self::Array => write!(f, "array"),
30            Self::Tuple => write!(f, "tuple"),
31            Self::Map => write!(f, "map"),
32        }
33    }
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub enum PrimitiveValue {
38    Null,
39    Bool(bool),
40    Integer(BigInt),
41    F32(f32),
42    F64(f64),
43    /// Unified text type for strings and code.
44    ///
45    /// - `"..."` syntax produces `Text` with `Language::Plaintext`
46    /// - `` `...` `` syntax produces `Text` with `Language::Implicit`
47    /// - `` lang`...` `` syntax produces `Text` with `Language::Other(lang)`
48    Text(Text),
49}
50
51impl PrimitiveValue {
52    /// Returns the text if this is a `Text` variant.
53    pub fn as_text(&self) -> Option<&Text> {
54        if let Self::Text(text) = self {
55            Some(text)
56        } else {
57            None
58        }
59    }
60
61    /// Returns the text content as a string slice if this is a `Text` variant.
62    pub fn as_str(&self) -> Option<&str> {
63        self.as_text().map(|t| t.as_str())
64    }
65
66    pub(crate) fn kind(&self) -> ValueKind {
67        match self {
68            Self::Null => ValueKind::Null,
69            Self::Bool(_) => ValueKind::Bool,
70            Self::Integer(_) => ValueKind::Integer,
71            Self::F32(_) => ValueKind::F32,
72            Self::F64(_) => ValueKind::F64,
73            Self::Text(_) => ValueKind::Text,
74        }
75    }
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
79/// Key-comparable value which implements `Eq` and `Hash`.
80///
81/// Eure restricts map keys to three types — `String`, `Number` (BigInt),
82/// and `Tuple<ObjectKey>` — for practical and predictable behavior.
83///
84/// - **Deterministic equality:**
85///   These types provide stable, well-defined equality and hashing.
86///   Types like floats, null, or holes introduce ambiguous or
87///   platform-dependent comparison rules.
88///
89/// - **Reliable round-tripping:**
90///   Keys must serialize and deserialize without losing meaning.
91///   Strings, integers, and tuples have canonical and unambiguous textual forms.
92///
93/// - **Tooling-friendly:**
94///   This set balances expressiveness and simplicity, making keys easy
95///   to validate, index, and reason about across implementations.
96///
97/// Note: In key position, `true`, `false`, and `null` are parsed as string
98/// identifiers, not as boolean/null values. For example, `a.true = true`
99/// creates a key `"true"` with boolean value `true`.
100pub enum ObjectKey {
101    Number(BigInt),
102    String(String),
103    Tuple(Tuple<ObjectKey>),
104}
105
106impl core::fmt::Display for ObjectKey {
107    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108        match self {
109            ObjectKey::Number(n) => write!(f, "{}", n),
110            ObjectKey::String(s) => {
111                write!(f, "\"")?;
112                for c in s.chars() {
113                    match c {
114                        '"' => write!(f, "\\\"")?,
115                        '\\' => write!(f, "\\\\")?,
116                        _ => write!(f, "{}", c)?,
117                    }
118                }
119                write!(f, "\"")
120            }
121            ObjectKey::Tuple(t) => write!(f, "{}", t),
122        }
123    }
124}
125
126impl From<&str> for ObjectKey {
127    fn from(s: &str) -> Self {
128        ObjectKey::String(s.to_string())
129    }
130}
131
132impl From<String> for ObjectKey {
133    fn from(s: String) -> Self {
134        ObjectKey::String(s)
135    }
136}
137
138impl From<bool> for ObjectKey {
139    fn from(b: bool) -> Self {
140        ObjectKey::String(if b { "true" } else { "false" }.to_string())
141    }
142}
143
144macro_rules! impl_from_int_for_object_key {
145    ($($ty:ty),*) => {
146        $(
147            impl From<$ty> for ObjectKey {
148                fn from(n: $ty) -> Self {
149                    ObjectKey::Number(BigInt::from(n))
150                }
151            }
152        )*
153    };
154}
155
156impl_from_int_for_object_key!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
157
158impl From<BigInt> for ObjectKey {
159    fn from(n: BigInt) -> Self {
160        ObjectKey::Number(n)
161    }
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Plural, Default)]
165pub struct Tuple<T>(pub Vec<T>);
166
167impl core::fmt::Display for Tuple<ObjectKey> {
168    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
169        write!(f, "(")?;
170        for (i, item) in self.0.iter().enumerate() {
171            if i != 0 {
172                write!(f, ", ")?;
173            }
174            write!(f, "{}", item)?;
175        }
176        write!(f, ")")
177    }
178}
179
180// ============================================================================
181// From implementations for PrimitiveValue
182// ============================================================================
183
184impl From<bool> for PrimitiveValue {
185    fn from(b: bool) -> Self {
186        PrimitiveValue::Bool(b)
187    }
188}
189
190macro_rules! impl_from_int_for_primitive_value {
191    ($($ty:ty),*) => {
192        $(
193            impl From<$ty> for PrimitiveValue {
194                fn from(n: $ty) -> Self {
195                    PrimitiveValue::Integer(BigInt::from(n))
196                }
197            }
198        )*
199    };
200}
201
202impl_from_int_for_primitive_value!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
203
204impl From<f32> for PrimitiveValue {
205    fn from(n: f32) -> Self {
206        PrimitiveValue::F32(n)
207    }
208}
209
210impl From<f64> for PrimitiveValue {
211    fn from(n: f64) -> Self {
212        PrimitiveValue::F64(n)
213    }
214}
215
216impl From<&str> for PrimitiveValue {
217    fn from(s: &str) -> Self {
218        PrimitiveValue::Text(Text::plaintext(s))
219    }
220}
221
222impl From<String> for PrimitiveValue {
223    fn from(s: String) -> Self {
224        PrimitiveValue::Text(Text::plaintext(s))
225    }
226}
227
228impl From<Text> for PrimitiveValue {
229    fn from(t: Text) -> Self {
230        PrimitiveValue::Text(t)
231    }
232}