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