Skip to main content

verit_core/
value.rs

1//! Dynamic values for the write path. The prototype has no codegen; you build
2//! a `Value` tree against a runtime [`crate::Schema`] and encode it. A struct
3//! value lists (field id, value) pairs — omitted fields are absent (their
4//! presence bit stays 0 and readers see `None`).
5
6#[derive(Clone, Debug, PartialEq)]
7pub enum Value {
8    Bool(bool),
9    U8(u8),
10    U16(u16),
11    U32(u32),
12    U64(u64),
13    I8(i8),
14    I16(i16),
15    I32(i32),
16    I64(i64),
17    F32(f32),
18    F64(f64),
19    Str(String),
20    Bytes(Vec<u8>),
21    /// Raw enum value; enums are open, so this need not name a known variant.
22    Enum(u32),
23    List(Vec<Value>),
24    /// (field id, value) pairs. Order does not matter; duplicate ids are an
25    /// encode-time error.
26    Struct(Vec<(u16, Value)>),
27    /// (key, value) entries. Order does not matter — the encoder sorts entries
28    /// by key into canonical order; duplicate keys are an encode-time error.
29    Map(Vec<(Value, Value)>),
30    /// A list of scalars in native form — the bulk-write peer of
31    /// [`Scalars`]. Encodes byte-identically to the equivalent
32    /// [`Value::List`], without allocating a `Value` per element.
33    Scalars(Scalars),
34    /// A `union` value: the variant tag (index into the schema's variant list)
35    /// and that variant's value.
36    Union(u32, Box<Value>),
37}
38
39impl Value {
40    pub fn str(s: &str) -> Value {
41        Value::Str(s.to_string())
42    }
43
44    /// A `list<f32>` from a slice, without building a `Value` per element —
45    /// the shape an embedding vector wants.
46    pub fn f32_list(xs: &[f32]) -> Value {
47        Value::Scalars(Scalars::F32(xs.to_vec()))
48    }
49
50    /// A `list<f64>` from a slice.
51    pub fn f64_list(xs: &[f64]) -> Value {
52        Value::Scalars(Scalars::F64(xs.to_vec()))
53    }
54
55    pub fn kind(&self) -> &'static str {
56        match self {
57            Value::Bool(_) => "bool",
58            Value::U8(_) => "u8",
59            Value::U16(_) => "u16",
60            Value::U32(_) => "u32",
61            Value::U64(_) => "u64",
62            Value::I8(_) => "i8",
63            Value::I16(_) => "i16",
64            Value::I32(_) => "i32",
65            Value::I64(_) => "i64",
66            Value::F32(_) => "f32",
67            Value::F64(_) => "f64",
68            Value::Str(_) => "string",
69            Value::Bytes(_) => "bytes",
70            Value::Enum(_) => "enum",
71            Value::List(_) => "list",
72            Value::Struct(_) => "struct",
73            Value::Map(_) => "map",
74            Value::Scalars(s) => s.kind(),
75            Value::Union(..) => "union",
76        }
77    }
78}
79
80/// A run of scalars held in its native Rust form.
81///
82/// Building a `list<f32>` of 1,536 elements as [`Value::List`] allocates 1,536
83/// `Value` enums before a single byte is written — fine for a one-off
84/// conversion, wrong for a hot write path. This carries the values as they
85/// already are, and the encoder writes the whole run in one pass.
86///
87/// The output is **byte-identical** to the equivalent `Value::List`, so this is
88/// purely a cost choice and never a wire-format one.
89#[derive(Clone, Debug, PartialEq)]
90pub enum Scalars {
91    Bool(Vec<bool>),
92    U8(Vec<u8>),
93    U16(Vec<u16>),
94    U32(Vec<u32>),
95    U64(Vec<u64>),
96    I8(Vec<i8>),
97    I16(Vec<i16>),
98    I32(Vec<i32>),
99    I64(Vec<i64>),
100    F32(Vec<f32>),
101    F64(Vec<f64>),
102}
103
104impl Scalars {
105    pub fn len(&self) -> usize {
106        match self {
107            Scalars::Bool(v) => v.len(),
108            Scalars::U8(v) => v.len(),
109            Scalars::U16(v) => v.len(),
110            Scalars::U32(v) => v.len(),
111            Scalars::U64(v) => v.len(),
112            Scalars::I8(v) => v.len(),
113            Scalars::I16(v) => v.len(),
114            Scalars::I32(v) => v.len(),
115            Scalars::I64(v) => v.len(),
116            Scalars::F32(v) => v.len(),
117            Scalars::F64(v) => v.len(),
118        }
119    }
120
121    pub fn is_empty(&self) -> bool {
122        self.len() == 0
123    }
124
125    pub fn kind(&self) -> &'static str {
126        match self {
127            Scalars::Bool(_) => "list<bool>",
128            Scalars::U8(_) => "list<u8>",
129            Scalars::U16(_) => "list<u16>",
130            Scalars::U32(_) => "list<u32>",
131            Scalars::U64(_) => "list<u64>",
132            Scalars::I8(_) => "list<i8>",
133            Scalars::I16(_) => "list<i16>",
134            Scalars::I32(_) => "list<i32>",
135            Scalars::I64(_) => "list<i64>",
136            Scalars::F32(_) => "list<f32>",
137            Scalars::F64(_) => "list<f64>",
138        }
139    }
140}