use flatbuffers::{FlatBufferBuilder, InvalidFlatbuffer};
pub use selium_abi::{
AbiParam, AbiScalarType, AbiScalarValue, AbiSignature, Capability, EntrypointArg,
GuestResourceId, GuestUint,
};
use thiserror::Error;
#[allow(missing_docs)]
#[allow(warnings)]
#[rustfmt::skip]
pub mod fbs;
use crate::fbs::remote_client::protocol as fb;
const REMOTE_CLIENT_IDENTIFIER: &str = "RMCL";
pub type GuestWriterId = u16;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IoFrame {
pub writer_id: GuestWriterId,
pub payload: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Request {
ChannelCreate(GuestUint),
ChannelDelete(GuestResourceId),
Subscribe(ChannelRef, GuestUint),
Publish(GuestResourceId),
ProcessStart(ProcessStartRequest),
ProcessStop(GuestResourceId),
ProcessLogChannel(GuestResourceId),
}
#[derive(Clone, Debug, PartialEq)]
pub enum Response {
ChannelCreate(GuestResourceId),
ChannelRead(IoFrame),
ChannelWrite(GuestUint),
ProcessStart(GuestResourceId),
ProcessLogChannel(GuestResourceId),
Ok,
Error(String),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelRef {
Strong(GuestResourceId),
Shared(GuestResourceId),
}
#[derive(Clone, Debug, PartialEq)]
pub struct ProcessStartRequest {
pub module_id: String,
pub entrypoint: String,
pub log_uri: Option<String>,
pub capabilities: Vec<Capability>,
pub signature: AbiSignature,
pub args: Vec<EntrypointArg>,
}
#[derive(Debug, Error)]
pub enum ProtocolError {
#[error("invalid flatbuffer: {0:?}")]
InvalidFlatbuffer(InvalidFlatbuffer),
#[error("remote-client message missing payload")]
MissingPayload,
#[error("unknown remote-client payload type")]
UnknownPayload,
#[error("invalid remote-client message identifier")]
InvalidIdentifier,
#[error("remote-client payload was not a {expected}")]
UnexpectedPayload { expected: &'static str },
#[error("unknown capability variant")]
UnknownCapability,
#[error("unknown ABI scalar type")]
UnknownAbiScalarType,
#[error("unknown ABI parameter kind")]
UnknownAbiParamKind,
#[error("unknown channel reference kind")]
UnknownChannelRefKind,
#[error("unknown entrypoint argument kind")]
UnknownEntrypointArgKind,
#[error("missing remote-client field: {0}")]
MissingField(&'static str),
}
impl From<InvalidFlatbuffer> for ProtocolError {
fn from(value: InvalidFlatbuffer) -> Self {
ProtocolError::InvalidFlatbuffer(value)
}
}
pub fn encode_request(request: &Request) -> Result<Vec<u8>, ProtocolError> {
let mut builder = FlatBufferBuilder::new();
let (payload_type, payload) = encode_request_payload(&mut builder, request)?;
let message = fb::RemoteClientMessage::create(
&mut builder,
&fb::RemoteClientMessageArgs {
payload_type,
payload,
},
);
builder.finish(message, Some(REMOTE_CLIENT_IDENTIFIER));
Ok(builder.finished_data().to_vec())
}
pub fn decode_request(bytes: &[u8]) -> Result<Request, ProtocolError> {
let message = decode_message(bytes)?;
match message.payload_type() {
fb::RemoteClientPayload::ChannelCreateRequest => {
let req = message
.payload_as_channel_create_request()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Request::ChannelCreate(req.capacity()))
}
fb::RemoteClientPayload::ChannelDeleteRequest => {
let req = message
.payload_as_channel_delete_request()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Request::ChannelDelete(req.handle()))
}
fb::RemoteClientPayload::SubscribeRequest => {
let req = message
.payload_as_subscribe_request()
.ok_or(ProtocolError::MissingPayload)?;
let target = decode_channel_ref(
req.target()
.ok_or(ProtocolError::MissingField("subscribe.target"))?,
)?;
Ok(Request::Subscribe(target, req.chunk_size()))
}
fb::RemoteClientPayload::PublishRequest => {
let req = message
.payload_as_publish_request()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Request::Publish(req.handle()))
}
fb::RemoteClientPayload::ProcessStartRequest => {
let req = message
.payload_as_process_start_request()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Request::ProcessStart(decode_process_start_request(req)?))
}
fb::RemoteClientPayload::ProcessStopRequest => {
let req = message
.payload_as_process_stop_request()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Request::ProcessStop(req.handle()))
}
fb::RemoteClientPayload::ProcessLogChannelRequest => {
let req = message
.payload_as_process_log_channel_request()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Request::ProcessLogChannel(req.handle()))
}
fb::RemoteClientPayload::ChannelCreateResponse
| fb::RemoteClientPayload::ChannelReadResponse
| fb::RemoteClientPayload::ChannelWriteResponse
| fb::RemoteClientPayload::ProcessStartResponse
| fb::RemoteClientPayload::ProcessLogChannelResponse
| fb::RemoteClientPayload::OkResponse
| fb::RemoteClientPayload::ErrorResponse => Err(ProtocolError::UnexpectedPayload {
expected: "request",
}),
_ => Err(ProtocolError::UnknownPayload),
}
}
pub fn encode_response(response: &Response) -> Result<Vec<u8>, ProtocolError> {
let mut builder = FlatBufferBuilder::new();
let (payload_type, payload) = encode_response_payload(&mut builder, response);
let message = fb::RemoteClientMessage::create(
&mut builder,
&fb::RemoteClientMessageArgs {
payload_type,
payload,
},
);
builder.finish(message, Some(REMOTE_CLIENT_IDENTIFIER));
Ok(builder.finished_data().to_vec())
}
pub fn decode_response(bytes: &[u8]) -> Result<Response, ProtocolError> {
let message = decode_message(bytes)?;
match message.payload_type() {
fb::RemoteClientPayload::ChannelCreateResponse => {
let resp = message
.payload_as_channel_create_response()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Response::ChannelCreate(resp.handle()))
}
fb::RemoteClientPayload::ChannelReadResponse => {
let resp = message
.payload_as_channel_read_response()
.ok_or(ProtocolError::MissingPayload)?;
let frame = resp
.frame()
.ok_or(ProtocolError::MissingField("channel_read.frame"))?;
Ok(Response::ChannelRead(decode_io_frame(frame)?))
}
fb::RemoteClientPayload::ChannelWriteResponse => {
let resp = message
.payload_as_channel_write_response()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Response::ChannelWrite(resp.len()))
}
fb::RemoteClientPayload::ProcessStartResponse => {
let resp = message
.payload_as_process_start_response()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Response::ProcessStart(resp.handle()))
}
fb::RemoteClientPayload::ProcessLogChannelResponse => {
let resp = message
.payload_as_process_log_channel_response()
.ok_or(ProtocolError::MissingPayload)?;
Ok(Response::ProcessLogChannel(resp.handle()))
}
fb::RemoteClientPayload::OkResponse => Ok(Response::Ok),
fb::RemoteClientPayload::ErrorResponse => {
let resp = message
.payload_as_error_response()
.ok_or(ProtocolError::MissingPayload)?;
let message = resp
.message()
.ok_or(ProtocolError::MissingField("error.message"))?
.to_string();
Ok(Response::Error(message))
}
fb::RemoteClientPayload::ChannelCreateRequest
| fb::RemoteClientPayload::ChannelDeleteRequest
| fb::RemoteClientPayload::SubscribeRequest
| fb::RemoteClientPayload::PublishRequest
| fb::RemoteClientPayload::ProcessStartRequest
| fb::RemoteClientPayload::ProcessStopRequest
| fb::RemoteClientPayload::ProcessLogChannelRequest => {
Err(ProtocolError::UnexpectedPayload {
expected: "response",
})
}
_ => Err(ProtocolError::UnknownPayload),
}
}
fn decode_message(bytes: &[u8]) -> Result<fb::RemoteClientMessage<'_>, ProtocolError> {
if !fb::remote_client_message_buffer_has_identifier(bytes) {
return Err(ProtocolError::InvalidIdentifier);
}
Ok(flatbuffers::root::<fb::RemoteClientMessage>(bytes)?)
}
fn encode_request_payload<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
request: &Request,
) -> Result<
(
fb::RemoteClientPayload,
Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
),
ProtocolError,
> {
let payload = match request {
Request::ChannelCreate(capacity) => {
let payload = fb::ChannelCreateRequest::create(
builder,
&fb::ChannelCreateRequestArgs {
capacity: *capacity,
},
);
(
fb::RemoteClientPayload::ChannelCreateRequest,
Some(payload.as_union_value()),
)
}
Request::ChannelDelete(handle) => {
let payload = fb::ChannelDeleteRequest::create(
builder,
&fb::ChannelDeleteRequestArgs { handle: *handle },
);
(
fb::RemoteClientPayload::ChannelDeleteRequest,
Some(payload.as_union_value()),
)
}
Request::Subscribe(target, chunk_size) => {
let target = encode_channel_ref(builder, target);
let payload = fb::SubscribeRequest::create(
builder,
&fb::SubscribeRequestArgs {
target: Some(target),
chunk_size: *chunk_size,
},
);
(
fb::RemoteClientPayload::SubscribeRequest,
Some(payload.as_union_value()),
)
}
Request::Publish(handle) => {
let payload =
fb::PublishRequest::create(builder, &fb::PublishRequestArgs { handle: *handle });
(
fb::RemoteClientPayload::PublishRequest,
Some(payload.as_union_value()),
)
}
Request::ProcessStart(request) => {
let payload = encode_process_start_request(builder, request)?;
(
fb::RemoteClientPayload::ProcessStartRequest,
Some(payload.as_union_value()),
)
}
Request::ProcessStop(handle) => {
let payload = fb::ProcessStopRequest::create(
builder,
&fb::ProcessStopRequestArgs { handle: *handle },
);
(
fb::RemoteClientPayload::ProcessStopRequest,
Some(payload.as_union_value()),
)
}
Request::ProcessLogChannel(handle) => {
let payload = fb::ProcessLogChannelRequest::create(
builder,
&fb::ProcessLogChannelRequestArgs { handle: *handle },
);
(
fb::RemoteClientPayload::ProcessLogChannelRequest,
Some(payload.as_union_value()),
)
}
};
Ok(payload)
}
fn encode_response_payload<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
response: &Response,
) -> (
fb::RemoteClientPayload,
Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
) {
match response {
Response::ChannelCreate(handle) => {
let payload = fb::ChannelCreateResponse::create(
builder,
&fb::ChannelCreateResponseArgs { handle: *handle },
);
(
fb::RemoteClientPayload::ChannelCreateResponse,
Some(payload.as_union_value()),
)
}
Response::ChannelRead(frame) => {
let frame = encode_io_frame(builder, frame);
let payload = fb::ChannelReadResponse::create(
builder,
&fb::ChannelReadResponseArgs { frame: Some(frame) },
);
(
fb::RemoteClientPayload::ChannelReadResponse,
Some(payload.as_union_value()),
)
}
Response::ChannelWrite(len) => {
let payload = fb::ChannelWriteResponse::create(
builder,
&fb::ChannelWriteResponseArgs { len: *len },
);
(
fb::RemoteClientPayload::ChannelWriteResponse,
Some(payload.as_union_value()),
)
}
Response::ProcessStart(handle) => {
let payload = fb::ProcessStartResponse::create(
builder,
&fb::ProcessStartResponseArgs { handle: *handle },
);
(
fb::RemoteClientPayload::ProcessStartResponse,
Some(payload.as_union_value()),
)
}
Response::ProcessLogChannel(handle) => {
let payload = fb::ProcessLogChannelResponse::create(
builder,
&fb::ProcessLogChannelResponseArgs { handle: *handle },
);
(
fb::RemoteClientPayload::ProcessLogChannelResponse,
Some(payload.as_union_value()),
)
}
Response::Ok => {
let payload = fb::OkResponse::create(builder, &fb::OkResponseArgs {});
(
fb::RemoteClientPayload::OkResponse,
Some(payload.as_union_value()),
)
}
Response::Error(message) => {
let message = builder.create_string(message);
let payload = fb::ErrorResponse::create(
builder,
&fb::ErrorResponseArgs {
message: Some(message),
},
);
(
fb::RemoteClientPayload::ErrorResponse,
Some(payload.as_union_value()),
)
}
}
}
fn encode_channel_ref<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
target: &ChannelRef,
) -> flatbuffers::WIPOffset<fb::ChannelRef<'bldr>> {
let (kind, handle) = match target {
ChannelRef::Strong(handle) => (fb::ChannelRefKind::Strong, *handle),
ChannelRef::Shared(handle) => (fb::ChannelRefKind::Shared, *handle),
};
fb::ChannelRef::create(builder, &fb::ChannelRefArgs { kind, handle })
}
fn decode_channel_ref(channel_ref: fb::ChannelRef<'_>) -> Result<ChannelRef, ProtocolError> {
match channel_ref.kind() {
fb::ChannelRefKind::Strong => Ok(ChannelRef::Strong(channel_ref.handle())),
fb::ChannelRefKind::Shared => Ok(ChannelRef::Shared(channel_ref.handle())),
_ => Err(ProtocolError::UnknownChannelRefKind),
}
}
fn encode_process_start_request<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
request: &ProcessStartRequest,
) -> Result<flatbuffers::WIPOffset<fb::ProcessStartRequest<'bldr>>, ProtocolError> {
let module_id = builder.create_string(&request.module_id);
let entrypoint = builder.create_string(&request.entrypoint);
let log_uri = request
.log_uri
.as_ref()
.map(|value| builder.create_string(value));
let capabilities = encode_capabilities(builder, &request.capabilities)?;
let signature = encode_abi_signature(builder, &request.signature);
let args = encode_entrypoint_args(builder, &request.args);
Ok(fb::ProcessStartRequest::create(
builder,
&fb::ProcessStartRequestArgs {
module_id: Some(module_id),
entrypoint: Some(entrypoint),
log_uri,
capabilities: Some(capabilities),
signature: Some(signature),
args: Some(args),
},
))
}
fn decode_process_start_request(
request: fb::ProcessStartRequest<'_>,
) -> Result<ProcessStartRequest, ProtocolError> {
let module_id = request
.module_id()
.ok_or(ProtocolError::MissingField("process_start.module_id"))?
.to_string();
let entrypoint = request
.entrypoint()
.ok_or(ProtocolError::MissingField("process_start.entrypoint"))?
.to_string();
let log_uri = request.log_uri().map(|value| value.to_string());
let capabilities = decode_capabilities(request.capabilities())?;
let signature = request
.signature()
.ok_or(ProtocolError::MissingField("process_start.signature"))?;
let signature = decode_abi_signature(signature)?;
let args = decode_entrypoint_args(request.args())?;
Ok(ProcessStartRequest {
module_id,
entrypoint,
log_uri,
capabilities,
signature,
args,
})
}
fn encode_capabilities<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
caps: &[Capability],
) -> Result<flatbuffers::WIPOffset<flatbuffers::Vector<'bldr, fb::Capability>>, ProtocolError> {
let mut values = Vec::with_capacity(caps.len());
for cap in caps {
values.push(encode_capability(*cap)?);
}
Ok(builder.create_vector(&values))
}
fn decode_capabilities(
caps: Option<flatbuffers::Vector<'_, fb::Capability>>,
) -> Result<Vec<Capability>, ProtocolError> {
let mut out = Vec::new();
if let Some(vec) = caps {
for cap in vec.iter() {
out.push(decode_capability(cap)?);
}
}
Ok(out)
}
fn encode_capability(value: Capability) -> Result<fb::Capability, ProtocolError> {
match value {
Capability::SessionLifecycle => Ok(fb::Capability::SessionLifecycle),
Capability::ChannelLifecycle => Ok(fb::Capability::ChannelLifecycle),
Capability::ChannelReader => Ok(fb::Capability::ChannelReader),
Capability::ChannelWriter => Ok(fb::Capability::ChannelWriter),
Capability::ProcessLifecycle => Ok(fb::Capability::ProcessLifecycle),
Capability::NetQuicBind => Ok(fb::Capability::NetQuicBind),
Capability::NetQuicAccept => Ok(fb::Capability::NetQuicAccept),
Capability::NetQuicConnect => Ok(fb::Capability::NetQuicConnect),
Capability::NetQuicRead => Ok(fb::Capability::NetQuicRead),
Capability::NetQuicWrite => Ok(fb::Capability::NetQuicWrite),
Capability::NetHttpBind => Ok(fb::Capability::NetHttpBind),
Capability::NetHttpAccept => Ok(fb::Capability::NetHttpAccept),
Capability::NetHttpConnect => Ok(fb::Capability::NetHttpConnect),
Capability::NetHttpRead => Ok(fb::Capability::NetHttpRead),
Capability::NetHttpWrite => Ok(fb::Capability::NetHttpWrite),
Capability::NetTlsServerConfig => Ok(fb::Capability::NetTlsServerConfig),
Capability::NetTlsClientConfig => Ok(fb::Capability::NetTlsClientConfig),
Capability::SingletonRegistry => Ok(fb::Capability::SingletonRegistry),
Capability::SingletonLookup => Ok(fb::Capability::SingletonLookup),
Capability::TimeRead => Ok(fb::Capability::TimeRead),
}
}
fn decode_capability(value: fb::Capability) -> Result<Capability, ProtocolError> {
match value {
fb::Capability::SessionLifecycle => Ok(Capability::SessionLifecycle),
fb::Capability::ChannelLifecycle => Ok(Capability::ChannelLifecycle),
fb::Capability::ChannelReader => Ok(Capability::ChannelReader),
fb::Capability::ChannelWriter => Ok(Capability::ChannelWriter),
fb::Capability::ProcessLifecycle => Ok(Capability::ProcessLifecycle),
fb::Capability::NetQuicBind => Ok(Capability::NetQuicBind),
fb::Capability::NetQuicAccept => Ok(Capability::NetQuicAccept),
fb::Capability::NetQuicConnect => Ok(Capability::NetQuicConnect),
fb::Capability::NetQuicRead => Ok(Capability::NetQuicRead),
fb::Capability::NetQuicWrite => Ok(Capability::NetQuicWrite),
fb::Capability::NetHttpBind => Ok(Capability::NetHttpBind),
fb::Capability::NetHttpAccept => Ok(Capability::NetHttpAccept),
fb::Capability::NetHttpConnect => Ok(Capability::NetHttpConnect),
fb::Capability::NetHttpRead => Ok(Capability::NetHttpRead),
fb::Capability::NetHttpWrite => Ok(Capability::NetHttpWrite),
fb::Capability::NetTlsServerConfig => Ok(Capability::NetTlsServerConfig),
fb::Capability::NetTlsClientConfig => Ok(Capability::NetTlsClientConfig),
fb::Capability::SingletonRegistry => Ok(Capability::SingletonRegistry),
fb::Capability::SingletonLookup => Ok(Capability::SingletonLookup),
fb::Capability::TimeRead => Ok(Capability::TimeRead),
_ => Err(ProtocolError::UnknownCapability),
}
}
fn encode_abi_signature<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
signature: &AbiSignature,
) -> flatbuffers::WIPOffset<fb::AbiSignature<'bldr>> {
let params = encode_abi_params(builder, signature.params());
let results = encode_abi_params(builder, signature.results());
fb::AbiSignature::create(
builder,
&fb::AbiSignatureArgs {
params: Some(params),
results: Some(results),
},
)
}
fn decode_abi_signature(signature: fb::AbiSignature<'_>) -> Result<AbiSignature, ProtocolError> {
let params = decode_abi_params(signature.params())?;
let results = decode_abi_params(signature.results())?;
Ok(AbiSignature::new(params, results))
}
fn encode_abi_params<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
params: &[AbiParam],
) -> flatbuffers::WIPOffset<
flatbuffers::Vector<'bldr, flatbuffers::ForwardsUOffset<fb::AbiParam<'bldr>>>,
> {
let items: Vec<_> = params
.iter()
.map(|param| encode_abi_param(builder, param))
.collect();
builder.create_vector(&items)
}
fn decode_abi_params(
params: Option<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<fb::AbiParam<'_>>>>,
) -> Result<Vec<AbiParam>, ProtocolError> {
let mut out = Vec::new();
if let Some(vec) = params {
for param in vec {
out.push(decode_abi_param(param)?);
}
}
Ok(out)
}
fn encode_abi_param<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
param: &AbiParam,
) -> flatbuffers::WIPOffset<fb::AbiParam<'bldr>> {
let (kind, scalar_type) = match param {
AbiParam::Scalar(scalar) => (fb::AbiParamKind::Scalar, encode_abi_scalar_type(*scalar)),
AbiParam::Buffer => (fb::AbiParamKind::Buffer, fb::AbiScalarType::I8),
};
fb::AbiParam::create(builder, &fb::AbiParamArgs { kind, scalar_type })
}
fn decode_abi_param(param: fb::AbiParam<'_>) -> Result<AbiParam, ProtocolError> {
match param.kind() {
fb::AbiParamKind::Scalar => {
let scalar = decode_abi_scalar_type(param.scalar_type())?;
Ok(AbiParam::Scalar(scalar))
}
fb::AbiParamKind::Buffer => Ok(AbiParam::Buffer),
_ => Err(ProtocolError::UnknownAbiParamKind),
}
}
fn encode_entrypoint_args<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
args: &[EntrypointArg],
) -> flatbuffers::WIPOffset<
flatbuffers::Vector<'bldr, flatbuffers::ForwardsUOffset<fb::EntrypointArg<'bldr>>>,
> {
let items: Vec<_> = args
.iter()
.map(|arg| encode_entrypoint_arg(builder, arg))
.collect();
builder.create_vector(&items)
}
fn decode_entrypoint_args(
args: Option<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<fb::EntrypointArg<'_>>>>,
) -> Result<Vec<EntrypointArg>, ProtocolError> {
let mut out = Vec::new();
if let Some(vec) = args {
for arg in vec {
out.push(decode_entrypoint_arg(arg)?);
}
}
Ok(out)
}
fn encode_entrypoint_arg<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
arg: &EntrypointArg,
) -> flatbuffers::WIPOffset<fb::EntrypointArg<'bldr>> {
match arg {
EntrypointArg::Scalar(value) => {
let scalar = encode_scalar_value(builder, value);
fb::EntrypointArg::create(
builder,
&fb::EntrypointArgArgs {
kind: fb::EntrypointArgKind::Scalar,
scalar: Some(scalar),
buffer: None,
resource: 0,
},
)
}
EntrypointArg::Buffer(bytes) => {
let buffer = builder.create_vector(bytes);
fb::EntrypointArg::create(
builder,
&fb::EntrypointArgArgs {
kind: fb::EntrypointArgKind::Buffer,
scalar: None,
buffer: Some(buffer),
resource: 0,
},
)
}
EntrypointArg::Resource(handle) => fb::EntrypointArg::create(
builder,
&fb::EntrypointArgArgs {
kind: fb::EntrypointArgKind::Resource,
scalar: None,
buffer: None,
resource: *handle,
},
),
}
}
fn decode_entrypoint_arg(arg: fb::EntrypointArg<'_>) -> Result<EntrypointArg, ProtocolError> {
match arg.kind() {
fb::EntrypointArgKind::Scalar => {
let scalar = arg
.scalar()
.ok_or(ProtocolError::MissingField("entrypoint_arg.scalar"))?;
Ok(EntrypointArg::Scalar(decode_scalar_value(scalar)?))
}
fb::EntrypointArgKind::Buffer => {
let payload = arg
.buffer()
.map(|buf| buf.iter().collect())
.unwrap_or_default();
Ok(EntrypointArg::Buffer(payload))
}
fb::EntrypointArgKind::Resource => Ok(EntrypointArg::Resource(arg.resource())),
_ => Err(ProtocolError::UnknownEntrypointArgKind),
}
}
fn encode_scalar_value<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
value: &AbiScalarValue,
) -> flatbuffers::WIPOffset<fb::ScalarValue<'bldr>> {
let (kind, bits) = scalar_bits(value);
fb::ScalarValue::create(builder, &fb::ScalarValueArgs { kind, bits })
}
fn decode_scalar_value(value: fb::ScalarValue<'_>) -> Result<AbiScalarValue, ProtocolError> {
let kind = decode_abi_scalar_type(value.kind())?;
let bits = value.bits();
let bytes = bits.to_le_bytes();
let scalar = match kind {
AbiScalarType::I8 => AbiScalarValue::I8(i8::from_le_bytes([bytes[0]])),
AbiScalarType::U8 => AbiScalarValue::U8(bytes[0]),
AbiScalarType::I16 => AbiScalarValue::I16(i16::from_le_bytes([bytes[0], bytes[1]])),
AbiScalarType::U16 => AbiScalarValue::U16(u16::from_le_bytes([bytes[0], bytes[1]])),
AbiScalarType::I32 => {
AbiScalarValue::I32(i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
}
AbiScalarType::U32 => {
AbiScalarValue::U32(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
}
AbiScalarType::I64 => AbiScalarValue::I64(i64::from_le_bytes(bytes)),
AbiScalarType::U64 => AbiScalarValue::U64(bits),
AbiScalarType::F32 => AbiScalarValue::F32(f32::from_bits(u32::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
]))),
AbiScalarType::F64 => AbiScalarValue::F64(f64::from_bits(bits)),
};
Ok(scalar)
}
fn scalar_bits(value: &AbiScalarValue) -> (fb::AbiScalarType, u64) {
match value {
AbiScalarValue::I8(v) => (
fb::AbiScalarType::I8,
u64::from_le_bytes(i64::from(*v).to_le_bytes()),
),
AbiScalarValue::U8(v) => (fb::AbiScalarType::U8, u64::from(*v)),
AbiScalarValue::I16(v) => (
fb::AbiScalarType::I16,
u64::from_le_bytes(i64::from(*v).to_le_bytes()),
),
AbiScalarValue::U16(v) => (fb::AbiScalarType::U16, u64::from(*v)),
AbiScalarValue::I32(v) => (
fb::AbiScalarType::I32,
u64::from_le_bytes(i64::from(*v).to_le_bytes()),
),
AbiScalarValue::U32(v) => (fb::AbiScalarType::U32, u64::from(*v)),
AbiScalarValue::I64(v) => (fb::AbiScalarType::I64, u64::from_le_bytes(v.to_le_bytes())),
AbiScalarValue::U64(v) => (fb::AbiScalarType::U64, *v),
AbiScalarValue::F32(v) => (fb::AbiScalarType::F32, u64::from(v.to_bits())),
AbiScalarValue::F64(v) => (fb::AbiScalarType::F64, v.to_bits()),
}
}
fn encode_abi_scalar_type(value: AbiScalarType) -> fb::AbiScalarType {
match value {
AbiScalarType::I8 => fb::AbiScalarType::I8,
AbiScalarType::U8 => fb::AbiScalarType::U8,
AbiScalarType::I16 => fb::AbiScalarType::I16,
AbiScalarType::U16 => fb::AbiScalarType::U16,
AbiScalarType::I32 => fb::AbiScalarType::I32,
AbiScalarType::U32 => fb::AbiScalarType::U32,
AbiScalarType::I64 => fb::AbiScalarType::I64,
AbiScalarType::U64 => fb::AbiScalarType::U64,
AbiScalarType::F32 => fb::AbiScalarType::F32,
AbiScalarType::F64 => fb::AbiScalarType::F64,
}
}
fn decode_abi_scalar_type(value: fb::AbiScalarType) -> Result<AbiScalarType, ProtocolError> {
match value {
fb::AbiScalarType::I8 => Ok(AbiScalarType::I8),
fb::AbiScalarType::U8 => Ok(AbiScalarType::U8),
fb::AbiScalarType::I16 => Ok(AbiScalarType::I16),
fb::AbiScalarType::U16 => Ok(AbiScalarType::U16),
fb::AbiScalarType::I32 => Ok(AbiScalarType::I32),
fb::AbiScalarType::U32 => Ok(AbiScalarType::U32),
fb::AbiScalarType::I64 => Ok(AbiScalarType::I64),
fb::AbiScalarType::U64 => Ok(AbiScalarType::U64),
fb::AbiScalarType::F32 => Ok(AbiScalarType::F32),
fb::AbiScalarType::F64 => Ok(AbiScalarType::F64),
_ => Err(ProtocolError::UnknownAbiScalarType),
}
}
fn encode_io_frame<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
frame: &IoFrame,
) -> flatbuffers::WIPOffset<fb::IoFrame<'bldr>> {
let payload = builder.create_vector(&frame.payload);
fb::IoFrame::create(
builder,
&fb::IoFrameArgs {
writer_id: frame.writer_id,
payload: Some(payload),
},
)
}
fn decode_io_frame(frame: fb::IoFrame<'_>) -> Result<IoFrame, ProtocolError> {
let payload = frame
.payload()
.map(|buf| buf.iter().collect())
.unwrap_or_default();
Ok(IoFrame {
writer_id: frame.writer_id(),
payload,
})
}