konjure_lang/
inspection.rs1use crate::{Snapshot, Value};
3use konjure_sdk::data::{TensorInspection, TensorInspectionOptions, inspect_tensor};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
9#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
10pub enum InspectionRoot {
11 Global {
13 name: String,
15 },
16 Component {
18 #[cfg_attr(feature = "typescript", ts(type = "number"))]
20 entity: u64,
21 component: String,
23 },
24}
25
26#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
28#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
29#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
30pub enum InspectionStep {
31 Field {
33 name: String,
35 },
36 Index {
38 index: u32,
40 },
41 Payload {
43 index: u32,
45 },
46}
47
48#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
50#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
51#[serde(deny_unknown_fields)]
52pub struct InspectionTarget {
53 pub root: InspectionRoot,
55 #[serde(default)]
57 pub path: Vec<InspectionStep>,
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
62#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
63#[serde(rename_all = "snake_case")]
64pub enum InspectionError {
65 InvalidTarget,
67 MissingValue,
69 NotTensor,
71 InvalidTensor,
73 Encoding,
75}
76
77impl Snapshot {
78 pub fn inspection_value(&self, target: &InspectionTarget) -> Result<&Value, InspectionError> {
80 let valid_name = |name: &str| !name.is_empty() && name.len() <= 512;
81 if target.path.len() > 16 {
82 return Err(InspectionError::InvalidTarget);
83 }
84 let mut value = match &target.root {
85 InspectionRoot::Global { name } if valid_name(name) => self.globals.get(name),
86 InspectionRoot::Component { entity, component } if valid_name(component) => self
87 .entities
88 .iter()
89 .find(|candidate| candidate.id == *entity)
90 .and_then(|candidate| candidate.components.get(component)),
91 _ => return Err(InspectionError::InvalidTarget),
92 }
93 .ok_or(InspectionError::MissingValue)?;
94 for step in &target.path {
95 value = match (step, value) {
96 (InspectionStep::Field { name }, Value::Record(record)) if valid_name(name) => {
97 record.fields.get(name)
98 }
99 (InspectionStep::Index { index }, Value::List(values)) => {
100 values.get(*index as usize)
101 }
102 (InspectionStep::Payload { index }, Value::Enum(value)) => {
103 value.payload.get(*index as usize)
104 }
105 _ => None,
106 }
107 .ok_or(InspectionError::MissingValue)?;
108 }
109 Ok(value)
110 }
111
112 pub fn tensor_inspection(
117 &self,
118 target: &InspectionTarget,
119 ) -> Result<TensorInspection, InspectionError> {
120 let Value::Tensor(tensor) = self.inspection_value(target)? else {
121 return Err(InspectionError::NotTensor);
122 };
123 inspect_tensor(tensor, TensorInspectionOptions::default())
124 .map_err(|_| InspectionError::InvalidTensor)
125 }
126}