wip_protocol/model.rs
1use std::collections::BTreeMap;
2
3use crate::{ProtocolError, ValidationError};
4
5/// Human-readable plain-text documentation attached to a protocol declaration.
6#[derive(Debug, Clone, PartialEq, Eq, Default)]
7pub struct Documentation {
8 /// A short, self-contained description.
9 pub summary: String,
10 /// Optional extended documentation.
11 pub details: Option<String>,
12}
13
14/// The protocol projection currently published at one Worldspace path.
15///
16/// `name` is a path segment, `interfaces` is an ordered set of opaque interface
17/// references, `r#ref` is optional object identity, and `validator` is an
18/// independent optional observation precondition. In particular, neither the
19/// path nor `r#ref` is a mandatory object identifier.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct Object {
22 /// Path-segment name. The root object's name is empty.
23 pub name: String,
24 /// Short public description of the object.
25 pub description: Option<String>,
26 /// Opaque interface references in host publication order.
27 pub interfaces: Vec<String>,
28 /// Optional opaque identity within one client-facing Worldspace.
29 pub r#ref: Option<String>,
30 /// Optional opaque validator for the object's observed state.
31 pub validator: Option<Vec<u8>>,
32}
33
34/// Transport-independent description of one interface.
35///
36/// Interface identity is supplied by interaction fields such as
37/// [`FetchInterfaceResponse::interface`], not embedded in the descriptor.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct InterfaceDescriptor {
40 /// Descriptor format version understood by clients and hosts.
41 pub format: String,
42 /// Optional interface documentation.
43 pub documentation: Option<Documentation>,
44 /// Named declarations local to this descriptor.
45 pub types: Vec<TypeDeclaration>,
46 /// Operations exposed by this interface.
47 pub operations: Vec<OperationDeclaration>,
48}
49
50/// A descriptor-local named type declaration.
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct TypeDeclaration {
53 /// Descriptor-local type name.
54 pub name: String,
55 /// Optional type documentation.
56 pub documentation: Option<Documentation>,
57 /// Definition associated with `name`.
58 pub definition: TypeExpr,
59}
60
61/// A type expression used by declarations, fields, parameters, and returns.
62///
63/// [`TypeExpr::Named`] references are resolved only within the containing
64/// descriptor. Recursive references, including recursion through lists,
65/// records, and unions, are invalid.
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub enum TypeExpr {
68 /// A value carrying no data.
69 Unit,
70 /// A boolean.
71 Boolean,
72 /// A JavaScript-lossless signed integer.
73 Integer,
74 /// A finite IEEE-754 binary64 number.
75 Number,
76 /// A Unicode string.
77 String,
78 /// An opaque byte sequence.
79 Bytes,
80 /// A schema-opaque JSON-compatible value tree.
81 Json,
82 /// A canonical absolute Worldspace path represented by a string value.
83 Entry,
84 /// A descriptor-local named declaration.
85 Named {
86 /// Referenced declaration name.
87 name: String,
88 },
89 /// A record with named fields.
90 Record {
91 /// Fields in declaration order.
92 fields: Vec<FieldDeclaration>,
93 },
94 /// An ordered list.
95 List {
96 /// Type of every list item.
97 items: Box<TypeExpr>,
98 },
99 /// A closed set of payload-free cases represented by strings.
100 Enum {
101 /// Cases in declaration order.
102 cases: Vec<EnumCase>,
103 },
104 /// A discriminated union represented by a record.
105 Union {
106 /// Cases in declaration order.
107 cases: Vec<UnionCase>,
108 },
109}
110
111/// Declaration of a record field.
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct FieldDeclaration {
114 /// Field name.
115 pub name: String,
116 /// Whether the field must be present.
117 pub required: bool,
118 /// Optional field documentation.
119 pub documentation: Option<Documentation>,
120 /// Field value type.
121 pub r#type: TypeExpr,
122}
123
124/// One payload-free enum case.
125#[derive(Debug, Clone, PartialEq, Eq)]
126pub struct EnumCase {
127 /// Case name.
128 pub name: String,
129 /// Optional case documentation.
130 pub documentation: Option<Documentation>,
131}
132
133/// One union case with zero or one payload.
134#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct UnionCase {
136 /// Case name.
137 pub name: String,
138 /// Optional case documentation.
139 pub documentation: Option<Documentation>,
140 /// Optional payload type.
141 pub payload: Option<TypeExpr>,
142}
143
144/// Declaration of one interface operation.
145#[derive(Debug, Clone, PartialEq, Eq)]
146pub struct OperationDeclaration {
147 /// Operation name, unique within its descriptor.
148 pub name: String,
149 /// Optional operation documentation.
150 pub documentation: Option<Documentation>,
151 /// Parameters in declaration order.
152 pub parameters: Vec<ParameterDeclaration>,
153 /// Return declaration. No-data operations return [`TypeExpr::Unit`].
154 pub returns: ReturnDeclaration,
155}
156
157/// Declaration of one operation parameter.
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct ParameterDeclaration {
160 /// Parameter name.
161 pub name: String,
162 /// Whether the parameter must be present.
163 pub required: bool,
164 /// Optional parameter documentation.
165 pub documentation: Option<Documentation>,
166 /// Parameter value type.
167 pub r#type: TypeExpr,
168}
169
170/// Declaration of an operation return value.
171#[derive(Debug, Clone, PartialEq, Eq)]
172pub struct ReturnDeclaration {
173 /// Optional return-value documentation.
174 pub documentation: Option<Documentation>,
175 /// Return value type.
176 pub r#type: TypeExpr,
177}
178
179/// A schema-neutral logical protocol value.
180///
181/// Enum cases, union cases, entries, and JSON are interpretations imposed by a
182/// descriptor. They are deliberately not variants of this enum. Record key
183/// ordering is not protocol-significant.
184#[derive(Debug, Clone, PartialEq)]
185pub enum Value {
186 /// A value carrying no data; it also represents JSON null under `Json`.
187 Unit,
188 /// A boolean.
189 Boolean(bool),
190 /// A JavaScript-lossless integer.
191 Integer(i64),
192 /// A finite IEEE-754 binary64 number.
193 Number(f64),
194 /// A Unicode string.
195 String(String),
196 /// An opaque byte sequence.
197 Bytes(Vec<u8>),
198 /// String-keyed fields with order-insensitive semantics.
199 Record(BTreeMap<String, Value>),
200 /// An ordered sequence.
201 List(Vec<Value>),
202}
203
204impl Value {
205 /// Returns the structural kind used by validation diagnostics.
206 #[must_use]
207 pub fn kind(&self) -> crate::ValueKind {
208 match self {
209 Self::Unit => crate::ValueKind::Unit,
210 Self::Boolean(_) => crate::ValueKind::Boolean,
211 Self::Integer(_) => crate::ValueKind::Integer,
212 Self::Number(_) => crate::ValueKind::Number,
213 Self::String(_) => crate::ValueKind::String,
214 Self::Bytes(_) => crate::ValueKind::Bytes,
215 Self::Record(_) => crate::ValueKind::Record,
216 Self::List(_) => crate::ValueKind::List,
217 }
218 }
219}
220
221/// Request for the object currently published at one path and its indexable descendants.
222#[derive(Debug, Clone, PartialEq, Eq)]
223pub struct ObserveRequest {
224 /// Canonical absolute path of the observation root.
225 pub path: String,
226 /// Maximum observed depth, where the requested object has depth zero.
227 pub depth: u32,
228}
229
230/// One node in an object observation.
231#[derive(Debug, Clone, PartialEq, Eq)]
232pub struct ObjectObservation {
233 /// Object observed at this Worldspace position.
234 pub object: Object,
235 /// Complete direct children when observed, or `None` at the requested depth boundary.
236 pub children: Option<Vec<ObjectObservation>>,
237}
238
239/// Successful `observe` response.
240pub type ObserveResponse = ObjectObservation;
241
242/// Request for the current descriptor of one opaque interface reference.
243#[derive(Debug, Clone, PartialEq, Eq)]
244pub struct FetchInterfaceRequest {
245 /// Opaque interface reference obtained from an object.
246 pub interface: String,
247}
248
249/// Successful `fetch_interface` response.
250#[derive(Debug, Clone, PartialEq, Eq)]
251pub struct FetchInterfaceResponse {
252 /// Opaque interface reference corresponding to the request.
253 pub interface: String,
254 /// Current validated descriptor.
255 pub descriptor: InterfaceDescriptor,
256 /// Optional opaque validator for this descriptor observation.
257 pub validator: Option<Vec<u8>>,
258}
259
260/// Object portion of an operation target.
261#[derive(Debug, Clone, PartialEq, Eq)]
262pub struct Target {
263 /// Canonical absolute path of the target object.
264 pub path: String,
265 /// Optional validator copied from the object observation.
266 pub validator: Option<Vec<u8>>,
267}
268
269/// Interface portion of an operation target.
270#[derive(Debug, Clone, PartialEq, Eq)]
271pub struct InterfaceTarget {
272 /// Opaque interface reference selected from the object's interface set.
273 pub reference: String,
274 /// Optional validator copied from the interface observation.
275 pub validator: Option<Vec<u8>>,
276}
277
278/// Transport-independent request to execute one operation.
279#[derive(Debug, Clone, PartialEq)]
280pub struct CallOperationRequest {
281 /// Path and optional object-state precondition.
282 pub target: Target,
283 /// Interface reference and its independent optional precondition.
284 pub interface: InterfaceTarget,
285 /// Operation name within the selected descriptor.
286 pub operation: String,
287 /// Named arguments; map iteration order has no protocol meaning.
288 pub arguments: BTreeMap<String, Value>,
289}
290
291/// Successful operation response.
292#[derive(Debug, Clone, PartialEq)]
293pub struct CallOperationResponse {
294 /// Application result validated against the operation return declaration.
295 pub result: Value,
296 /// Optional validator for the object state observed after execution.
297 pub validator: Option<Vec<u8>>,
298}
299
300/// Logical outcome of any core interaction.
301#[derive(Debug, Clone, PartialEq, Eq)]
302pub enum ProtocolResult<T> {
303 /// The interaction succeeded.
304 Success(T),
305 /// The interaction failed at the protocol boundary.
306 Failure(ProtocolError),
307}
308
309impl Object {
310 /// Validates the object-independent name and ordered-interface-set rules.
311 pub fn validate(&self) -> Result<(), ValidationError> {
312 crate::validation::validate_object(self)
313 }
314
315 /// Validates this object as the response observed at `path`.
316 pub fn validate_at_path(&self, path: &str) -> Result<(), ValidationError> {
317 crate::validation::validate_object_at_path(self, path)
318 }
319
320 /// Validates equal representations for a shared ref and present validator.
321 pub fn validate_consistency_with(&self, other: &Self) -> Result<(), ValidationError> {
322 crate::validation::validate_object_consistency(self, other)
323 }
324}
325
326impl InterfaceDescriptor {
327 /// Validates declaration structure, named references, and absence of cycles.
328 pub fn validate(&self) -> Result<(), ValidationError> {
329 crate::validation::validate_descriptor(self)
330 }
331
332 /// Validates a raw value against a type expression in this descriptor.
333 pub fn validate_value(&self, r#type: &TypeExpr, value: &Value) -> Result<(), ValidationError> {
334 crate::validation::validate_root_value(self, r#type, value)
335 }
336
337 /// Validates named arguments for one declared operation.
338 pub fn validate_arguments(
339 &self,
340 operation: &str,
341 arguments: &BTreeMap<String, Value>,
342 ) -> Result<(), ValidationError> {
343 crate::validation::validate_arguments(self, operation, arguments)
344 }
345
346 /// Validates one operation result against its return declaration.
347 pub fn validate_result(&self, operation: &str, result: &Value) -> Result<(), ValidationError> {
348 crate::validation::validate_result(self, operation, result)
349 }
350
351 /// Validates the path, operation, and arguments in a call request.
352 pub fn validate_call(&self, request: &CallOperationRequest) -> Result<(), ValidationError> {
353 crate::validation::validate_call(self, request)
354 }
355}
356
357impl ObserveRequest {
358 /// Validates the request path.
359 pub fn validate(&self) -> Result<(), ValidationError> {
360 crate::validation::validate_path(&self.path)
361 }
362
363 /// Validates observation shape, names, and requested depth.
364 ///
365 /// Failure means the Client received an invalid success response; it is not a
366 /// Host-returned [`crate::ProtocolErrorCode`].
367 pub fn validate_response(&self, response: &ObserveResponse) -> Result<(), ValidationError> {
368 crate::validation::validate_observe_response(response, self)
369 }
370}
371
372impl FetchInterfaceResponse {
373 /// Validates request correspondence and descriptor semantics.
374 ///
375 /// Failure means the Client received an invalid success response; it is not a
376 /// Host-returned [`crate::ProtocolErrorCode`]. Descriptor format support is a
377 /// separate Client concern: an otherwise valid descriptor with an unsupported
378 /// `format` is a Client-local `UnsupportedDescriptorFormat`.
379 pub fn validate_for(&self, request: &FetchInterfaceRequest) -> Result<(), ValidationError> {
380 crate::validation::validate_fetch_interface_response(self, request)
381 }
382}
383
384impl CallOperationRequest {
385 /// Validates this call against the descriptor selected by `interface`.
386 pub fn validate_with(&self, descriptor: &InterfaceDescriptor) -> Result<(), ValidationError> {
387 descriptor.validate_call(self)
388 }
389}
390
391impl CallOperationResponse {
392 /// Validates this result against the named operation in `descriptor`.
393 ///
394 /// Failure means the Client received an invalid success response; it is not a
395 /// Host-returned [`crate::ProtocolErrorCode`].
396 pub fn validate_for(
397 &self,
398 descriptor: &InterfaceDescriptor,
399 operation: &str,
400 ) -> Result<(), ValidationError> {
401 descriptor.validate_result(operation, &self.result)
402 }
403}