wip-protocol 0.1.0

Transport-independent logical model and validation for WIP
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
use std::collections::BTreeMap;

use crate::{ProtocolError, ValidationError};

/// Human-readable plain-text documentation attached to a protocol declaration.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Documentation {
    /// A short, self-contained description.
    pub summary: String,
    /// Optional extended documentation.
    pub details: Option<String>,
}

/// The protocol projection currently published at one Worldspace path.
///
/// `name` is a path segment, `interfaces` is an ordered set of opaque interface
/// references, `r#ref` is optional object identity, and `validator` is an
/// independent optional observation precondition. In particular, neither the
/// path nor `r#ref` is a mandatory object identifier.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Object {
    /// Path-segment name. The root object's name is empty.
    pub name: String,
    /// Short public description of the object.
    pub description: Option<String>,
    /// Opaque interface references in host publication order.
    pub interfaces: Vec<String>,
    /// Optional opaque identity within one client-facing Worldspace.
    pub r#ref: Option<String>,
    /// Optional opaque validator for the object's observed state.
    pub validator: Option<Vec<u8>>,
}

/// Transport-independent description of one interface.
///
/// Interface identity is supplied by interaction fields such as
/// [`FetchInterfaceResponse::interface`], not embedded in the descriptor.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InterfaceDescriptor {
    /// Descriptor format version understood by clients and hosts.
    pub format: String,
    /// Optional interface documentation.
    pub documentation: Option<Documentation>,
    /// Named declarations local to this descriptor.
    pub types: Vec<TypeDeclaration>,
    /// Operations exposed by this interface.
    pub operations: Vec<OperationDeclaration>,
}

/// A descriptor-local named type declaration.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeDeclaration {
    /// Descriptor-local type name.
    pub name: String,
    /// Optional type documentation.
    pub documentation: Option<Documentation>,
    /// Definition associated with `name`.
    pub definition: TypeExpr,
}

/// A type expression used by declarations, fields, parameters, and returns.
///
/// [`TypeExpr::Named`] references are resolved only within the containing
/// descriptor. Recursive references, including recursion through lists,
/// records, and unions, are invalid.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TypeExpr {
    /// A value carrying no data.
    Unit,
    /// A boolean.
    Boolean,
    /// A JavaScript-lossless signed integer.
    Integer,
    /// A finite IEEE-754 binary64 number.
    Number,
    /// A Unicode string.
    String,
    /// An opaque byte sequence.
    Bytes,
    /// A schema-opaque JSON-compatible value tree.
    Json,
    /// A canonical absolute Worldspace path represented by a string value.
    Entry,
    /// A descriptor-local named declaration.
    Named {
        /// Referenced declaration name.
        name: String,
    },
    /// A record with named fields.
    Record {
        /// Fields in declaration order.
        fields: Vec<FieldDeclaration>,
    },
    /// An ordered list.
    List {
        /// Type of every list item.
        items: Box<TypeExpr>,
    },
    /// A closed set of payload-free cases represented by strings.
    Enum {
        /// Cases in declaration order.
        cases: Vec<EnumCase>,
    },
    /// A discriminated union represented by a record.
    Union {
        /// Cases in declaration order.
        cases: Vec<UnionCase>,
    },
}

/// Declaration of a record field.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldDeclaration {
    /// Field name.
    pub name: String,
    /// Whether the field must be present.
    pub required: bool,
    /// Optional field documentation.
    pub documentation: Option<Documentation>,
    /// Field value type.
    pub r#type: TypeExpr,
}

/// One payload-free enum case.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumCase {
    /// Case name.
    pub name: String,
    /// Optional case documentation.
    pub documentation: Option<Documentation>,
}

/// One union case with zero or one payload.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnionCase {
    /// Case name.
    pub name: String,
    /// Optional case documentation.
    pub documentation: Option<Documentation>,
    /// Optional payload type.
    pub payload: Option<TypeExpr>,
}

