Skip to main content

selium_remote_client_protocol/
lib.rs

1//! Flatbuffers protocol helpers for the remote-client control plane.
2
3use flatbuffers::{FlatBufferBuilder, InvalidFlatbuffer};
4pub use selium_abi::{
5    AbiParam, AbiScalarType, AbiScalarValue, AbiSignature, Capability, EntrypointArg,
6    GuestResourceId, GuestUint,
7};
8use thiserror::Error;
9
10/// Generated Flatbuffers bindings for the remote-client protocol.
11#[allow(missing_docs)]
12#[allow(warnings)]
13#[rustfmt::skip]
14pub mod fbs;
15
16use crate::fbs::remote_client::protocol as fb;
17
18const REMOTE_CLIENT_IDENTIFIER: &str = "RMCL";
19
20/// Identifier for a writer that produced a frame.
21pub type GuestWriterId = u16;
22
23/// Response carrying an attributed frame.
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct IoFrame {
26    /// Identifier of the writer that produced this frame.
27    pub writer_id: GuestWriterId,
28    /// Frame payload.
29    pub payload: Vec<u8>,
30}
31
32/// Requests accepted by the remote-client guest.
33#[derive(Clone, Debug, PartialEq)]
34pub enum Request {
35    /// Create a channel with the requested capacity.
36    ChannelCreate(GuestUint),
37    /// Delete the referenced channel.
38    ChannelDelete(GuestResourceId),
39    /// Subscribe to a channel with the requested chunk size.
40    Subscribe(ChannelRef, GuestUint),
41    /// Publish frames into a channel.
42    Publish(GuestResourceId),
43    /// Start a process with the supplied details.
44    ProcessStart(ProcessStartRequest),
45    /// Stop the referenced process.
46    ProcessStop(GuestResourceId),
47    /// Fetch the logging channel for the referenced process.
48    ProcessLogChannel(GuestResourceId),
49}
50
51/// Responses emitted by the remote-client guest.
52#[derive(Clone, Debug, PartialEq)]
53pub enum Response {
54    /// Channel creation response returning the channel handle.
55    ChannelCreate(GuestResourceId),
56    /// Frame payload returned from a channel read.
57    ChannelRead(IoFrame),
58    /// Acknowledgement of a channel write request.
59    ChannelWrite(GuestUint),
60    /// Process start response returning the process handle.
61    ProcessStart(GuestResourceId),
62    /// Logging channel response returning the channel handle.
63    ProcessLogChannel(GuestResourceId),
64    /// Success response with no additional payload.
65    Ok,
66    /// Error response containing a human-readable message.
67    Error(String),
68}
69
70/// Reference to a channel capability.
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub enum ChannelRef {
73    /// Strong channel handle (read/write access).
74    Strong(GuestResourceId),
75    /// Shared channel handle (read access only).
76    Shared(GuestResourceId),
77}
78
79/// Request payload used to start a process in the runtime.
80#[derive(Clone, Debug, PartialEq)]
81pub struct ProcessStartRequest {
82    /// Module identifier that should be activated.
83    pub module_id: String,
84    /// Entrypoint symbol exposed by the module.
85    pub entrypoint: String,
86    /// Optional log URI passed to the entrypoint when Atlas is enabled.
87    pub log_uri: Option<String>,
88    /// Capabilities granted to the process.
89    pub capabilities: Vec<Capability>,
90    /// Entrypoint signature describing parameter and result layouts.
91    pub signature: AbiSignature,
92    /// Arguments supplied to the entrypoint.
93    pub args: Vec<EntrypointArg>,
94}
95
96/// Errors produced while encoding or decoding remote-client payloads.
97#[derive(Debug, Error)]
98pub enum ProtocolError {
99    /// Flatbuffers payload failed to verify.
100    #[error("invalid flatbuffer: {0:?}")]
101    InvalidFlatbuffer(InvalidFlatbuffer),
102    /// Message payload was not present.
103    #[error("remote-client message missing payload")]
104    MissingPayload,
105    /// Message payload type is unsupported.
106    #[error("unknown remote-client payload type")]
107    UnknownPayload,
108    /// Remote-client message identifier did not match.
109    #[error("invalid remote-client message identifier")]
110    InvalidIdentifier,
111    /// Payload kind did not match the expected direction.
112    #[error("remote-client payload was not a {expected}")]
113    UnexpectedPayload { expected: &'static str },
114    /// Capability variant was not recognised.
115    #[error("unknown capability variant")]
116    UnknownCapability,
117    /// ABI scalar type was not recognised.
118    #[error("unknown ABI scalar type")]
119    UnknownAbiScalarType,
120    /// ABI parameter kind was not recognised.
121    #[error("unknown ABI parameter kind")]
122    UnknownAbiParamKind,
123    /// Channel reference kind was not recognised.
124    #[error("unknown channel reference kind")]
125    UnknownChannelRefKind,
126    /// Entrypoint argument kind was not recognised.
127    #[error("unknown entrypoint argument kind")]
128    UnknownEntrypointArgKind,
129    /// Required field was missing from the payload.
130    #[error("missing remote-client field: {0}")]
131    MissingField(&'static str),
132}
133
134impl From<InvalidFlatbuffer> for ProtocolError {
135    fn from(value: InvalidFlatbuffer) -> Self {
136        ProtocolError::InvalidFlatbuffer(value)
137    }
138}
139
140/// Encode a remote-client request into Flatbuffers bytes.
141pub fn encode_request(request: &Request) -> Result<Vec<u8>, ProtocolError> {
142    let mut builder = FlatBufferBuilder::new();
143    let (payload_type, payload) = encode_request_payload(&mut builder, request)?;
144    let message = fb::RemoteClientMessage::create(
145        &mut builder,
146        &fb::RemoteClientMessageArgs {
147            payload_type,
148            payload,
149        },
150    );
151    builder.finish(message, Some(REMOTE_CLIENT_IDENTIFIER));
152    Ok(builder.finished_data().to_vec())
153}
154
155/// Decode Flatbuffers bytes into a remote-client request.
156pub fn decode_request(bytes: &[u8]) -> Result<Request, ProtocolError> {
157    let message = decode_message(bytes)?;
158
159    match message.payload_type() {
160        fb::RemoteClientPayload::ChannelCreateRequest => {
161            let req = message
162                .payload_as_channel_create_request()
163                .ok_or(ProtocolError::MissingPayload)?;
164            Ok(Request::ChannelCreate(req.capacity()))
165        }
166        fb::RemoteClientPayload::ChannelDeleteRequest => {
167            let req = message
168                .payload_as_channel_delete_request()
169                .ok_or(ProtocolError::MissingPayload)?;
170            Ok(Request::ChannelDelete(req.handle()))
171        }
172        fb::RemoteClientPayload::SubscribeRequest => {
173            let req = message
174                .payload_as_subscribe_request()
175                .ok_or(ProtocolError::MissingPayload)?;
176            let target = decode_channel_ref(
177                req.target()
178                    .ok_or(ProtocolError::MissingField("subscribe.target"))?,
179            )?;
180            Ok(Request::Subscribe(target, req.chunk_size()))
181        }
182        fb::RemoteClientPayload::PublishRequest => {
183            let req = message
184                .payload_as_publish_request()
185                .ok_or(ProtocolError::MissingPayload)?;
186            Ok(Request::Publish(req.handle()))
187        }
188        fb::RemoteClientPayload::ProcessStartRequest => {
189            let req = message
190                .payload_as_process_start_request()
191                .ok_or(ProtocolError::MissingPayload)?;
192            Ok(Request::ProcessStart(decode_process_start_request(req)?))
193        }
194        fb::RemoteClientPayload::ProcessStopRequest => {
195            let req = message
196                .payload_as_process_stop_request()
197                .ok_or(ProtocolError::MissingPayload)?;
198            Ok(Request::ProcessStop(req.handle()))
199        }
200        fb::RemoteClientPayload::ProcessLogChannelRequest => {
201            let req = message
202                .payload_as_process_log_channel_request()
203                .ok_or(ProtocolError::MissingPayload)?;
204            Ok(Request::ProcessLogChannel(req.handle()))
205        }
206        fb::RemoteClientPayload::ChannelCreateResponse
207        | fb::RemoteClientPayload::ChannelReadResponse
208        | fb::RemoteClientPayload::ChannelWriteResponse
209        | fb::RemoteClientPayload::ProcessStartResponse
210        | fb::RemoteClientPayload::ProcessLogChannelResponse
211        | fb::RemoteClientPayload::OkResponse
212        | fb::RemoteClientPayload::ErrorResponse => Err(ProtocolError::UnexpectedPayload {
213            expected: "request",
214        }),
215        _ => Err(ProtocolError::UnknownPayload),
216    }
217}
218
219/// Encode a remote-client response into Flatbuffers bytes.
220pub fn encode_response(response: &Response) -> Result<Vec<u8>, ProtocolError> {
221    let mut builder = FlatBufferBuilder::new();
222    let (payload_type, payload) = encode_response_payload(&mut builder, response);
223    let message = fb::RemoteClientMessage::create(
224        &mut builder,
225        &fb::RemoteClientMessageArgs {
226            payload_type,
227            payload,
228        },
229    );
230    builder.finish(message, Some(REMOTE_CLIENT_IDENTIFIER));
231    Ok(builder.finished_data().to_vec())
232}
233
234/// Decode Flatbuffers bytes into a remote-client response.
235pub fn decode_response(bytes: &[u8]) -> Result<Response, ProtocolError> {
236    let message = decode_message(bytes)?;
237
238    match message.payload_type() {
239        fb::RemoteClientPayload::ChannelCreateResponse => {
240            let resp = message
241                .payload_as_channel_create_response()
242                .ok_or(ProtocolError::MissingPayload)?;
243            Ok(Response::ChannelCreate(resp.handle()))
244        }
245        fb::RemoteClientPayload::ChannelReadResponse => {
246            let resp = message
247                .payload_as_channel_read_response()
248                .ok_or(ProtocolError::MissingPayload)?;
249            let frame = resp
250                .frame()
251                .ok_or(ProtocolError::MissingField("channel_read.frame"))?;
252            Ok(Response::ChannelRead(decode_io_frame(frame)?))
253        }
254        fb::RemoteClientPayload::ChannelWriteResponse => {
255            let resp = message
256                .payload_as_channel_write_response()
257                .ok_or(ProtocolError::MissingPayload)?;
258            Ok(Response::ChannelWrite(resp.len()))
259        }
260        fb::RemoteClientPayload::ProcessStartResponse => {
261            let resp = message
262                .payload_as_process_start_response()
263                .ok_or(ProtocolError::MissingPayload)?;
264            Ok(Response::ProcessStart(resp.handle()))
265        }
266        fb::RemoteClientPayload::ProcessLogChannelResponse => {
267            let resp = message
268                .payload_as_process_log_channel_response()
269                .ok_or(ProtocolError::MissingPayload)?;
270            Ok(Response::ProcessLogChannel(resp.handle()))
271        }
272        fb::RemoteClientPayload::OkResponse => Ok(Response::Ok),
273        fb::RemoteClientPayload::ErrorResponse => {
274            let resp = message
275                .payload_as_error_response()
276                .ok_or(ProtocolError::MissingPayload)?;
277            let message = resp
278                .message()
279                .ok_or(ProtocolError::MissingField("error.message"))?
280                .to_string();
281            Ok(Response::Error(message))
282        }
283        fb::RemoteClientPayload::ChannelCreateRequest
284        | fb::RemoteClientPayload::ChannelDeleteRequest
285        | fb::RemoteClientPayload::SubscribeRequest
286        | fb::RemoteClientPayload::PublishRequest
287        | fb::RemoteClientPayload::ProcessStartRequest
288        | fb::RemoteClientPayload::ProcessStopRequest
289        | fb::RemoteClientPayload::ProcessLogChannelRequest => {
290            Err(ProtocolError::UnexpectedPayload {
291                expected: "response",
292            })
293        }
294        _ => Err(ProtocolError::UnknownPayload),
295    }
296}
297
298fn decode_message(bytes: &[u8]) -> Result<fb::RemoteClientMessage<'_>, ProtocolError> {
299    if !fb::remote_client_message_buffer_has_identifier(bytes) {
300        return Err(ProtocolError::InvalidIdentifier);
301    }
302    Ok(flatbuffers::root::<fb::RemoteClientMessage>(bytes)?)
303}
304
305fn encode_request_payload<'bldr>(
306    builder: &mut FlatBufferBuilder<'bldr>,
307    request: &Request,
308) -> Result<
309    (
310        fb::RemoteClientPayload,
311        Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
312    ),
313    ProtocolError,
314> {
315    let payload = match request {
316        Request::ChannelCreate(capacity) => {
317            let payload = fb::ChannelCreateRequest::create(
318                builder,
319                &fb::ChannelCreateRequestArgs {
320                    capacity: *capacity,
321                },
322            );
323            (
324                fb::RemoteClientPayload::ChannelCreateRequest,
325                Some(payload.as_union_value()),
326            )
327        }
328        Request::ChannelDelete(handle) => {
329            let payload = fb::ChannelDeleteRequest::create(
330                builder,
331                &fb::ChannelDeleteRequestArgs { handle: *handle },
332            );
333            (
334                fb::RemoteClientPayload::ChannelDeleteRequest,
335                Some(payload.as_union_value()),
336            )
337        }
338        Request::Subscribe(target, chunk_size) => {
339            let target = encode_channel_ref(builder, target);
340            let payload = fb::SubscribeRequest::create(
341                builder,
342                &fb::SubscribeRequestArgs {
343                    target: Some(target),
344                    chunk_size: *chunk_size,
345                },
346            );
347            (
348                fb::RemoteClientPayload::SubscribeRequest,
349                Some(payload.as_union_value()),
350            )
351        }
352        Request::Publish(handle) => {
353            let payload =
354                fb::PublishRequest::create(builder, &fb::PublishRequestArgs { handle: *handle });
355            (
356                fb::RemoteClientPayload::PublishRequest,
357                Some(payload.as_union_value()),
358            )
359        }
360        Request::ProcessStart(request) => {
361            let payload = encode_process_start_request(builder, request)?;
362            (
363                fb::RemoteClientPayload::ProcessStartRequest,
364                Some(payload.as_union_value()),
365            )
366        }
367        Request::ProcessStop(handle) => {
368            let payload = fb::ProcessStopRequest::create(
369                builder,
370                &fb::ProcessStopRequestArgs { handle: *handle },
371            );
372            (
373                fb::RemoteClientPayload::ProcessStopRequest,
374                Some(payload.as_union_value()),
375            )
376        }
377        Request::ProcessLogChannel(handle) => {
378            let payload = fb::ProcessLogChannelRequest::create(
379                builder,
380                &fb::ProcessLogChannelRequestArgs { handle: *handle },
381            );
382            (
383                fb::RemoteClientPayload::ProcessLogChannelRequest,
384                Some(payload.as_union_value()),
385            )
386        }
387    };
388    Ok(payload)
389}
390
391fn encode_response_payload<'bldr>(
392    builder: &mut FlatBufferBuilder<'bldr>,
393    response: &Response,
394) -> (
395    fb::RemoteClientPayload,
396    Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
397) {
398    match response {
399        Response::ChannelCreate(handle) => {
400            let payload = fb::ChannelCreateResponse::create(
401                builder,
402                &fb::ChannelCreateResponseArgs { handle: *handle },
403            );
404            (
405                fb::RemoteClientPayload::ChannelCreateResponse,
406                Some(payload.as_union_value()),
407            )
408        }
409        Response::ChannelRead(frame) => {
410            let frame = encode_io_frame(builder, frame);
411            let payload = fb::ChannelReadResponse::create(
412                builder,
413                &fb::ChannelReadResponseArgs { frame: Some(frame) },
414            );
415            (
416                fb::RemoteClientPayload::ChannelReadResponse,
417                Some(payload.as_union_value()),
418            )
419        }
420        Response::ChannelWrite(len) => {
421            let payload = fb::ChannelWriteResponse::create(
422                builder,
423                &fb::ChannelWriteResponseArgs { len: *len },
424            );
425            (
426                fb::RemoteClientPayload::ChannelWriteResponse,
427                Some(payload.as_union_value()),
428            )
429        }
430        Response::ProcessStart(handle) => {
431            let payload = fb::ProcessStartResponse::create(
432                builder,
433                &fb::ProcessStartResponseArgs { handle: *handle },
434            );
435            (
436                fb::RemoteClientPayload::ProcessStartResponse,
437                Some(payload.as_union_value()),
438            )
439        }
440        Response::ProcessLogChannel(handle) => {
441            let payload = fb::ProcessLogChannelResponse::create(
442                builder,
443                &fb::ProcessLogChannelResponseArgs { handle: *handle },
444            );
445            (
446                fb::RemoteClientPayload::ProcessLogChannelResponse,
447                Some(payload.as_union_value()),
448            )
449        }
450        Response::Ok => {
451            let payload = fb::OkResponse::create(builder, &fb::OkResponseArgs {});
452            (
453                fb::RemoteClientPayload::OkResponse,
454                Some(payload.as_union_value()),
455            )
456        }
457        Response::Error(message) => {
458            let message = builder.create_string(message);
459            let payload = fb::ErrorResponse::create(
460                builder,
461                &fb::ErrorResponseArgs {
462                    message: Some(message),
463                },
464            );
465            (
466                fb::RemoteClientPayload::ErrorResponse,
467                Some(payload.as_union_value()),
468            )
469        }
470    }
471}
472
473fn encode_channel_ref<'bldr>(
474    builder: &mut FlatBufferBuilder<'bldr>,
475    target: &ChannelRef,
476) -> flatbuffers::WIPOffset<fb::ChannelRef<'bldr>> {
477    let (kind, handle) = match target {
478        ChannelRef::Strong(handle) => (fb::ChannelRefKind::Strong, *handle),
479        ChannelRef::Shared(handle) => (fb::ChannelRefKind::Shared, *handle),
480    };
481
482    fb::ChannelRef::create(builder, &fb::ChannelRefArgs { kind, handle })
483}
484
485fn decode_channel_ref(channel_ref: fb::ChannelRef<'_>) -> Result<ChannelRef, ProtocolError> {
486    match channel_ref.kind() {
487        fb::ChannelRefKind::Strong => Ok(ChannelRef::Strong(channel_ref.handle())),
488        fb::ChannelRefKind::Shared => Ok(ChannelRef::Shared(channel_ref.handle())),
489        _ => Err(ProtocolError::UnknownChannelRefKind),
490    }
491}
492
493fn encode_process_start_request<'bldr>(
494    builder: &mut FlatBufferBuilder<'bldr>,
495    request: &ProcessStartRequest,
496) -> Result<flatbuffers::WIPOffset<fb::ProcessStartRequest<'bldr>>, ProtocolError> {
497    let module_id = builder.create_string(&request.module_id);
498    let entrypoint = builder.create_string(&request.entrypoint);
499    let log_uri = request
500        .log_uri
501        .as_ref()
502        .map(|value| builder.create_string(value));
503    let capabilities = encode_capabilities(builder, &request.capabilities)?;
504    let signature = encode_abi_signature(builder, &request.signature);
505    let args = encode_entrypoint_args(builder, &request.args);
506
507    Ok(fb::ProcessStartRequest::create(
508        builder,
509        &fb::ProcessStartRequestArgs {
510            module_id: Some(module_id),
511            entrypoint: Some(entrypoint),
512            log_uri,
513            capabilities: Some(capabilities),
514            signature: Some(signature),
515            args: Some(args),
516        },
517    ))
518}
519
520fn decode_process_start_request(
521    request: fb::ProcessStartRequest<'_>,
522) -> Result<ProcessStartRequest, ProtocolError> {
523    let module_id = request
524        .module_id()
525        .ok_or(ProtocolError::MissingField("process_start.module_id"))?
526        .to_string();
527    let entrypoint = request
528        .entrypoint()
529        .ok_or(ProtocolError::MissingField("process_start.entrypoint"))?
530        .to_string();
531    let log_uri = request.log_uri().map(|value| value.to_string());
532    let capabilities = decode_capabilities(request.capabilities())?;
533    let signature = request
534        .signature()
535        .ok_or(ProtocolError::MissingField("process_start.signature"))?;
536    let signature = decode_abi_signature(signature)?;
537    let args = decode_entrypoint_args(request.args())?;
538
539    Ok(ProcessStartRequest {
540        module_id,
541        entrypoint,
542        log_uri,
543        capabilities,
544        signature,
545        args,
546    })
547}
548
549fn encode_capabilities<'bldr>(
550    builder: &mut FlatBufferBuilder<'bldr>,
551    caps: &[Capability],
552) -> Result<flatbuffers::WIPOffset<flatbuffers::Vector<'bldr, fb::Capability>>, ProtocolError> {
553    let mut values = Vec::with_capacity(caps.len());
554    for cap in caps {
555        values.push(encode_capability(*cap)?);
556    }
557    Ok(builder.create_vector(&values))
558}
559
560fn decode_capabilities(
561    caps: Option<flatbuffers::Vector<'_, fb::Capability>>,
562) -> Result<Vec<Capability>, ProtocolError> {
563    let mut out = Vec::new();
564    if let Some(vec) = caps {
565        for cap in vec.iter() {
566            out.push(decode_capability(cap)?);
567        }
568    }
569    Ok(out)
570}
571
572fn encode_capability(value: Capability) -> Result<fb::Capability, ProtocolError> {
573    match value {
574        Capability::SessionLifecycle => Ok(fb::Capability::SessionLifecycle),
575        Capability::ChannelLifecycle => Ok(fb::Capability::ChannelLifecycle),
576        Capability::ChannelReader => Ok(fb::Capability::ChannelReader),
577        Capability::ChannelWriter => Ok(fb::Capability::ChannelWriter),
578        Capability::ProcessLifecycle => Ok(fb::Capability::ProcessLifecycle),
579        Capability::NetQuicBind => Ok(fb::Capability::NetQuicBind),
580        Capability::NetQuicAccept => Ok(fb::Capability::NetQuicAccept),
581        Capability::NetQuicConnect => Ok(fb::Capability::NetQuicConnect),
582        Capability::NetQuicRead => Ok(fb::Capability::NetQuicRead),
583        Capability::NetQuicWrite => Ok(fb::Capability::NetQuicWrite),
584        Capability::NetHttpBind => Ok(fb::Capability::NetHttpBind),
585        Capability::NetHttpAccept => Ok(fb::Capability::NetHttpAccept),
586        Capability::NetHttpConnect => Ok(fb::Capability::NetHttpConnect),
587        Capability::NetHttpRead => Ok(fb::Capability::NetHttpRead),
588        Capability::NetHttpWrite => Ok(fb::Capability::NetHttpWrite),
589        Capability::NetTlsServerConfig => Ok(fb::Capability::NetTlsServerConfig),
590        Capability::NetTlsClientConfig => Ok(fb::Capability::NetTlsClientConfig),
591        Capability::SingletonRegistry => Ok(fb::Capability::SingletonRegistry),
592        Capability::SingletonLookup => Ok(fb::Capability::SingletonLookup),
593        Capability::TimeRead => Ok(fb::Capability::TimeRead),
594    }
595}
596
597fn decode_capability(value: fb::Capability) -> Result<Capability, ProtocolError> {
598    match value {
599        fb::Capability::SessionLifecycle => Ok(Capability::SessionLifecycle),
600        fb::Capability::ChannelLifecycle => Ok(Capability::ChannelLifecycle),
601        fb::Capability::ChannelReader => Ok(Capability::ChannelReader),
602        fb::Capability::ChannelWriter => Ok(Capability::ChannelWriter),
603        fb::Capability::ProcessLifecycle => Ok(Capability::ProcessLifecycle),
604        fb::Capability::NetQuicBind => Ok(Capability::NetQuicBind),
605        fb::Capability::NetQuicAccept => Ok(Capability::NetQuicAccept),
606        fb::Capability::NetQuicConnect => Ok(Capability::NetQuicConnect),
607        fb::Capability::NetQuicRead => Ok(Capability::NetQuicRead),
608        fb::Capability::NetQuicWrite => Ok(Capability::NetQuicWrite),
609        fb::Capability::NetHttpBind => Ok(Capability::NetHttpBind),
610        fb::Capability::NetHttpAccept => Ok(Capability::NetHttpAccept),
611        fb::Capability::NetHttpConnect => Ok(Capability::NetHttpConnect),
612        fb::Capability::NetHttpRead => Ok(Capability::NetHttpRead),
613        fb::Capability::NetHttpWrite => Ok(Capability::NetHttpWrite),
614        fb::Capability::NetTlsServerConfig => Ok(Capability::NetTlsServerConfig),
615        fb::Capability::NetTlsClientConfig => Ok(Capability::NetTlsClientConfig),
616        fb::Capability::SingletonRegistry => Ok(Capability::SingletonRegistry),
617        fb::Capability::SingletonLookup => Ok(Capability::SingletonLookup),
618        fb::Capability::TimeRead => Ok(Capability::TimeRead),
619        _ => Err(ProtocolError::UnknownCapability),
620    }
621}
622
623fn encode_abi_signature<'bldr>(
624    builder: &mut FlatBufferBuilder<'bldr>,
625    signature: &AbiSignature,
626) -> flatbuffers::WIPOffset<fb::AbiSignature<'bldr>> {
627    let params = encode_abi_params(builder, signature.params());
628    let results = encode_abi_params(builder, signature.results());
629
630    fb::AbiSignature::create(
631        builder,
632        &fb::AbiSignatureArgs {
633            params: Some(params),
634            results: Some(results),
635        },
636    )
637}
638
639fn decode_abi_signature(signature: fb::AbiSignature<'_>) -> Result<AbiSignature, ProtocolError> {
640    let params = decode_abi_params(signature.params())?;
641    let results = decode_abi_params(signature.results())?;
642    Ok(AbiSignature::new(params, results))
643}
644
645fn encode_abi_params<'bldr>(
646    builder: &mut FlatBufferBuilder<'bldr>,
647    params: &[AbiParam],
648) -> flatbuffers::WIPOffset<
649    flatbuffers::Vector<'bldr, flatbuffers::ForwardsUOffset<fb::AbiParam<'bldr>>>,
650> {
651    let items: Vec<_> = params
652        .iter()
653        .map(|param| encode_abi_param(builder, param))
654        .collect();
655    builder.create_vector(&items)
656}
657
658fn decode_abi_params(
659    params: Option<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<fb::AbiParam<'_>>>>,
660) -> Result<Vec<AbiParam>, ProtocolError> {
661    let mut out = Vec::new();
662    if let Some(vec) = params {
663        for param in vec {
664            out.push(decode_abi_param(param)?);
665        }
666    }
667    Ok(out)
668}
669
670fn encode_abi_param<'bldr>(
671    builder: &mut FlatBufferBuilder<'bldr>,
672    param: &AbiParam,
673) -> flatbuffers::WIPOffset<fb::AbiParam<'bldr>> {
674    let (kind, scalar_type) = match param {
675        AbiParam::Scalar(scalar) => (fb::AbiParamKind::Scalar, encode_abi_scalar_type(*scalar)),
676        AbiParam::Buffer => (fb::AbiParamKind::Buffer, fb::AbiScalarType::I8),
677    };
678
679    fb::AbiParam::create(builder, &fb::AbiParamArgs { kind, scalar_type })
680}
681
682fn decode_abi_param(param: fb::AbiParam<'_>) -> Result<AbiParam, ProtocolError> {
683    match param.kind() {
684        fb::AbiParamKind::Scalar => {
685            let scalar = decode_abi_scalar_type(param.scalar_type())?;
686            Ok(AbiParam::Scalar(scalar))
687        }
688        fb::AbiParamKind::Buffer => Ok(AbiParam::Buffer),
689        _ => Err(ProtocolError::UnknownAbiParamKind),
690    }
691}
692
693fn encode_entrypoint_args<'bldr>(
694    builder: &mut FlatBufferBuilder<'bldr>,
695    args: &[EntrypointArg],
696) -> flatbuffers::WIPOffset<
697    flatbuffers::Vector<'bldr, flatbuffers::ForwardsUOffset<fb::EntrypointArg<'bldr>>>,
698> {
699    let items: Vec<_> = args
700        .iter()
701        .map(|arg| encode_entrypoint_arg(builder, arg))
702        .collect();
703    builder.create_vector(&items)
704}
705
706fn decode_entrypoint_args(
707    args: Option<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<fb::EntrypointArg<'_>>>>,
708) -> Result<Vec<EntrypointArg>, ProtocolError> {
709    let mut out = Vec::new();
710    if let Some(vec) = args {
711        for arg in vec {
712            out.push(decode_entrypoint_arg(arg)?);
713        }
714    }
715    Ok(out)
716}
717
718fn encode_entrypoint_arg<'bldr>(
719    builder: &mut FlatBufferBuilder<'bldr>,
720    arg: &EntrypointArg,
721) -> flatbuffers::WIPOffset<fb::EntrypointArg<'bldr>> {
722    match arg {
723        EntrypointArg::Scalar(value) => {
724            let scalar = encode_scalar_value(builder, value);
725            fb::EntrypointArg::create(
726                builder,
727                &fb::EntrypointArgArgs {
728                    kind: fb::EntrypointArgKind::Scalar,
729                    scalar: Some(scalar),
730                    buffer: None,
731                    resource: 0,
732                },
733            )
734        }
735        EntrypointArg::Buffer(bytes) => {
736            let buffer = builder.create_vector(bytes);
737            fb::EntrypointArg::create(
738                builder,
739                &fb::EntrypointArgArgs {
740                    kind: fb::EntrypointArgKind::Buffer,
741                    scalar: None,
742                    buffer: Some(buffer),
743                    resource: 0,
744                },
745            )
746        }
747        EntrypointArg::Resource(handle) => fb::EntrypointArg::create(
748            builder,
749            &fb::EntrypointArgArgs {
750                kind: fb::EntrypointArgKind::Resource,
751                scalar: None,
752                buffer: None,
753                resource: *handle,
754            },
755        ),
756    }
757}
758
759fn decode_entrypoint_arg(arg: fb::EntrypointArg<'_>) -> Result<EntrypointArg, ProtocolError> {
760    match arg.kind() {
761        fb::EntrypointArgKind::Scalar => {
762            let scalar = arg
763                .scalar()
764                .ok_or(ProtocolError::MissingField("entrypoint_arg.scalar"))?;
765            Ok(EntrypointArg::Scalar(decode_scalar_value(scalar)?))
766        }
767        fb::EntrypointArgKind::Buffer => {
768            let payload = arg
769                .buffer()
770                .map(|buf| buf.iter().collect())
771                .unwrap_or_default();
772            Ok(EntrypointArg::Buffer(payload))
773        }
774        fb::EntrypointArgKind::Resource => Ok(EntrypointArg::Resource(arg.resource())),
775        _ => Err(ProtocolError::UnknownEntrypointArgKind),
776    }
777}
778
779fn encode_scalar_value<'bldr>(
780    builder: &mut FlatBufferBuilder<'bldr>,
781    value: &AbiScalarValue,
782) -> flatbuffers::WIPOffset<fb::ScalarValue<'bldr>> {
783    let (kind, bits) = scalar_bits(value);
784    fb::ScalarValue::create(builder, &fb::ScalarValueArgs { kind, bits })
785}
786
787fn decode_scalar_value(value: fb::ScalarValue<'_>) -> Result<AbiScalarValue, ProtocolError> {
788    let kind = decode_abi_scalar_type(value.kind())?;
789    let bits = value.bits();
790    let bytes = bits.to_le_bytes();
791    let scalar = match kind {
792        AbiScalarType::I8 => AbiScalarValue::I8(i8::from_le_bytes([bytes[0]])),
793        AbiScalarType::U8 => AbiScalarValue::U8(bytes[0]),
794        AbiScalarType::I16 => AbiScalarValue::I16(i16::from_le_bytes([bytes[0], bytes[1]])),
795        AbiScalarType::U16 => AbiScalarValue::U16(u16::from_le_bytes([bytes[0], bytes[1]])),
796        AbiScalarType::I32 => {
797            AbiScalarValue::I32(i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
798        }
799        AbiScalarType::U32 => {
800            AbiScalarValue::U32(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
801        }
802        AbiScalarType::I64 => AbiScalarValue::I64(i64::from_le_bytes(bytes)),
803        AbiScalarType::U64 => AbiScalarValue::U64(bits),
804        AbiScalarType::F32 => AbiScalarValue::F32(f32::from_bits(u32::from_le_bytes([
805            bytes[0], bytes[1], bytes[2], bytes[3],
806        ]))),
807        AbiScalarType::F64 => AbiScalarValue::F64(f64::from_bits(bits)),
808    };
809    Ok(scalar)
810}
811
812fn scalar_bits(value: &AbiScalarValue) -> (fb::AbiScalarType, u64) {
813    match value {
814        AbiScalarValue::I8(v) => (
815            fb::AbiScalarType::I8,
816            u64::from_le_bytes(i64::from(*v).to_le_bytes()),
817        ),
818        AbiScalarValue::U8(v) => (fb::AbiScalarType::U8, u64::from(*v)),
819        AbiScalarValue::I16(v) => (
820            fb::AbiScalarType::I16,
821            u64::from_le_bytes(i64::from(*v).to_le_bytes()),
822        ),
823        AbiScalarValue::U16(v) => (fb::AbiScalarType::U16, u64::from(*v)),
824        AbiScalarValue::I32(v) => (
825            fb::AbiScalarType::I32,
826            u64::from_le_bytes(i64::from(*v).to_le_bytes()),
827        ),
828        AbiScalarValue::U32(v) => (fb::AbiScalarType::U32, u64::from(*v)),
829        AbiScalarValue::I64(v) => (fb::AbiScalarType::I64, u64::from_le_bytes(v.to_le_bytes())),
830        AbiScalarValue::U64(v) => (fb::AbiScalarType::U64, *v),
831        AbiScalarValue::F32(v) => (fb::AbiScalarType::F32, u64::from(v.to_bits())),
832        AbiScalarValue::F64(v) => (fb::AbiScalarType::F64, v.to_bits()),
833    }
834}
835
836fn encode_abi_scalar_type(value: AbiScalarType) -> fb::AbiScalarType {
837    match value {
838        AbiScalarType::I8 => fb::AbiScalarType::I8,
839        AbiScalarType::U8 => fb::AbiScalarType::U8,
840        AbiScalarType::I16 => fb::AbiScalarType::I16,
841        AbiScalarType::U16 => fb::AbiScalarType::U16,
842        AbiScalarType::I32 => fb::AbiScalarType::I32,
843        AbiScalarType::U32 => fb::AbiScalarType::U32,
844        AbiScalarType::I64 => fb::AbiScalarType::I64,
845        AbiScalarType::U64 => fb::AbiScalarType::U64,
846        AbiScalarType::F32 => fb::AbiScalarType::F32,
847        AbiScalarType::F64 => fb::AbiScalarType::F64,
848    }
849}
850
851fn decode_abi_scalar_type(value: fb::AbiScalarType) -> Result<AbiScalarType, ProtocolError> {
852    match value {
853        fb::AbiScalarType::I8 => Ok(AbiScalarType::I8),
854        fb::AbiScalarType::U8 => Ok(AbiScalarType::U8),
855        fb::AbiScalarType::I16 => Ok(AbiScalarType::I16),
856        fb::AbiScalarType::U16 => Ok(AbiScalarType::U16),
857        fb::AbiScalarType::I32 => Ok(AbiScalarType::I32),
858        fb::AbiScalarType::U32 => Ok(AbiScalarType::U32),
859        fb::AbiScalarType::I64 => Ok(AbiScalarType::I64),
860        fb::AbiScalarType::U64 => Ok(AbiScalarType::U64),
861        fb::AbiScalarType::F32 => Ok(AbiScalarType::F32),
862        fb::AbiScalarType::F64 => Ok(AbiScalarType::F64),
863        _ => Err(ProtocolError::UnknownAbiScalarType),
864    }
865}
866
867fn encode_io_frame<'bldr>(
868    builder: &mut FlatBufferBuilder<'bldr>,
869    frame: &IoFrame,
870) -> flatbuffers::WIPOffset<fb::IoFrame<'bldr>> {
871    let payload = builder.create_vector(&frame.payload);
872    fb::IoFrame::create(
873        builder,
874        &fb::IoFrameArgs {
875            writer_id: frame.writer_id,
876            payload: Some(payload),
877        },
878    )
879}
880
881fn decode_io_frame(frame: fb::IoFrame<'_>) -> Result<IoFrame, ProtocolError> {
882    let payload = frame
883        .payload()
884        .map(|buf| buf.iter().collect())
885        .unwrap_or_default();
886    Ok(IoFrame {
887        writer_id: frame.writer_id(),
888        payload,
889    })
890}