1pub mod component;
4pub mod robot;
5pub mod simulation;
6pub mod structure;
7
8pub use robot::{ROBOT_SCHEMA, Robot, RobotIdentity};
9
10#[doc(hidden)]
12pub mod __private {
13 pub fn structure_from_compiler_value(
16 document: serde_json::Value,
17 ) -> Result<crate::structure::Structure, crate::ModelError> {
18 crate::structure::Structure::from_compiler_value(document)
19 }
20}
21
22#[derive(Debug, thiserror::Error)]
24pub enum ModelError {
25 #[error("{0}")]
26 Invalid(String),
27}
28
29#[derive(Debug, thiserror::Error)]
31#[error("failed to encode canonical robot: {0}")]
32pub struct EncodeError(#[from] serde_json::Error);
33
34#[derive(Debug, thiserror::Error)]
36pub enum DecodeError {
37 #[error("invalid canonical robot JSON: {0}")]
38 Json(#[from] serde_json::Error),
39 #[error("unsupported robot schema '{0}'")]
40 UnsupportedSchema(String),
41 #[error("invalid canonical robot: {0}")]
42 Model(#[from] ModelError),
43}
44
45mod strict_json {
46 use std::collections::BTreeMap;
47
48 use serde::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
49 use serde_json::{Number, Value};
50
51 use crate::DecodeError;
52
53 pub(crate) fn parse(bytes: &[u8]) -> Result<Value, DecodeError> {
54 let mut deserializer = serde_json::Deserializer::from_slice(bytes);
55 let value = StrictValue::deserialize(&mut deserializer)?.0;
56 deserializer.end()?;
57 Ok(value)
58 }
59
60 struct StrictValue(Value);
61
62 impl<'de> Deserialize<'de> for StrictValue {
63 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
64 deserializer.deserialize_any(StrictVisitor)
65 }
66 }
67
68 struct StrictVisitor;
69
70 impl<'de> Visitor<'de> for StrictVisitor {
71 type Value = StrictValue;
72
73 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 formatter.write_str("a JSON value without duplicate object fields")
75 }
76
77 fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> {
78 Ok(StrictValue(Value::Bool(value)))
79 }
80
81 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
82 Ok(StrictValue(Value::Number(Number::from(value))))
83 }
84
85 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
86 Ok(StrictValue(Value::Number(Number::from(value))))
87 }
88
89 fn visit_f64<E: serde::de::Error>(self, value: f64) -> Result<Self::Value, E> {
90 Number::from_f64(value)
91 .map(Value::Number)
92 .map(StrictValue)
93 .ok_or_else(|| E::custom("non-finite JSON number"))
94 }
95
96 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> {
97 Ok(StrictValue(Value::String(value.to_string())))
98 }
99
100 fn visit_string<E>(self, value: String) -> Result<Self::Value, E> {
101 Ok(StrictValue(Value::String(value)))
102 }
103
104 fn visit_none<E>(self) -> Result<Self::Value, E> {
105 Ok(StrictValue(Value::Null))
106 }
107
108 fn visit_unit<E>(self) -> Result<Self::Value, E> {
109 Ok(StrictValue(Value::Null))
110 }
111
112 fn visit_seq<A: SeqAccess<'de>>(self, mut sequence: A) -> Result<Self::Value, A::Error> {
113 let mut values = Vec::new();
114 while let Some(value) = sequence.next_element::<StrictValue>()? {
115 values.push(value.0);
116 }
117 Ok(StrictValue(Value::Array(values)))
118 }
119
120 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
121 let mut values = BTreeMap::new();
122 while let Some((key, value)) = map.next_entry::<String, StrictValue>()? {
123 if values.insert(key.clone(), value.0).is_some() {
124 return Err(serde::de::Error::custom(format!(
125 "duplicate JSON object field '{key}'"
126 )));
127 }
128 }
129 Ok(StrictValue(Value::Object(values.into_iter().collect())))
130 }
131 }
132}