/// Declaration of one interface operation.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OperationDeclaration {
    /// Operation name, unique within its descriptor.
    pub name: String,
    /// Optional operation documentation.
    pub documentation: Option<Documentation>,
    /// Parameters in declaration order.
    pub parameters: Vec<ParameterDeclaration>,
    /// Return declaration. No-data operations return [`TypeExpr::Unit`].
    pub returns: ReturnDeclaration,
}

/// Declaration of one operation parameter.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParameterDeclaration {
    /// Parameter name.
    pub name: String,
    /// Whether the parameter must be present.
    pub required: bool,
    /// Optional parameter documentation.
    pub documentation: Option<Documentation>,
    /// Parameter value type.
    pub r#type: TypeExpr,
}

/// Declaration of an operation return value.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReturnDeclaration {
    /// Optional return-value documentation.
    pub documentation: Option<Documentation>,
    /// Return value type.
    pub r#type: TypeExpr,
}

/// A schema-neutral logical protocol value.
///
/// Enum cases, union cases, entries, and JSON are interpretations imposed by a
/// descriptor. They are deliberately not variants of this enum. Record key
/// ordering is not protocol-significant.
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    /// A value carrying no data; it also represents JSON null under `Json`.
    Unit,
    /// A boolean.
    Boolean(bool),
    /// A JavaScript-lossless integer.
    Integer(i64),
    /// A finite IEEE-754 binary64 number.
    Number(f64),
    /// A Unicode string.
    String(String),
    /// An opaque byte sequence.
    Bytes(Vec<u8>),
    /// String-keyed fields with order-insensitive semantics.
    Record(BTreeMap<String, Value>),
    /// An ordered sequence.
    List(Vec<Value>),
}

impl Value {
    /// Returns the structural kind used by validation diagnostics.
    #[must_use]
    pub fn kind(&self) -> crate::ValueKind {
        match self {
            Self::Unit => crate::ValueKind::Unit,
            Self::Boolean(_) => crate::ValueKind::Boolean,
            Self::Integer(_) => crate::ValueKind::Integer,
            Self::Number(_) => crate::ValueKind::Number,
            Self::String(_) => crate::ValueKind::String,
            Self::Bytes(_) => crate::ValueKind::Bytes,
            Self::Record(_) => crate::ValueKind::Record,
            Self::List(_) => crate::ValueKind::List,
        }
    }
}

/// Request for the object currently published at one path and its indexable descendants.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ObserveRequest {
    /// Canonical absolute path of the observation root.
    pub path: String,
    /// Maximum observed depth, where the requested object has depth zero.
    pub depth: u32,
}

/// One node in an object observation.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ObjectObservation {
    /// Object observed at this Worldspace position.
    pub object: Object,
    /// Complete direct children when observed, or `None` at the requested depth boundary.
    pub children: Option<Vec<ObjectObservation>>,
}

/// Successful `observe` response.
pub type ObserveResponse = ObjectObservation;

/// Request for the current descriptor of one opaque interface reference.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FetchInterfaceRequest {
    /// Opaque interface reference obtained from an object.
    pub interface: String,
}

/// Successful `fetch_interface` response.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FetchInterfaceResponse {
    /// Opaque interface reference corresponding to the request.
    pub interface: String,
    /// Current validated descriptor.
    pub descriptor: InterfaceDescriptor,
    /// Optional opaque validator for this descriptor observation.
    pub validator: Option<Vec<u8>>,
}

/// Object portion of an operation target.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Target {
    /// Canonical absolute path of the target object.
    pub path: String,
    /// Optional validator copied from the object observation.
    pub validator: Option<Vec<u8>>,
}

/// Interface portion of an operation target.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InterfaceTarget {
    /// Opaque interface reference selected from the object's interface set.
    pub reference: String,
    /// Optional validator copied from the interface observation.
    pub validator: Option<Vec<u8>>,
}

/// Transport-independent request to execute one operation.
#[derive(Debug, Clone, PartialEq)]
pub struct CallOperationRequest {
    /// Path and optional object-state precondition.
    pub target: Target,
    /// Interface reference and its independent optional precondition.
    pub interface: InterfaceTarget,
    /// Operation name within the selected descriptor.
    pub operation: String,
    /// Named arguments; map iteration order has no protocol meaning.
    pub arguments: BTreeMap<String, Value>,
}

