Skip to main content

runmat_execution/value/
mod.rs

1use serde::{Deserialize, Serialize};
2
3use crate::identity::{Digest, NodeLeaseId, ValueId, WorkerId};
4use crate::ContractError;
5
6mod identity;
7mod validation;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
10pub struct ValueLimits {
11    pub max_depth: u16,
12    pub max_nodes: u64,
13    pub max_inline_bytes: u64,
14    pub max_elements: u64,
15    pub max_fields: u32,
16    pub max_text_bytes: u64,
17}
18
19impl Default for ValueLimits {
20    fn default() -> Self {
21        Self {
22            max_depth: 64,
23            max_nodes: 1_000_000,
24            max_inline_bytes: 1024 * 1024,
25            max_elements: 100_000_000,
26            max_fields: 100_000,
27            max_text_bytes: 16 * 1024 * 1024,
28        }
29    }
30}
31
32#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
33#[serde(rename_all = "snake_case", tag = "form", content = "value")]
34pub enum ValuePayload {
35    Inline(Box<InlineValue>),
36    Object(Box<ValueRef>),
37}
38
39impl ValuePayload {
40    pub fn validate(&self, limits: ValueLimits) -> Result<(), ContractError> {
41        validation::validate(self, limits)
42    }
43
44    pub fn logical_digest(&self) -> Result<Digest, ContractError> {
45        identity::logical_digest(self)
46    }
47}
48
49#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
50#[serde(rename_all = "snake_case", tag = "type", content = "value")]
51pub enum InlineValue {
52    Null,
53    Logical(bool),
54    F64Bits(u64),
55    I8(i8),
56    I16(i16),
57    I32(i32),
58    I64(i64),
59    U8(u8),
60    U16(u16),
61    U32(u32),
62    U64(u64),
63    ComplexF64Bits {
64        real: u64,
65        imaginary: u64,
66    },
67    String(String),
68    Char {
69        shape: Vec<u64>,
70        code_points: Vec<u32>,
71    },
72    StringArray {
73        shape: Vec<u64>,
74        values: Vec<String>,
75    },
76    Dense(DenseValue),
77    Sparse(SparseValue),
78    Symbolic(RegisteredData),
79    Cell {
80        shape: Vec<u64>,
81        values: Vec<ValuePayload>,
82    },
83    Struct(Vec<StructField>),
84    OutputList(Vec<ValuePayload>),
85    Exception(ExceptionValue),
86    Callable(CallableValue),
87    ImmutableValueClass(RegisteredData),
88}
89
90#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
91pub struct DenseValue {
92    pub element_type: ElementType,
93    pub shape: Vec<u64>,
94    pub little_endian_data: Vec<u8>,
95}
96
97#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
98pub struct SparseValue {
99    pub element_type: ElementType,
100    pub rows: u64,
101    pub columns: u64,
102    pub column_offsets: Vec<u64>,
103    pub row_indices: Vec<u64>,
104    pub little_endian_data: Vec<u8>,
105}
106
107#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
108#[serde(rename_all = "snake_case")]
109#[repr(u8)]
110pub enum ElementType {
111    Logical = 0,
112    F32 = 1,
113    F64 = 2,
114    ComplexF64 = 3,
115    I8 = 4,
116    I16 = 5,
117    I32 = 6,
118    I64 = 7,
119    U8 = 8,
120    U16 = 9,
121    U32 = 10,
122    U64 = 11,
123    ComplexF32 = 12,
124    ComplexI8 = 13,
125    ComplexI16 = 14,
126    ComplexI32 = 15,
127    ComplexI64 = 16,
128    ComplexU8 = 17,
129    ComplexU16 = 18,
130    ComplexU32 = 19,
131    ComplexU64 = 20,
132}
133
134impl ElementType {
135    const fn byte_width(self) -> u64 {
136        match self {
137            Self::Logical | Self::I8 | Self::U8 => 1,
138            Self::I16 | Self::U16 => 2,
139            Self::F32 | Self::I32 | Self::U32 => 4,
140            Self::F64 | Self::I64 | Self::U64 => 8,
141            Self::ComplexI8 | Self::ComplexU8 => 2,
142            Self::ComplexF32 | Self::ComplexI32 | Self::ComplexU32 => 8,
143            Self::ComplexI16 | Self::ComplexU16 => 4,
144            Self::ComplexI64 | Self::ComplexU64 => 16,
145            Self::ComplexF64 => 16,
146        }
147    }
148}
149
150#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
151pub struct StructField {
152    pub name: String,
153    pub value: ValuePayload,
154}
155
156#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
157pub struct RegisteredData {
158    pub type_identity: String,
159    pub schema_version: u32,
160    pub fields: Vec<RegisteredField>,
161}
162
163#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
164pub struct RegisteredField {
165    pub name: String,
166    pub value: ValuePayload,
167}
168
169#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
170pub struct ExceptionValue {
171    pub identifier: String,
172    pub message: String,
173    pub stack: Vec<String>,
174    pub causes: Vec<ExceptionValue>,
175}
176
177#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
178pub struct CallableValue {
179    pub owner_identity: String,
180    pub qualified_name: String,
181    pub callable_digest: Digest,
182    pub captures: Vec<ValuePayload>,
183}
184
185impl CallableValue {
186    pub fn identity_digest(owner_identity: &str, qualified_name: &str) -> Digest {
187        let mut identity = b"runmat-callable-v1\0".to_vec();
188        identity.extend_from_slice(owner_identity.as_bytes());
189        identity.push(0);
190        identity.extend_from_slice(qualified_name.as_bytes());
191        Digest::sha256(identity)
192    }
193
194    pub fn validate_identity(&self) -> Result<(), ContractError> {
195        if self.callable_digest != Self::identity_digest(&self.owner_identity, &self.qualified_name)
196        {
197            return Err(ContractError::invalid(
198                "callable value",
199                "callable digest does not match its owner and qualified name",
200            ));
201        }
202        Ok(())
203    }
204}
205
206#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
207pub struct ValueRef {
208    pub schema_version: u16,
209    pub id: ValueId,
210    pub logical_digest: Digest,
211    pub encoded_length: u64,
212    pub media_type: String,
213    pub value_schema: String,
214    pub encryption_context: Digest,
215    pub kind: ValueRefKind,
216    pub authorization_scope: String,
217    pub resident_fence: Option<ResidentFence>,
218}
219
220#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
221#[serde(rename_all = "snake_case")]
222pub enum ValueRefKind {
223    DriverObject,
224    WorkerObject,
225    ProjectObject,
226    BroadcastObject,
227    SlicedObject,
228    ResultObject,
229    CheckpointObject,
230    ResidentObject,
231}
232
233#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
234pub struct ResidentFence {
235    pub worker_id: WorkerId,
236    pub node_lease_id: NodeLeaseId,
237    pub process_generation: u64,
238    pub device_identity: Option<String>,
239}