pub trait ToolResultCodec: Send + Sync {
// Required methods
fn lift(&self, version: ProtocolVersion, wire: &Value) -> Option<ToolResult>;
fn lower(
&self,
version: ProtocolVersion,
value: ToolResult,
policy: DegradePolicy,
report: &mut TranslationReport,
) -> Result<Value, LowerError>;
}Expand description
Reads and writes a ToolResult in one revision’s wire encoding.
Declared by the consumer — this module — and implemented by the codec layer, which is the only place that knows a revision’s generated types. The bridge names no wire type, so it could not implement this even if it wanted to.
§Why lift answers Option
None means this build does not read that shape, and it is a decision
rather than a fault: the caller forwards the value untouched so a peer that
does understand it still receives it. A build that had no wire types at all
for the revision would answer None for everything, and the bridge would
degrade into a pure pass-through rather than into a component that breaks a
connection it never had to translate.
§Example
The smallest implementor that could exist. A production one is
WireToolResults,
which dispatches to the six per-revision codecs.
use protocol_droid::application::bridge::ToolResultCodec;
use protocol_droid::domain::ir::{LowerError, ToolResult, TranslationReport};
use protocol_droid::domain::{DegradePolicy, ProtocolVersion};
use serde_json::Value;
/// Reads nothing, so every reply through this codec passes through.
struct ReadsNothing;
impl ToolResultCodec for ReadsNothing {
fn lift(&self, _version: ProtocolVersion, _wire: &Value) -> Option<ToolResult> {
None
}
fn lower(
&self,
_version: ProtocolVersion,
_value: ToolResult,
_policy: DegradePolicy,
_report: &mut TranslationReport,
) -> Result<Value, LowerError> {
Ok(Value::Null)
}
}A Bridge holds its codec across an await while the reply is in flight,
and a serving loop may drive several bridges at once, so a codec that is not
Sync would make every one of those futures non-Send. The bound is on the
port rather than on Bridge for one reason: this crate’s ports already
require Send + Sync, and a codec that only worked on the current thread
would not be a codec a bridge could hold.
Required Methods§
Sourcefn lift(&self, version: ProtocolVersion, wire: &Value) -> Option<ToolResult>
fn lift(&self, version: ProtocolVersion, wire: &Value) -> Option<ToolResult>
The ToolResult wire holds at version, or None if this build
does not read it.
Sourcefn lower(
&self,
version: ProtocolVersion,
value: ToolResult,
policy: DegradePolicy,
report: &mut TranslationReport,
) -> Result<Value, LowerError>
fn lower( &self, version: ProtocolVersion, value: ToolResult, policy: DegradePolicy, report: &mut TranslationReport, ) -> Result<Value, LowerError>
Writes value at version, recording anything the codec changed in
report.
value arrives already lowered — the codec asks
lower_tool_result
itself rather than being handed a decision, which is why this is not a
bare serialisation and why the report comes back from here.
§Errors
LowerError::FieldNotRepresentable when the value does not fit a
shape version types — the typed-meta case.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl<C: ToolResultCodec> ToolResultCodec for Arc<C>
Lets a shared codec be a codec.
impl<C: ToolResultCodec> ToolResultCodec for Arc<C>
Lets a shared codec be a codec.
Arc<T> satisfies none of this crate’s ports on its own — it is not a
FrameSink and it is not a FrameSource either, for the same reason. A
Bridge is usually held by a serving loop and a test wants to watch what it
did, and an Arc is the only thing that gives both at once.