/// Successful operation response.
#[derive(Debug, Clone, PartialEq)]
pub struct CallOperationResponse {
    /// Application result validated against the operation return declaration.
    pub result: Value,
    /// Optional validator for the object state observed after execution.
    pub validator: Option<Vec<u8>>,
}

/// Logical outcome of any core interaction.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProtocolResult<T> {
    /// The interaction succeeded.
    Success(T),
    /// The interaction failed at the protocol boundary.
    Failure(ProtocolError),
}

impl Object {
    /// Validates the object-independent name and ordered-interface-set rules.
    pub fn validate(&self) -> Result<(), ValidationError> {
        crate::validation::validate_object(self)
    }

    /// Validates this object as the response observed at `path`.
    pub fn validate_at_path(&self, path: &str) -> Result<(), ValidationError> {
        crate::validation::validate_object_at_path(self, path)
    }

    /// Validates equal representations for a shared ref and present validator.
    pub fn validate_consistency_with(&self, other: &Self) -> Result<(), ValidationError> {
        crate::validation::validate_object_consistency(self, other)
    }
}

impl InterfaceDescriptor {
    /// Validates declaration structure, named references, and absence of cycles.
    pub fn validate(&self) -> Result<(), ValidationError> {
        crate::validation::validate_descriptor(self)
    }

    /// Validates a raw value against a type expression in this descriptor.
    pub fn validate_value(&self, r#type: &TypeExpr, value: &Value) -> Result<(), ValidationError> {
        crate::validation::validate_root_value(self, r#type, value)
    }

    /// Validates named arguments for one declared operation.
    pub fn validate_arguments(
        &self,
        operation: &str,
        arguments: &BTreeMap<String, Value>,
    ) -> Result<(), ValidationError> {
        crate::validation::validate_arguments(self, operation, arguments)
    }

    /// Validates one operation result against its return declaration.
    pub fn validate_result(&self, operation: &str, result: &Value) -> Result<(), ValidationError> {
        crate::validation::validate_result(self, operation, result)
    }

    /// Validates the path, operation, and arguments in a call request.
    pub fn validate_call(&self, request: &CallOperationRequest) -> Result<(), ValidationError> {
        crate::validation::validate_call(self, request)
    }
}

impl ObserveRequest {
    /// Validates the request path.
    pub fn validate(&self) -> Result<(), ValidationError> {
        crate::validation::validate_path(&self.path)
    }

    /// Validates observation shape, names, and requested depth.
    ///
    /// Failure means the Client received an invalid success response; it is not a
    /// Host-returned [`crate::ProtocolErrorCode`].
    pub fn validate_response(&self, response: &ObserveResponse) -> Result<(), ValidationError> {
        crate::validation::validate_observe_response(response, self)
    }
}

impl FetchInterfaceResponse {
    /// Validates request correspondence and descriptor semantics.
    ///
    /// Failure means the Client received an invalid success response; it is not a
    /// Host-returned [`crate::ProtocolErrorCode`]. Descriptor format support is a
    /// separate Client concern: an otherwise valid descriptor with an unsupported
    /// `format` is a Client-local `UnsupportedDescriptorFormat`.
    pub fn validate_for(&self, request: &FetchInterfaceRequest) -> Result<(), ValidationError> {
        crate::validation::validate_fetch_interface_response(self, request)
    }
}

impl CallOperationRequest {
    /// Validates this call against the descriptor selected by `interface`.
    pub fn validate_with(&self, descriptor: &InterfaceDescriptor) -> Result<(), ValidationError> {
        descriptor.validate_call(self)
    }
}

impl CallOperationResponse {
    /// Validates this result against the named operation in `descriptor`.
    ///
    /// Failure means the Client received an invalid success response; it is not a
    /// Host-returned [`crate::ProtocolErrorCode`].
    pub fn validate_for(
        &self,
        descriptor: &InterfaceDescriptor,
        operation: &str,
    ) -> Result<(), ValidationError> {
        descriptor.validate_result(operation, &self.result)
    }
}