fix: align interface macros with canonical values
This commit is contained in:
+34
-32
@@ -31,7 +31,7 @@
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use std::any::TypeId;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::error::Error;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::marker::PhantomData;
|
||||
@@ -42,8 +42,7 @@ use wip_interface::DispatchError;
|
||||
pub use wip_interface::{InterfaceDefinition, InterfaceImplementation};
|
||||
pub use wip_protocol;
|
||||
use wip_protocol::{
|
||||
InterfaceDescriptor, NamedValue, Object, ObjectId, OperationCall, OperationTarget,
|
||||
ProtocolError, ProtocolErrorCategory, ValidationError, Value,
|
||||
InterfaceDescriptor, Object, ProtocolError, ProtocolErrorCode, ValidationError, Value,
|
||||
};
|
||||
|
||||
/// Opaque bytes used as a conditional execution precondition.
|
||||
@@ -64,6 +63,14 @@ impl Validator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Host-local identity used by the legacy request-scoped publication API.
|
||||
///
|
||||
/// Canonical protocol calls target a Worldspace path. This wrapper remains
|
||||
/// temporarily host-local so T-5 can adapt generated values without assigning
|
||||
/// object identity semantics to the protocol descriptor model.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct ObjectId(pub String);
|
||||
|
||||
/// Opaque host-assigned reference to one registered interface artifact.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct InterfaceRef(String);
|
||||
@@ -161,8 +168,8 @@ impl InterfaceRegistry {
|
||||
/// `validator` should be present when the host intends the reference to
|
||||
/// represent a versioned descriptor. Its presence makes the same value a
|
||||
/// mandatory precondition for dispatch. Registration finalizes the
|
||||
/// descriptor's protocol `name` to the assigned opaque reference so it
|
||||
/// corresponds directly to [`Object::interfaces`].
|
||||
/// descriptor remains independent of both registration and its assigned
|
||||
/// opaque reference.
|
||||
pub fn register<D>(
|
||||
&mut self,
|
||||
_definition: D,
|
||||
@@ -176,7 +183,7 @@ impl InterfaceRegistry {
|
||||
return Err(RegistrationError::AlreadyRegistered);
|
||||
}
|
||||
|
||||
let mut descriptor = D::descriptor();
|
||||
let descriptor = D::descriptor();
|
||||
descriptor
|
||||
.validate()
|
||||
.map_err(RegistrationError::InvalidDescriptor)?;
|
||||
@@ -185,11 +192,6 @@ impl InterfaceRegistry {
|
||||
"wip-interface:{}:{}",
|
||||
self.namespace, self.next_reference
|
||||
));
|
||||
// The protocol model currently carries the interface identifier in the
|
||||
// descriptor's `name` field. Finalize that identity to the same opaque
|
||||
// reference placed on published objects; the generated Rust trait name
|
||||
// is registration-local metadata, not wire identity.
|
||||
descriptor.name = reference.0.clone();
|
||||
self.next_reference = self
|
||||
.next_reference
|
||||
.checked_add(1)
|
||||
@@ -289,7 +291,7 @@ pub trait WipObject {
|
||||
}
|
||||
}
|
||||
|
||||
type DispatchFn<T> = fn(&T, &str, Vec<NamedValue>) -> Result<Option<Value>, DispatchError>;
|
||||
type DispatchFn<T> = fn(&T, &str, BTreeMap<String, Value>) -> Result<Value, DispatchError>;
|
||||
|
||||
struct BoundInterface<T> {
|
||||
artifact: Arc<InterfaceArtifact>,
|
||||
@@ -350,13 +352,20 @@ impl<T: WipObject> PublishedObject<T> {
|
||||
/// Builds the protocol object metadata with interface insertion order intact.
|
||||
#[must_use]
|
||||
pub fn protocol_object(&self) -> Object {
|
||||
let id = self.implementation.id();
|
||||
let object = Object {
|
||||
id: self.implementation.id(),
|
||||
name: id.0.clone(),
|
||||
description: None,
|
||||
interfaces: self
|
||||
.interfaces
|
||||
.iter()
|
||||
.map(|bound| bound.artifact.reference.0.clone())
|
||||
.collect(),
|
||||
r#ref: Some(id.0),
|
||||
validator: self
|
||||
.implementation
|
||||
.validator()
|
||||
.map(|validator| validator.0.clone()),
|
||||
};
|
||||
debug_assert!(object.validate().is_ok());
|
||||
object
|
||||
@@ -438,14 +447,7 @@ impl<T: WipObject> PublishedObject<T> {
|
||||
bound
|
||||
.artifact
|
||||
.descriptor
|
||||
.validate_call(&OperationCall {
|
||||
target: OperationTarget {
|
||||
object: request.object.clone(),
|
||||
interface: bound.artifact.descriptor.name.clone(),
|
||||
operation: request.operation.clone(),
|
||||
},
|
||||
arguments: request.arguments.clone(),
|
||||
})
|
||||
.validate_arguments(&request.operation, &request.arguments)
|
||||
.map_err(|error| CallError::new(CallErrorKind::InvalidArguments, error.to_string()))?;
|
||||
|
||||
let value = (bound.dispatch)(&self.implementation, &request.operation, request.arguments)
|
||||
@@ -454,7 +456,7 @@ impl<T: WipObject> PublishedObject<T> {
|
||||
bound
|
||||
.artifact
|
||||
.descriptor
|
||||
.validate_return(&request.operation, value.as_ref())
|
||||
.validate_result(&request.operation, &value)
|
||||
.map_err(|error| CallError::new(CallErrorKind::InvalidResult, error.to_string()))?;
|
||||
|
||||
Ok(CallResult {
|
||||
@@ -512,14 +514,14 @@ pub struct CallRequest {
|
||||
/// Operation name within the selected interface descriptor.
|
||||
pub operation: String,
|
||||
/// Named protocol arguments.
|
||||
pub arguments: Vec<NamedValue>,
|
||||
pub arguments: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// Successful host dispatch result.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct CallResult {
|
||||
/// Encoded application value, or `None` for a no-return operation.
|
||||
pub value: Option<Value>,
|
||||
/// Encoded application result. No-data operations return [`Value::Unit`].
|
||||
pub value: Value,
|
||||
/// Object validator observed after the implementation returned.
|
||||
pub validator: Option<Validator>,
|
||||
}
|
||||
@@ -610,20 +612,20 @@ impl CallError {
|
||||
#[must_use]
|
||||
pub fn protocol_error(&self) -> ProtocolError {
|
||||
let category = match self.kind {
|
||||
CallErrorKind::ObjectNotFound => ProtocolErrorCategory::ObjectNotFound,
|
||||
CallErrorKind::InterfaceMismatch => ProtocolErrorCategory::InterfaceNotFound,
|
||||
CallErrorKind::OperationNotFound => ProtocolErrorCategory::OperationNotFound,
|
||||
CallErrorKind::InvalidArguments => ProtocolErrorCategory::InvalidArguments,
|
||||
CallErrorKind::ObjectNotFound => ProtocolErrorCode::NotFound,
|
||||
CallErrorKind::InterfaceMismatch => ProtocolErrorCode::InterfaceMismatch,
|
||||
CallErrorKind::OperationNotFound => ProtocolErrorCode::OperationNotFound,
|
||||
CallErrorKind::InvalidArguments => ProtocolErrorCode::InvalidArguments,
|
||||
CallErrorKind::ValidatorRequired
|
||||
| CallErrorKind::ValidatorMismatch
|
||||
| CallErrorKind::InterfaceValidatorRequired
|
||||
| CallErrorKind::InterfaceValidatorMismatch => ProtocolErrorCategory::InvalidRequest,
|
||||
| CallErrorKind::InterfaceValidatorMismatch => ProtocolErrorCode::InvalidRequest,
|
||||
CallErrorKind::InvalidResult | CallErrorKind::Implementation => {
|
||||
ProtocolErrorCategory::Internal
|
||||
ProtocolErrorCode::Internal
|
||||
}
|
||||
};
|
||||
ProtocolError {
|
||||
category,
|
||||
code: category,
|
||||
message: self.message.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user