Skip to main content

agentos_sidecar_protocol/
protocol.rs

1use crate::generated_protocol::v1 as generated_protocol;
2use serde::de::{self, SeqAccess, Visitor};
3use serde::ser::SerializeTuple;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::Value;
6use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
7use std::error::Error;
8use std::fmt;
9
10pub use crate::wire::{OwnershipRequirement, ProtocolCodecError, RequestDirection};
11
12pub const PROTOCOL_NAME: &str = crate::wire::PROTOCOL_NAME;
13pub const PROTOCOL_VERSION: u16 = crate::wire::PROTOCOL_VERSION;
14pub const DEFAULT_MAX_FRAME_BYTES: usize = crate::wire::DEFAULT_MAX_FRAME_BYTES;
15pub const DEFAULT_COMPLETED_RESPONSE_CAP: usize = 10_000;
16pub type RequestId = crate::wire::RequestId;
17pub type ExtEnvelope = crate::wire::ExtEnvelope;
18
19fn serialize_bare_newtype_tag<S, T>(serializer: S, tag: u64, payload: &T) -> Result<S::Ok, S::Error>
20where
21    S: Serializer,
22    T: Serialize,
23{
24    let mut tuple = serializer.serialize_tuple(2)?;
25    tuple.serialize_element(&serde_bare::Uint(tag))?;
26    tuple.serialize_element(payload)?;
27    tuple.end()
28}
29
30/// Convert the compatibility protocol frame into the generated wire frame.
31pub fn to_generated_protocol_frame(
32    frame: &ProtocolFrame,
33) -> Result<generated_protocol::ProtocolFrame, ProtocolCodecError> {
34    Ok(match frame {
35        ProtocolFrame::Request(frame) => {
36            generated_protocol::ProtocolFrame::RequestFrame(generated_protocol::RequestFrame {
37                schema: to_generated_protocol_schema(&frame.schema),
38                request_id: frame.request_id,
39                ownership: to_generated_ownership_scope(&frame.ownership),
40                payload: to_generated_request_payload(&frame.payload)?,
41            })
42        }
43        ProtocolFrame::Response(frame) => {
44            generated_protocol::ProtocolFrame::ResponseFrame(generated_protocol::ResponseFrame {
45                schema: to_generated_protocol_schema(&frame.schema),
46                request_id: frame.request_id,
47                ownership: to_generated_ownership_scope(&frame.ownership),
48                payload: to_generated_response_payload(&frame.payload)?,
49            })
50        }
51        ProtocolFrame::Event(frame) => {
52            generated_protocol::ProtocolFrame::EventFrame(generated_protocol::EventFrame {
53                schema: to_generated_protocol_schema(&frame.schema),
54                ownership: to_generated_ownership_scope(&frame.ownership),
55                payload: to_generated_event_payload(&frame.payload),
56            })
57        }
58        ProtocolFrame::SidecarRequest(frame) => {
59            generated_protocol::ProtocolFrame::SidecarRequestFrame(
60                generated_protocol::SidecarRequestFrame {
61                    schema: to_generated_protocol_schema(&frame.schema),
62                    request_id: frame.request_id,
63                    ownership: to_generated_ownership_scope(&frame.ownership),
64                    payload: to_generated_sidecar_request_payload(&frame.payload)?,
65                },
66            )
67        }
68        ProtocolFrame::SidecarResponse(frame) => {
69            generated_protocol::ProtocolFrame::SidecarResponseFrame(
70                generated_protocol::SidecarResponseFrame {
71                    schema: to_generated_protocol_schema(&frame.schema),
72                    request_id: frame.request_id,
73                    ownership: to_generated_ownership_scope(&frame.ownership),
74                    payload: to_generated_sidecar_response_payload(&frame.payload)?,
75                },
76            )
77        }
78        ProtocolFrame::Control(frame) => {
79            generated_protocol::ProtocolFrame::ControlFrame(frame.clone())
80        }
81    })
82}
83
84/// Convert the generated wire frame into the compatibility protocol frame.
85pub fn from_generated_protocol_frame(
86    frame: generated_protocol::ProtocolFrame,
87) -> Result<ProtocolFrame, ProtocolCodecError> {
88    Ok(match frame {
89        generated_protocol::ProtocolFrame::RequestFrame(frame) => {
90            ProtocolFrame::Request(RequestFrame {
91                schema: from_generated_protocol_schema(frame.schema),
92                request_id: frame.request_id,
93                ownership: from_generated_ownership_scope(frame.ownership),
94                payload: from_generated_request_payload(frame.payload)?,
95            })
96        }
97        generated_protocol::ProtocolFrame::ResponseFrame(frame) => {
98            ProtocolFrame::Response(ResponseFrame {
99                schema: from_generated_protocol_schema(frame.schema),
100                request_id: frame.request_id,
101                ownership: from_generated_ownership_scope(frame.ownership),
102                payload: from_generated_response_payload(frame.payload)?,
103            })
104        }
105        generated_protocol::ProtocolFrame::EventFrame(frame) => ProtocolFrame::Event(EventFrame {
106            schema: from_generated_protocol_schema(frame.schema),
107            ownership: from_generated_ownership_scope(frame.ownership),
108            payload: from_generated_event_payload(frame.payload),
109        }),
110        generated_protocol::ProtocolFrame::SidecarRequestFrame(frame) => {
111            ProtocolFrame::SidecarRequest(SidecarRequestFrame {
112                schema: from_generated_protocol_schema(frame.schema),
113                request_id: frame.request_id,
114                ownership: from_generated_ownership_scope(frame.ownership),
115                payload: from_generated_sidecar_request_payload(frame.payload)?,
116            })
117        }
118        generated_protocol::ProtocolFrame::SidecarResponseFrame(frame) => {
119            ProtocolFrame::SidecarResponse(SidecarResponseFrame {
120                schema: from_generated_protocol_schema(frame.schema),
121                request_id: frame.request_id,
122                ownership: from_generated_ownership_scope(frame.ownership),
123                payload: from_generated_sidecar_response_payload(frame.payload)?,
124            })
125        }
126        generated_protocol::ProtocolFrame::ControlFrame(frame) => ProtocolFrame::Control(frame),
127    })
128}
129
130fn to_generated_protocol_schema(schema: &ProtocolSchema) -> generated_protocol::ProtocolSchema {
131    schema.clone()
132}
133
134fn from_generated_protocol_schema(schema: generated_protocol::ProtocolSchema) -> ProtocolSchema {
135    schema
136}
137
138// `OwnershipScope` is now an alias for the generated `crate::wire::OwnershipScope`, so the
139// compat<->generated converters are identity functions. They are retained so the JSON-carrying
140// frame-conversion chain (still hand-written, out of scope for this pass) keeps compiling
141// without site-by-site rewiring.
142pub(crate) fn to_generated_ownership_scope(
143    ownership: &OwnershipScope,
144) -> generated_protocol::OwnershipScope {
145    ownership.clone()
146}
147
148pub(crate) fn from_generated_ownership_scope(
149    ownership: generated_protocol::OwnershipScope,
150) -> OwnershipScope {
151    ownership
152}
153
154fn to_generated_dispose_reason(reason: &DisposeReason) -> generated_protocol::DisposeReason {
155    match reason {
156        DisposeReason::Requested => generated_protocol::DisposeReason::Requested,
157        DisposeReason::ConnectionClosed => generated_protocol::DisposeReason::ConnectionClosed,
158        DisposeReason::HostShutdown => generated_protocol::DisposeReason::HostShutdown,
159    }
160}
161
162fn from_generated_dispose_reason(reason: generated_protocol::DisposeReason) -> DisposeReason {
163    match reason {
164        generated_protocol::DisposeReason::Requested => DisposeReason::Requested,
165        generated_protocol::DisposeReason::ConnectionClosed => DisposeReason::ConnectionClosed,
166        generated_protocol::DisposeReason::HostShutdown => DisposeReason::HostShutdown,
167    }
168}
169
170fn to_generated_filesystem_operation(
171    operation: &FilesystemOperation,
172) -> generated_protocol::FilesystemOperation {
173    match operation {
174        FilesystemOperation::Read => generated_protocol::FilesystemOperation::Read,
175        FilesystemOperation::Write => generated_protocol::FilesystemOperation::Write,
176        FilesystemOperation::Stat => generated_protocol::FilesystemOperation::Stat,
177        FilesystemOperation::ReadDir => generated_protocol::FilesystemOperation::ReadDir,
178        FilesystemOperation::Mkdir => generated_protocol::FilesystemOperation::Mkdir,
179        FilesystemOperation::Remove => generated_protocol::FilesystemOperation::Remove,
180        FilesystemOperation::Rename => generated_protocol::FilesystemOperation::Rename,
181    }
182}
183
184fn from_generated_filesystem_operation(
185    operation: generated_protocol::FilesystemOperation,
186) -> FilesystemOperation {
187    match operation {
188        generated_protocol::FilesystemOperation::Read => FilesystemOperation::Read,
189        generated_protocol::FilesystemOperation::Write => FilesystemOperation::Write,
190        generated_protocol::FilesystemOperation::Stat => FilesystemOperation::Stat,
191        generated_protocol::FilesystemOperation::ReadDir => FilesystemOperation::ReadDir,
192        generated_protocol::FilesystemOperation::Mkdir => FilesystemOperation::Mkdir,
193        generated_protocol::FilesystemOperation::Remove => FilesystemOperation::Remove,
194        generated_protocol::FilesystemOperation::Rename => FilesystemOperation::Rename,
195    }
196}
197
198fn to_generated_guest_filesystem_operation(
199    operation: &GuestFilesystemOperation,
200) -> generated_protocol::GuestFilesystemOperation {
201    match operation {
202        GuestFilesystemOperation::ReadFile => {
203            generated_protocol::GuestFilesystemOperation::ReadFile
204        }
205        GuestFilesystemOperation::WriteFile => {
206            generated_protocol::GuestFilesystemOperation::WriteFile
207        }
208        GuestFilesystemOperation::CreateDir => {
209            generated_protocol::GuestFilesystemOperation::CreateDir
210        }
211        GuestFilesystemOperation::Mkdir => generated_protocol::GuestFilesystemOperation::Mkdir,
212        GuestFilesystemOperation::Exists => generated_protocol::GuestFilesystemOperation::Exists,
213        GuestFilesystemOperation::Stat => generated_protocol::GuestFilesystemOperation::Stat,
214        GuestFilesystemOperation::Lstat => generated_protocol::GuestFilesystemOperation::Lstat,
215        GuestFilesystemOperation::ReadDir => generated_protocol::GuestFilesystemOperation::ReadDir,
216        GuestFilesystemOperation::ReadDirRecursive => {
217            generated_protocol::GuestFilesystemOperation::ReadDirRecursive
218        }
219        GuestFilesystemOperation::RemoveFile => {
220            generated_protocol::GuestFilesystemOperation::RemoveFile
221        }
222        GuestFilesystemOperation::RemoveDir => {
223            generated_protocol::GuestFilesystemOperation::RemoveDir
224        }
225        GuestFilesystemOperation::Remove => generated_protocol::GuestFilesystemOperation::Remove,
226        GuestFilesystemOperation::Copy => generated_protocol::GuestFilesystemOperation::Copy,
227        GuestFilesystemOperation::Move => generated_protocol::GuestFilesystemOperation::Move,
228        GuestFilesystemOperation::Rename => generated_protocol::GuestFilesystemOperation::Rename,
229        GuestFilesystemOperation::Realpath => {
230            generated_protocol::GuestFilesystemOperation::Realpath
231        }
232        GuestFilesystemOperation::Symlink => generated_protocol::GuestFilesystemOperation::Symlink,
233        GuestFilesystemOperation::ReadLink => {
234            generated_protocol::GuestFilesystemOperation::ReadLink
235        }
236        GuestFilesystemOperation::Link => generated_protocol::GuestFilesystemOperation::Link,
237        GuestFilesystemOperation::Chmod => generated_protocol::GuestFilesystemOperation::Chmod,
238        GuestFilesystemOperation::Chown => generated_protocol::GuestFilesystemOperation::Chown,
239        GuestFilesystemOperation::Utimes => generated_protocol::GuestFilesystemOperation::Utimes,
240        GuestFilesystemOperation::Truncate => {
241            generated_protocol::GuestFilesystemOperation::Truncate
242        }
243        GuestFilesystemOperation::Pread => generated_protocol::GuestFilesystemOperation::Pread,
244        GuestFilesystemOperation::Pwrite => generated_protocol::GuestFilesystemOperation::Pwrite,
245    }
246}
247
248fn from_generated_guest_filesystem_operation(
249    operation: generated_protocol::GuestFilesystemOperation,
250) -> GuestFilesystemOperation {
251    match operation {
252        generated_protocol::GuestFilesystemOperation::ReadFile => {
253            GuestFilesystemOperation::ReadFile
254        }
255        generated_protocol::GuestFilesystemOperation::WriteFile => {
256            GuestFilesystemOperation::WriteFile
257        }
258        generated_protocol::GuestFilesystemOperation::CreateDir => {
259            GuestFilesystemOperation::CreateDir
260        }
261        generated_protocol::GuestFilesystemOperation::Mkdir => GuestFilesystemOperation::Mkdir,
262        generated_protocol::GuestFilesystemOperation::Exists => GuestFilesystemOperation::Exists,
263        generated_protocol::GuestFilesystemOperation::Stat => GuestFilesystemOperation::Stat,
264        generated_protocol::GuestFilesystemOperation::Lstat => GuestFilesystemOperation::Lstat,
265        generated_protocol::GuestFilesystemOperation::ReadDir => GuestFilesystemOperation::ReadDir,
266        generated_protocol::GuestFilesystemOperation::ReadDirRecursive => {
267            GuestFilesystemOperation::ReadDirRecursive
268        }
269        generated_protocol::GuestFilesystemOperation::RemoveFile => {
270            GuestFilesystemOperation::RemoveFile
271        }
272        generated_protocol::GuestFilesystemOperation::RemoveDir => {
273            GuestFilesystemOperation::RemoveDir
274        }
275        generated_protocol::GuestFilesystemOperation::Remove => GuestFilesystemOperation::Remove,
276        generated_protocol::GuestFilesystemOperation::Copy => GuestFilesystemOperation::Copy,
277        generated_protocol::GuestFilesystemOperation::Move => GuestFilesystemOperation::Move,
278        generated_protocol::GuestFilesystemOperation::Rename => GuestFilesystemOperation::Rename,
279        generated_protocol::GuestFilesystemOperation::Realpath => {
280            GuestFilesystemOperation::Realpath
281        }
282        generated_protocol::GuestFilesystemOperation::Symlink => GuestFilesystemOperation::Symlink,
283        generated_protocol::GuestFilesystemOperation::ReadLink => {
284            GuestFilesystemOperation::ReadLink
285        }
286        generated_protocol::GuestFilesystemOperation::Link => GuestFilesystemOperation::Link,
287        generated_protocol::GuestFilesystemOperation::Chmod => GuestFilesystemOperation::Chmod,
288        generated_protocol::GuestFilesystemOperation::Chown => GuestFilesystemOperation::Chown,
289        generated_protocol::GuestFilesystemOperation::Utimes => GuestFilesystemOperation::Utimes,
290        generated_protocol::GuestFilesystemOperation::Truncate => {
291            GuestFilesystemOperation::Truncate
292        }
293        generated_protocol::GuestFilesystemOperation::Pread => GuestFilesystemOperation::Pread,
294        generated_protocol::GuestFilesystemOperation::Pwrite => GuestFilesystemOperation::Pwrite,
295    }
296}
297
298fn to_generated_permission_mode(mode: &PermissionMode) -> generated_protocol::PermissionMode {
299    mode.clone()
300}
301
302fn from_generated_permission_mode(mode: generated_protocol::PermissionMode) -> PermissionMode {
303    mode
304}
305
306fn to_generated_root_filesystem_entry_encoding(
307    encoding: &RootFilesystemEntryEncoding,
308) -> generated_protocol::RootFilesystemEntryEncoding {
309    match encoding {
310        RootFilesystemEntryEncoding::Utf8 => generated_protocol::RootFilesystemEntryEncoding::Utf8,
311        RootFilesystemEntryEncoding::Base64 => {
312            generated_protocol::RootFilesystemEntryEncoding::Base64
313        }
314    }
315}
316
317fn from_generated_root_filesystem_entry_encoding(
318    encoding: generated_protocol::RootFilesystemEntryEncoding,
319) -> RootFilesystemEntryEncoding {
320    match encoding {
321        generated_protocol::RootFilesystemEntryEncoding::Utf8 => RootFilesystemEntryEncoding::Utf8,
322        generated_protocol::RootFilesystemEntryEncoding::Base64 => {
323            RootFilesystemEntryEncoding::Base64
324        }
325    }
326}
327
328fn to_generated_stream_channel(channel: &StreamChannel) -> generated_protocol::StreamChannel {
329    match channel {
330        StreamChannel::Stdout => generated_protocol::StreamChannel::Stdout,
331        StreamChannel::Stderr => generated_protocol::StreamChannel::Stderr,
332    }
333}
334
335fn from_generated_stream_channel(channel: generated_protocol::StreamChannel) -> StreamChannel {
336    match channel {
337        generated_protocol::StreamChannel::Stdout => StreamChannel::Stdout,
338        generated_protocol::StreamChannel::Stderr => StreamChannel::Stderr,
339    }
340}
341
342fn to_generated_vm_lifecycle_state(
343    state: &VmLifecycleState,
344) -> generated_protocol::VmLifecycleState {
345    match state {
346        VmLifecycleState::Creating => generated_protocol::VmLifecycleState::Creating,
347        VmLifecycleState::Ready => generated_protocol::VmLifecycleState::Ready,
348        VmLifecycleState::Disposing => generated_protocol::VmLifecycleState::Disposing,
349        VmLifecycleState::Disposed => generated_protocol::VmLifecycleState::Disposed,
350        VmLifecycleState::Failed => generated_protocol::VmLifecycleState::Failed,
351    }
352}
353
354fn from_generated_vm_lifecycle_state(
355    state: generated_protocol::VmLifecycleState,
356) -> VmLifecycleState {
357    match state {
358        generated_protocol::VmLifecycleState::Creating => VmLifecycleState::Creating,
359        generated_protocol::VmLifecycleState::Ready => VmLifecycleState::Ready,
360        generated_protocol::VmLifecycleState::Disposing => VmLifecycleState::Disposing,
361        generated_protocol::VmLifecycleState::Disposed => VmLifecycleState::Disposed,
362        generated_protocol::VmLifecycleState::Failed => VmLifecycleState::Failed,
363    }
364}
365
366fn to_generated_guest_filesystem_stat(
367    stat: &GuestFilesystemStat,
368) -> generated_protocol::GuestFilesystemStat {
369    stat.clone()
370}
371
372fn from_generated_guest_filesystem_stat(
373    stat: generated_protocol::GuestFilesystemStat,
374) -> GuestFilesystemStat {
375    stat
376}
377
378fn to_generated_process_snapshot_entry(
379    entry: &ProcessSnapshotEntry,
380) -> generated_protocol::ProcessSnapshotEntry {
381    entry.clone()
382}
383
384fn from_generated_process_snapshot_entry(
385    entry: generated_protocol::ProcessSnapshotEntry,
386) -> ProcessSnapshotEntry {
387    entry
388}
389
390fn to_generated_ext_envelope(envelope: &ExtEnvelope) -> generated_protocol::ExtEnvelope {
391    envelope.clone()
392}
393
394fn from_generated_ext_envelope(envelope: generated_protocol::ExtEnvelope) -> ExtEnvelope {
395    envelope
396}
397
398fn to_generated_request_payload(
399    payload: &RequestPayload,
400) -> Result<generated_protocol::RequestPayload, ProtocolCodecError> {
401    Ok(match payload {
402        RequestPayload::Authenticate(inner) => {
403            generated_protocol::RequestPayload::AuthenticateRequest(inner.clone())
404        }
405        RequestPayload::OpenSession(inner) => {
406            generated_protocol::RequestPayload::OpenSessionRequest(inner.clone())
407        }
408        RequestPayload::CreateVm(inner) => {
409            generated_protocol::RequestPayload::CreateVmRequest(inner.clone())
410        }
411        RequestPayload::DisposeVm(inner) => generated_protocol::RequestPayload::DisposeVmRequest(
412            generated_protocol::DisposeVmRequest {
413                reason: to_generated_dispose_reason(&inner.reason),
414            },
415        ),
416        RequestPayload::BootstrapRootFilesystem(inner) => {
417            generated_protocol::RequestPayload::BootstrapRootFilesystemRequest(inner.clone())
418        }
419        RequestPayload::ConfigureVm(inner) => {
420            generated_protocol::RequestPayload::ConfigureVmRequest(inner.clone())
421        }
422        RequestPayload::RegisterHostCallbacks(inner) => {
423            generated_protocol::RequestPayload::RegisterHostCallbacksRequest(inner.clone())
424        }
425        RequestPayload::CreateLayer(_) => generated_protocol::RequestPayload::CreateLayerRequest,
426        RequestPayload::SealLayer(inner) => {
427            generated_protocol::RequestPayload::SealLayerRequest(inner.clone())
428        }
429        RequestPayload::ImportSnapshot(inner) => {
430            generated_protocol::RequestPayload::ImportSnapshotRequest(inner.clone())
431        }
432        RequestPayload::ExportSnapshot(inner) => {
433            generated_protocol::RequestPayload::ExportSnapshotRequest(inner.clone())
434        }
435        RequestPayload::CreateOverlay(inner) => {
436            generated_protocol::RequestPayload::CreateOverlayRequest(inner.clone())
437        }
438        RequestPayload::GuestFilesystemCall(inner) => {
439            generated_protocol::RequestPayload::GuestFilesystemCallRequest(inner.clone())
440        }
441        RequestPayload::SnapshotRootFilesystem(inner) => {
442            generated_protocol::RequestPayload::SnapshotRootFilesystemRequest(inner.clone())
443        }
444        RequestPayload::ListMounts(_) => generated_protocol::RequestPayload::ListMountsRequest,
445        RequestPayload::Execute(inner) => {
446            generated_protocol::RequestPayload::ExecuteRequest(inner.clone())
447        }
448        RequestPayload::WriteStdin(inner) => {
449            generated_protocol::RequestPayload::WriteStdinRequest(inner.clone())
450        }
451        RequestPayload::CloseStdin(inner) => {
452            generated_protocol::RequestPayload::CloseStdinRequest(inner.clone())
453        }
454        RequestPayload::KillProcess(inner) => {
455            generated_protocol::RequestPayload::KillProcessRequest(inner.clone())
456        }
457        RequestPayload::GetProcessSnapshot(_) => {
458            generated_protocol::RequestPayload::GetProcessSnapshotRequest
459        }
460        RequestPayload::GetResourceSnapshot(_) => {
461            generated_protocol::RequestPayload::GetResourceSnapshotRequest
462        }
463        RequestPayload::FindListener(inner) => {
464            generated_protocol::RequestPayload::FindListenerRequest(inner.clone())
465        }
466        RequestPayload::FindBoundUdp(inner) => {
467            generated_protocol::RequestPayload::FindBoundUdpRequest(inner.clone())
468        }
469        RequestPayload::VmFetch(inner) => {
470            generated_protocol::RequestPayload::VmFetchRequest(inner.clone())
471        }
472        RequestPayload::GetSignalState(inner) => {
473            generated_protocol::RequestPayload::GetSignalStateRequest(inner.clone())
474        }
475        RequestPayload::GetZombieTimerCount(_) => {
476            generated_protocol::RequestPayload::GetZombieTimerCountRequest
477        }
478        RequestPayload::HostFilesystemCall(inner) => {
479            generated_protocol::RequestPayload::HostFilesystemCallRequest(
480                generated_protocol::HostFilesystemCallRequest {
481                    operation: to_generated_filesystem_operation(&inner.operation),
482                    path: inner.path.clone(),
483                    payload_size_bytes: inner.payload_size_bytes,
484                },
485            )
486        }
487        RequestPayload::PersistenceLoad(inner) => {
488            generated_protocol::RequestPayload::PersistenceLoadRequest(inner.clone())
489        }
490        RequestPayload::PersistenceFlush(inner) => {
491            generated_protocol::RequestPayload::PersistenceFlushRequest(inner.clone())
492        }
493        RequestPayload::Ext(inner) => {
494            generated_protocol::RequestPayload::ExtEnvelope(to_generated_ext_envelope(inner))
495        }
496        RequestPayload::GuestKernelCall(inner) => {
497            generated_protocol::RequestPayload::GuestKernelCallRequest(inner.clone())
498        }
499        RequestPayload::ResizePty(inner) => {
500            generated_protocol::RequestPayload::ResizePtyRequest(inner.clone())
501        }
502        RequestPayload::LinkPackage(inner) => {
503            generated_protocol::RequestPayload::LinkPackageRequest(inner.clone())
504        }
505        RequestPayload::ProvidedCommands(_) => {
506            generated_protocol::RequestPayload::ProvidedCommandsRequest
507        }
508    })
509}
510
511fn from_generated_request_payload(
512    payload: generated_protocol::RequestPayload,
513) -> Result<RequestPayload, ProtocolCodecError> {
514    Ok(match payload {
515        generated_protocol::RequestPayload::AuthenticateRequest(inner) => {
516            RequestPayload::Authenticate(inner)
517        }
518        generated_protocol::RequestPayload::OpenSessionRequest(inner) => {
519            RequestPayload::OpenSession(inner)
520        }
521        generated_protocol::RequestPayload::CreateVmRequest(inner) => {
522            RequestPayload::CreateVm(inner)
523        }
524        generated_protocol::RequestPayload::DisposeVmRequest(inner) => {
525            RequestPayload::DisposeVm(DisposeVmRequest {
526                reason: from_generated_dispose_reason(inner.reason),
527            })
528        }
529        generated_protocol::RequestPayload::BootstrapRootFilesystemRequest(inner) => {
530            RequestPayload::BootstrapRootFilesystem(inner)
531        }
532        generated_protocol::RequestPayload::ConfigureVmRequest(inner) => {
533            RequestPayload::ConfigureVm(inner)
534        }
535        generated_protocol::RequestPayload::RegisterHostCallbacksRequest(inner) => {
536            RequestPayload::RegisterHostCallbacks(inner)
537        }
538        generated_protocol::RequestPayload::CreateLayerRequest => {
539            RequestPayload::CreateLayer(CreateLayerRequest {})
540        }
541        generated_protocol::RequestPayload::SealLayerRequest(inner) => {
542            RequestPayload::SealLayer(inner)
543        }
544        generated_protocol::RequestPayload::ImportSnapshotRequest(inner) => {
545            RequestPayload::ImportSnapshot(inner)
546        }
547        generated_protocol::RequestPayload::ExportSnapshotRequest(inner) => {
548            RequestPayload::ExportSnapshot(inner)
549        }
550        generated_protocol::RequestPayload::CreateOverlayRequest(inner) => {
551            RequestPayload::CreateOverlay(inner)
552        }
553        generated_protocol::RequestPayload::GuestFilesystemCallRequest(inner) => {
554            RequestPayload::GuestFilesystemCall(inner)
555        }
556        generated_protocol::RequestPayload::SnapshotRootFilesystemRequest(inner) => {
557            RequestPayload::SnapshotRootFilesystem(inner)
558        }
559        generated_protocol::RequestPayload::ListMountsRequest => {
560            RequestPayload::ListMounts(ListMountsRequest {})
561        }
562        generated_protocol::RequestPayload::ExecuteRequest(inner) => RequestPayload::Execute(inner),
563        generated_protocol::RequestPayload::WriteStdinRequest(inner) => {
564            RequestPayload::WriteStdin(inner)
565        }
566        generated_protocol::RequestPayload::CloseStdinRequest(inner) => {
567            RequestPayload::CloseStdin(inner)
568        }
569        generated_protocol::RequestPayload::KillProcessRequest(inner) => {
570            RequestPayload::KillProcess(inner)
571        }
572        generated_protocol::RequestPayload::GetProcessSnapshotRequest => {
573            RequestPayload::GetProcessSnapshot(GetProcessSnapshotRequest {})
574        }
575        generated_protocol::RequestPayload::GetResourceSnapshotRequest => {
576            RequestPayload::GetResourceSnapshot(GetResourceSnapshotRequest {})
577        }
578        generated_protocol::RequestPayload::FindListenerRequest(inner) => {
579            RequestPayload::FindListener(inner)
580        }
581        generated_protocol::RequestPayload::FindBoundUdpRequest(inner) => {
582            RequestPayload::FindBoundUdp(inner)
583        }
584        generated_protocol::RequestPayload::VmFetchRequest(inner) => RequestPayload::VmFetch(inner),
585        generated_protocol::RequestPayload::GetSignalStateRequest(inner) => {
586            RequestPayload::GetSignalState(inner)
587        }
588        generated_protocol::RequestPayload::GetZombieTimerCountRequest => {
589            RequestPayload::GetZombieTimerCount(GetZombieTimerCountRequest {})
590        }
591        generated_protocol::RequestPayload::HostFilesystemCallRequest(inner) => {
592            RequestPayload::HostFilesystemCall(HostFilesystemCallRequest {
593                operation: from_generated_filesystem_operation(inner.operation),
594                path: inner.path,
595                payload_size_bytes: inner.payload_size_bytes,
596            })
597        }
598        generated_protocol::RequestPayload::PersistenceLoadRequest(inner) => {
599            RequestPayload::PersistenceLoad(inner)
600        }
601        generated_protocol::RequestPayload::PersistenceFlushRequest(inner) => {
602            RequestPayload::PersistenceFlush(inner)
603        }
604        generated_protocol::RequestPayload::ExtEnvelope(inner) => {
605            RequestPayload::Ext(from_generated_ext_envelope(inner))
606        }
607        generated_protocol::RequestPayload::GuestKernelCallRequest(inner) => {
608            RequestPayload::GuestKernelCall(inner)
609        }
610        generated_protocol::RequestPayload::ResizePtyRequest(inner) => {
611            RequestPayload::ResizePty(inner)
612        }
613        generated_protocol::RequestPayload::LinkPackageRequest(inner) => {
614            RequestPayload::LinkPackage(inner)
615        }
616        generated_protocol::RequestPayload::ProvidedCommandsRequest => {
617            RequestPayload::ProvidedCommands(ProvidedCommandsRequest {})
618        }
619    })
620}
621
622fn to_generated_response_payload(
623    payload: &ResponsePayload,
624) -> Result<generated_protocol::ResponsePayload, ProtocolCodecError> {
625    Ok(match payload {
626        ResponsePayload::Authenticated(inner) => {
627            generated_protocol::ResponsePayload::AuthenticatedResponse(inner.clone())
628        }
629        ResponsePayload::SessionOpened(inner) => {
630            generated_protocol::ResponsePayload::SessionOpenedResponse(inner.clone())
631        }
632        ResponsePayload::VmCreated(inner) => {
633            generated_protocol::ResponsePayload::VmCreatedResponse(inner.clone())
634        }
635        ResponsePayload::VmDisposed(inner) => {
636            generated_protocol::ResponsePayload::VmDisposedResponse(inner.clone())
637        }
638        ResponsePayload::RootFilesystemBootstrapped(inner) => {
639            generated_protocol::ResponsePayload::RootFilesystemBootstrappedResponse(inner.clone())
640        }
641        ResponsePayload::VmConfigured(inner) => {
642            generated_protocol::ResponsePayload::VmConfiguredResponse(inner.clone())
643        }
644        ResponsePayload::HostCallbacksRegistered(inner) => {
645            generated_protocol::ResponsePayload::HostCallbacksRegisteredResponse(inner.clone())
646        }
647        ResponsePayload::LayerCreated(inner) => {
648            generated_protocol::ResponsePayload::LayerCreatedResponse(inner.clone())
649        }
650        ResponsePayload::LayerSealed(inner) => {
651            generated_protocol::ResponsePayload::LayerSealedResponse(inner.clone())
652        }
653        ResponsePayload::SnapshotImported(inner) => {
654            generated_protocol::ResponsePayload::SnapshotImportedResponse(inner.clone())
655        }
656        ResponsePayload::SnapshotExported(inner) => {
657            generated_protocol::ResponsePayload::SnapshotExportedResponse(
658                generated_protocol::SnapshotExportedResponse {
659                    layer_id: inner.layer_id.clone(),
660                    entries: inner.entries.clone(),
661                },
662            )
663        }
664        ResponsePayload::OverlayCreated(inner) => {
665            generated_protocol::ResponsePayload::OverlayCreatedResponse(inner.clone())
666        }
667        ResponsePayload::GuestFilesystemResult(inner) => {
668            generated_protocol::ResponsePayload::GuestFilesystemResultResponse(
669                generated_protocol::GuestFilesystemResultResponse {
670                    operation: to_generated_guest_filesystem_operation(&inner.operation),
671                    path: inner.path.clone(),
672                    content: inner.content.clone(),
673                    encoding: inner
674                        .encoding
675                        .as_ref()
676                        .map(to_generated_root_filesystem_entry_encoding),
677                    entries: inner.entries.clone(),
678                    stat: inner.stat.as_ref().map(to_generated_guest_filesystem_stat),
679                    exists: inner.exists,
680                    target: inner.target.clone(),
681                },
682            )
683        }
684        ResponsePayload::RootFilesystemSnapshot(inner) => {
685            generated_protocol::ResponsePayload::RootFilesystemSnapshotResponse(
686                generated_protocol::RootFilesystemSnapshotResponse {
687                    entries: inner.entries.clone(),
688                },
689            )
690        }
691        ResponsePayload::MountsListed(inner) => {
692            generated_protocol::ResponsePayload::ListMountsResponse(inner.clone())
693        }
694        ResponsePayload::ProcessStarted(inner) => {
695            generated_protocol::ResponsePayload::ProcessStartedResponse(inner.clone())
696        }
697        ResponsePayload::StdinWritten(inner) => {
698            generated_protocol::ResponsePayload::StdinWrittenResponse(inner.clone())
699        }
700        ResponsePayload::StdinClosed(inner) => {
701            generated_protocol::ResponsePayload::StdinClosedResponse(inner.clone())
702        }
703        ResponsePayload::ProcessKilled(inner) => {
704            generated_protocol::ResponsePayload::ProcessKilledResponse(inner.clone())
705        }
706        ResponsePayload::ProcessSnapshot(inner) => {
707            generated_protocol::ResponsePayload::ProcessSnapshotResponse(
708                generated_protocol::ProcessSnapshotResponse {
709                    processes: inner
710                        .processes
711                        .iter()
712                        .map(to_generated_process_snapshot_entry)
713                        .collect(),
714                },
715            )
716        }
717        ResponsePayload::ResourceSnapshot(inner) => {
718            generated_protocol::ResponsePayload::ResourceSnapshotResponse(inner.clone())
719        }
720        ResponsePayload::ListenerSnapshot(inner) => {
721            generated_protocol::ResponsePayload::ListenerSnapshotResponse(inner.clone())
722        }
723        ResponsePayload::BoundUdpSnapshot(inner) => {
724            generated_protocol::ResponsePayload::BoundUdpSnapshotResponse(inner.clone())
725        }
726        ResponsePayload::VmFetchResult(inner) => {
727            generated_protocol::ResponsePayload::VmFetchResponse(inner.clone())
728        }
729        ResponsePayload::SignalState(inner) => {
730            generated_protocol::ResponsePayload::SignalStateResponse(inner.clone())
731        }
732        ResponsePayload::ZombieTimerCount(inner) => {
733            generated_protocol::ResponsePayload::ZombieTimerCountResponse(inner.clone())
734        }
735        ResponsePayload::FilesystemResult(inner) => {
736            generated_protocol::ResponsePayload::FilesystemResultResponse(
737                generated_protocol::FilesystemResultResponse {
738                    operation: to_generated_filesystem_operation(&inner.operation),
739                    status: inner.status.clone(),
740                    payload_size_bytes: inner.payload_size_bytes,
741                },
742            )
743        }
744        ResponsePayload::PermissionDecision(inner) => {
745            generated_protocol::ResponsePayload::PermissionDecisionResponse(
746                generated_protocol::PermissionDecisionResponse {
747                    capability: inner.capability.clone(),
748                    decision: to_generated_permission_mode(&inner.decision),
749                },
750            )
751        }
752        ResponsePayload::PersistenceState(inner) => {
753            generated_protocol::ResponsePayload::PersistenceStateResponse(inner.clone())
754        }
755        ResponsePayload::PersistenceFlushed(inner) => {
756            generated_protocol::ResponsePayload::PersistenceFlushedResponse(inner.clone())
757        }
758        ResponsePayload::Rejected(inner) => {
759            generated_protocol::ResponsePayload::RejectedResponse(inner.clone())
760        }
761        ResponsePayload::ExtResult(inner) => {
762            generated_protocol::ResponsePayload::ExtEnvelope(to_generated_ext_envelope(inner))
763        }
764        ResponsePayload::GuestKernelResult(inner) => {
765            generated_protocol::ResponsePayload::GuestKernelResultResponse(inner.clone())
766        }
767        ResponsePayload::PtyResized(inner) => {
768            generated_protocol::ResponsePayload::PtyResizedResponse(inner.clone())
769        }
770        ResponsePayload::PackageLinked(inner) => {
771            generated_protocol::ResponsePayload::PackageLinkedResponse(inner.clone())
772        }
773        ResponsePayload::ProvidedCommands(inner) => {
774            generated_protocol::ResponsePayload::ProvidedCommandsResponse(inner.clone())
775        }
776    })
777}
778
779fn from_generated_response_payload(
780    payload: generated_protocol::ResponsePayload,
781) -> Result<ResponsePayload, ProtocolCodecError> {
782    Ok(match payload {
783        generated_protocol::ResponsePayload::AuthenticatedResponse(inner) => {
784            ResponsePayload::Authenticated(inner)
785        }
786        generated_protocol::ResponsePayload::SessionOpenedResponse(inner) => {
787            ResponsePayload::SessionOpened(inner)
788        }
789        generated_protocol::ResponsePayload::VmCreatedResponse(inner) => {
790            ResponsePayload::VmCreated(inner)
791        }
792        generated_protocol::ResponsePayload::VmDisposedResponse(inner) => {
793            ResponsePayload::VmDisposed(inner)
794        }
795        generated_protocol::ResponsePayload::RootFilesystemBootstrappedResponse(inner) => {
796            ResponsePayload::RootFilesystemBootstrapped(inner)
797        }
798        generated_protocol::ResponsePayload::VmConfiguredResponse(inner) => {
799            ResponsePayload::VmConfigured(inner)
800        }
801        generated_protocol::ResponsePayload::HostCallbacksRegisteredResponse(inner) => {
802            ResponsePayload::HostCallbacksRegistered(inner)
803        }
804        generated_protocol::ResponsePayload::LayerCreatedResponse(inner) => {
805            ResponsePayload::LayerCreated(inner)
806        }
807        generated_protocol::ResponsePayload::LayerSealedResponse(inner) => {
808            ResponsePayload::LayerSealed(inner)
809        }
810        generated_protocol::ResponsePayload::SnapshotImportedResponse(inner) => {
811            ResponsePayload::SnapshotImported(inner)
812        }
813        generated_protocol::ResponsePayload::SnapshotExportedResponse(inner) => {
814            ResponsePayload::SnapshotExported(SnapshotExportedResponse {
815                layer_id: inner.layer_id,
816                entries: inner.entries,
817            })
818        }
819        generated_protocol::ResponsePayload::OverlayCreatedResponse(inner) => {
820            ResponsePayload::OverlayCreated(inner)
821        }
822        generated_protocol::ResponsePayload::GuestFilesystemResultResponse(inner) => {
823            ResponsePayload::GuestFilesystemResult(GuestFilesystemResultResponse {
824                operation: from_generated_guest_filesystem_operation(inner.operation),
825                path: inner.path,
826                content: inner.content,
827                encoding: inner
828                    .encoding
829                    .map(from_generated_root_filesystem_entry_encoding),
830                entries: inner.entries,
831                stat: inner.stat.map(from_generated_guest_filesystem_stat),
832                exists: inner.exists,
833                target: inner.target,
834            })
835        }
836        generated_protocol::ResponsePayload::RootFilesystemSnapshotResponse(inner) => {
837            ResponsePayload::RootFilesystemSnapshot(RootFilesystemSnapshotResponse {
838                entries: inner.entries,
839            })
840        }
841        generated_protocol::ResponsePayload::ListMountsResponse(inner) => {
842            ResponsePayload::MountsListed(inner)
843        }
844        generated_protocol::ResponsePayload::ProcessStartedResponse(inner) => {
845            ResponsePayload::ProcessStarted(inner)
846        }
847        generated_protocol::ResponsePayload::StdinWrittenResponse(inner) => {
848            ResponsePayload::StdinWritten(inner)
849        }
850        generated_protocol::ResponsePayload::StdinClosedResponse(inner) => {
851            ResponsePayload::StdinClosed(inner)
852        }
853        generated_protocol::ResponsePayload::ProcessKilledResponse(inner) => {
854            ResponsePayload::ProcessKilled(inner)
855        }
856        generated_protocol::ResponsePayload::ProcessSnapshotResponse(inner) => {
857            ResponsePayload::ProcessSnapshot(ProcessSnapshotResponse {
858                processes: inner
859                    .processes
860                    .into_iter()
861                    .map(from_generated_process_snapshot_entry)
862                    .collect(),
863            })
864        }
865        generated_protocol::ResponsePayload::ResourceSnapshotResponse(inner) => {
866            ResponsePayload::ResourceSnapshot(inner)
867        }
868        generated_protocol::ResponsePayload::ListenerSnapshotResponse(inner) => {
869            ResponsePayload::ListenerSnapshot(inner)
870        }
871        generated_protocol::ResponsePayload::BoundUdpSnapshotResponse(inner) => {
872            ResponsePayload::BoundUdpSnapshot(inner)
873        }
874        generated_protocol::ResponsePayload::VmFetchResponse(inner) => {
875            ResponsePayload::VmFetchResult(inner)
876        }
877        generated_protocol::ResponsePayload::SignalStateResponse(inner) => {
878            ResponsePayload::SignalState(inner)
879        }
880        generated_protocol::ResponsePayload::ZombieTimerCountResponse(inner) => {
881            ResponsePayload::ZombieTimerCount(inner)
882        }
883        generated_protocol::ResponsePayload::FilesystemResultResponse(inner) => {
884            ResponsePayload::FilesystemResult(FilesystemResultResponse {
885                operation: from_generated_filesystem_operation(inner.operation),
886                status: inner.status,
887                payload_size_bytes: inner.payload_size_bytes,
888            })
889        }
890        generated_protocol::ResponsePayload::PermissionDecisionResponse(inner) => {
891            ResponsePayload::PermissionDecision(PermissionDecisionResponse {
892                capability: inner.capability,
893                decision: from_generated_permission_mode(inner.decision),
894            })
895        }
896        generated_protocol::ResponsePayload::PersistenceStateResponse(inner) => {
897            ResponsePayload::PersistenceState(inner)
898        }
899        generated_protocol::ResponsePayload::PersistenceFlushedResponse(inner) => {
900            ResponsePayload::PersistenceFlushed(inner)
901        }
902        generated_protocol::ResponsePayload::RejectedResponse(inner) => {
903            ResponsePayload::Rejected(inner)
904        }
905        generated_protocol::ResponsePayload::ExtEnvelope(inner) => {
906            ResponsePayload::ExtResult(from_generated_ext_envelope(inner))
907        }
908        generated_protocol::ResponsePayload::GuestKernelResultResponse(inner) => {
909            ResponsePayload::GuestKernelResult(inner)
910        }
911        generated_protocol::ResponsePayload::PtyResizedResponse(inner) => {
912            ResponsePayload::PtyResized(inner)
913        }
914        generated_protocol::ResponsePayload::PackageLinkedResponse(inner) => {
915            ResponsePayload::PackageLinked(inner)
916        }
917        generated_protocol::ResponsePayload::ProvidedCommandsResponse(inner) => {
918            ResponsePayload::ProvidedCommands(inner)
919        }
920    })
921}
922
923fn to_generated_event_payload(payload: &EventPayload) -> generated_protocol::EventPayload {
924    match payload {
925        EventPayload::VmLifecycle(inner) => generated_protocol::EventPayload::VmLifecycleEvent(
926            generated_protocol::VmLifecycleEvent {
927                state: to_generated_vm_lifecycle_state(&inner.state),
928            },
929        ),
930        EventPayload::ProcessOutput(inner) => generated_protocol::EventPayload::ProcessOutputEvent(
931            generated_protocol::ProcessOutputEvent {
932                process_id: inner.process_id.clone(),
933                channel: to_generated_stream_channel(&inner.channel),
934                chunk: inner.chunk.clone(),
935            },
936        ),
937        EventPayload::ProcessExited(inner) => {
938            generated_protocol::EventPayload::ProcessExitedEvent(inner.clone())
939        }
940        EventPayload::Structured(inner) => {
941            generated_protocol::EventPayload::StructuredEvent(inner.clone())
942        }
943        EventPayload::Ext(inner) => {
944            generated_protocol::EventPayload::ExtEnvelope(to_generated_ext_envelope(inner))
945        }
946    }
947}
948
949fn from_generated_event_payload(payload: generated_protocol::EventPayload) -> EventPayload {
950    match payload {
951        generated_protocol::EventPayload::VmLifecycleEvent(inner) => {
952            EventPayload::VmLifecycle(VmLifecycleEvent {
953                state: from_generated_vm_lifecycle_state(inner.state),
954            })
955        }
956        generated_protocol::EventPayload::ProcessOutputEvent(inner) => {
957            EventPayload::ProcessOutput(ProcessOutputEvent {
958                process_id: inner.process_id,
959                channel: from_generated_stream_channel(inner.channel),
960                chunk: inner.chunk,
961            })
962        }
963        generated_protocol::EventPayload::ProcessExitedEvent(inner) => {
964            EventPayload::ProcessExited(inner)
965        }
966        generated_protocol::EventPayload::StructuredEvent(inner) => EventPayload::Structured(inner),
967        generated_protocol::EventPayload::ExtEnvelope(inner) => {
968            EventPayload::Ext(from_generated_ext_envelope(inner))
969        }
970    }
971}
972
973fn to_generated_sidecar_request_payload(
974    payload: &SidecarRequestPayload,
975) -> Result<generated_protocol::SidecarRequestPayload, ProtocolCodecError> {
976    Ok(match payload {
977        SidecarRequestPayload::HostCallback(inner) => {
978            generated_protocol::SidecarRequestPayload::HostCallbackRequest(inner.clone())
979        }
980        SidecarRequestPayload::JsBridgeCall(inner) => {
981            generated_protocol::SidecarRequestPayload::JsBridgeCallRequest(inner.clone())
982        }
983        SidecarRequestPayload::Ext(inner) => {
984            generated_protocol::SidecarRequestPayload::ExtEnvelope(to_generated_ext_envelope(inner))
985        }
986    })
987}
988
989fn from_generated_sidecar_request_payload(
990    payload: generated_protocol::SidecarRequestPayload,
991) -> Result<SidecarRequestPayload, ProtocolCodecError> {
992    Ok(match payload {
993        generated_protocol::SidecarRequestPayload::HostCallbackRequest(inner) => {
994            SidecarRequestPayload::HostCallback(inner)
995        }
996        generated_protocol::SidecarRequestPayload::JsBridgeCallRequest(inner) => {
997            SidecarRequestPayload::JsBridgeCall(inner)
998        }
999        generated_protocol::SidecarRequestPayload::ExtEnvelope(inner) => {
1000            SidecarRequestPayload::Ext(from_generated_ext_envelope(inner))
1001        }
1002    })
1003}
1004
1005fn to_generated_sidecar_response_payload(
1006    payload: &SidecarResponsePayload,
1007) -> Result<generated_protocol::SidecarResponsePayload, ProtocolCodecError> {
1008    Ok(match payload {
1009        SidecarResponsePayload::HostCallbackResult(inner) => {
1010            generated_protocol::SidecarResponsePayload::HostCallbackResultResponse(inner.clone())
1011        }
1012        SidecarResponsePayload::JsBridgeResult(inner) => {
1013            generated_protocol::SidecarResponsePayload::JsBridgeResultResponse(inner.clone())
1014        }
1015        SidecarResponsePayload::ExtResult(inner) => {
1016            generated_protocol::SidecarResponsePayload::ExtEnvelope(to_generated_ext_envelope(
1017                inner,
1018            ))
1019        }
1020    })
1021}
1022
1023fn from_generated_sidecar_response_payload(
1024    payload: generated_protocol::SidecarResponsePayload,
1025) -> Result<SidecarResponsePayload, ProtocolCodecError> {
1026    Ok(match payload {
1027        generated_protocol::SidecarResponsePayload::HostCallbackResultResponse(inner) => {
1028            SidecarResponsePayload::HostCallbackResult(inner)
1029        }
1030        generated_protocol::SidecarResponsePayload::JsBridgeResultResponse(inner) => {
1031            SidecarResponsePayload::JsBridgeResult(inner)
1032        }
1033        generated_protocol::SidecarResponsePayload::ExtEnvelope(inner) => {
1034            SidecarResponsePayload::ExtResult(from_generated_ext_envelope(inner))
1035        }
1036    })
1037}
1038
1039macro_rules! impl_bare_newtype_union_enum {
1040    (
1041        $name:ident,
1042        $json_name:ident,
1043        $(#[$json_attr:meta])*
1044        {
1045            $($variant:ident($ty:ty) = $tag:literal),+ $(,)?
1046        }
1047    ) => {
1048        #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1049        $(#[$json_attr])*
1050        enum $json_name {
1051            $($variant($ty)),+
1052        }
1053
1054        impl From<&$name> for $json_name {
1055            fn from(value: &$name) -> Self {
1056                match value {
1057                    $($name::$variant(inner) => Self::$variant(inner.clone()),)+
1058                }
1059            }
1060        }
1061
1062        impl From<$json_name> for $name {
1063            fn from(value: $json_name) -> Self {
1064                match value {
1065                    $($json_name::$variant(inner) => Self::$variant(inner),)+
1066                }
1067            }
1068        }
1069
1070        impl Serialize for $name {
1071            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1072            where
1073                S: Serializer,
1074            {
1075                if serializer.is_human_readable() {
1076                    $json_name::from(self).serialize(serializer)
1077                } else {
1078                    match self {
1079                        $(Self::$variant(inner) => serialize_bare_newtype_tag(serializer, $tag, inner),)+
1080                    }
1081                }
1082            }
1083        }
1084
1085        impl<'de> Deserialize<'de> for $name {
1086            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1087            where
1088                D: Deserializer<'de>,
1089            {
1090                if deserializer.is_human_readable() {
1091                    Ok($json_name::deserialize(deserializer)?.into())
1092                } else {
1093                    struct UnionVisitor;
1094
1095                    impl<'de> Visitor<'de> for UnionVisitor {
1096                        type Value = $name;
1097
1098                        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1099                            write!(formatter, "a {} BARE union", stringify!($name))
1100                        }
1101
1102                        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1103                        where
1104                            A: SeqAccess<'de>,
1105                        {
1106                            let serde_bare::Uint(tag) = seq
1107                                .next_element()?
1108                                .ok_or_else(|| de::Error::custom(concat!("missing ", stringify!($name), " tag")))?;
1109                            match tag {
1110                                $(
1111                                    $tag => {
1112                                        let payload = seq.next_element::<$ty>()?.ok_or_else(|| {
1113                                            de::Error::custom(format!(
1114                                                "missing {} payload for tag {}",
1115                                                stringify!($variant),
1116                                                $tag
1117                                            ))
1118                                        })?;
1119                                        Ok($name::$variant(payload))
1120                                    }
1121                                )+
1122                                _ => Err(de::Error::custom(format!(
1123                                    "unknown {} tag: {}",
1124                                    stringify!($name),
1125                                    tag
1126                                ))),
1127                            }
1128                        }
1129                    }
1130
1131                    deserializer.deserialize_tuple(2, UnionVisitor)
1132                }
1133            }
1134        }
1135    };
1136}
1137
1138pub type ProtocolSchema = crate::wire::ProtocolSchema;
1139
1140pub type OwnershipScope = crate::wire::OwnershipScope;
1141
1142#[derive(Debug, Clone, PartialEq, Eq)]
1143pub enum ProtocolFrame {
1144    Request(RequestFrame),
1145    Response(ResponseFrame),
1146    Event(EventFrame),
1147    SidecarRequest(SidecarRequestFrame),
1148    SidecarResponse(SidecarResponseFrame),
1149    Control(ControlFrame),
1150}
1151
1152pub type ControlFrame = crate::wire::ControlFrame;
1153pub type ControlPayload = crate::wire::ControlPayload;
1154pub type ShutdownControl = crate::wire::ShutdownControl;
1155
1156#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1157pub struct RequestFrame {
1158    pub schema: ProtocolSchema,
1159    pub request_id: RequestId,
1160    pub ownership: OwnershipScope,
1161    pub payload: RequestPayload,
1162}
1163
1164impl RequestFrame {
1165    pub fn new(request_id: RequestId, ownership: OwnershipScope, payload: RequestPayload) -> Self {
1166        Self {
1167            schema: ProtocolSchema::current(),
1168            request_id,
1169            ownership,
1170            payload,
1171        }
1172    }
1173}
1174
1175#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1176pub struct ResponseFrame {
1177    pub schema: ProtocolSchema,
1178    pub request_id: RequestId,
1179    pub ownership: OwnershipScope,
1180    pub payload: ResponsePayload,
1181}
1182
1183impl ResponseFrame {
1184    pub fn new(request_id: RequestId, ownership: OwnershipScope, payload: ResponsePayload) -> Self {
1185        Self {
1186            schema: ProtocolSchema::current(),
1187            request_id,
1188            ownership,
1189            payload,
1190        }
1191    }
1192}
1193
1194#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1195pub struct SidecarRequestFrame {
1196    pub schema: ProtocolSchema,
1197    pub request_id: RequestId,
1198    pub ownership: OwnershipScope,
1199    pub payload: SidecarRequestPayload,
1200}
1201
1202impl SidecarRequestFrame {
1203    pub fn new(
1204        request_id: RequestId,
1205        ownership: OwnershipScope,
1206        payload: SidecarRequestPayload,
1207    ) -> Self {
1208        Self {
1209            schema: ProtocolSchema::current(),
1210            request_id,
1211            ownership,
1212            payload,
1213        }
1214    }
1215}
1216
1217#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1218pub struct SidecarResponseFrame {
1219    pub schema: ProtocolSchema,
1220    pub request_id: RequestId,
1221    pub ownership: OwnershipScope,
1222    pub payload: SidecarResponsePayload,
1223}
1224
1225impl SidecarResponseFrame {
1226    pub fn new(
1227        request_id: RequestId,
1228        ownership: OwnershipScope,
1229        payload: SidecarResponsePayload,
1230    ) -> Self {
1231        Self {
1232            schema: ProtocolSchema::current(),
1233            request_id,
1234            ownership,
1235            payload,
1236        }
1237    }
1238}
1239
1240#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1241pub struct EventFrame {
1242    pub schema: ProtocolSchema,
1243    pub ownership: OwnershipScope,
1244    pub payload: EventPayload,
1245}
1246
1247impl EventFrame {
1248    pub fn new(ownership: OwnershipScope, payload: EventPayload) -> Self {
1249        Self {
1250            schema: ProtocolSchema::current(),
1251            ownership,
1252            payload,
1253        }
1254    }
1255}
1256
1257#[derive(Debug, Clone, PartialEq, Eq)]
1258pub enum RequestPayload {
1259    Authenticate(AuthenticateRequest),
1260    OpenSession(OpenSessionRequest),
1261    CreateVm(CreateVmRequest),
1262    DisposeVm(DisposeVmRequest),
1263    BootstrapRootFilesystem(BootstrapRootFilesystemRequest),
1264    ConfigureVm(ConfigureVmRequest),
1265    RegisterHostCallbacks(RegisterHostCallbacksRequest),
1266    CreateLayer(CreateLayerRequest),
1267    SealLayer(SealLayerRequest),
1268    ImportSnapshot(ImportSnapshotRequest),
1269    ExportSnapshot(ExportSnapshotRequest),
1270    CreateOverlay(CreateOverlayRequest),
1271    GuestFilesystemCall(GuestFilesystemCallRequest),
1272    SnapshotRootFilesystem(SnapshotRootFilesystemRequest),
1273    ListMounts(ListMountsRequest),
1274    Execute(ExecuteRequest),
1275    WriteStdin(WriteStdinRequest),
1276    CloseStdin(CloseStdinRequest),
1277    KillProcess(KillProcessRequest),
1278    GetProcessSnapshot(GetProcessSnapshotRequest),
1279    FindListener(FindListenerRequest),
1280    FindBoundUdp(FindBoundUdpRequest),
1281    VmFetch(VmFetchRequest),
1282    GetSignalState(GetSignalStateRequest),
1283    GetZombieTimerCount(GetZombieTimerCountRequest),
1284    HostFilesystemCall(HostFilesystemCallRequest),
1285    PersistenceLoad(PersistenceLoadRequest),
1286    PersistenceFlush(PersistenceFlushRequest),
1287    Ext(ExtEnvelope),
1288    GuestKernelCall(GuestKernelCallRequest),
1289    ResizePty(ResizePtyRequest),
1290    GetResourceSnapshot(GetResourceSnapshotRequest),
1291    LinkPackage(LinkPackageRequest),
1292    ProvidedCommands(ProvidedCommandsRequest),
1293}
1294
1295#[derive(Debug, Clone, PartialEq, Eq)]
1296pub enum ResponsePayload {
1297    Authenticated(AuthenticatedResponse),
1298    SessionOpened(SessionOpenedResponse),
1299    VmCreated(VmCreatedResponse),
1300    VmDisposed(VmDisposedResponse),
1301    RootFilesystemBootstrapped(RootFilesystemBootstrappedResponse),
1302    VmConfigured(VmConfiguredResponse),
1303    HostCallbacksRegistered(HostCallbacksRegisteredResponse),
1304    LayerCreated(LayerCreatedResponse),
1305    LayerSealed(LayerSealedResponse),
1306    SnapshotImported(SnapshotImportedResponse),
1307    SnapshotExported(SnapshotExportedResponse),
1308    OverlayCreated(OverlayCreatedResponse),
1309    GuestFilesystemResult(GuestFilesystemResultResponse),
1310    RootFilesystemSnapshot(RootFilesystemSnapshotResponse),
1311    MountsListed(ListMountsResponse),
1312    ProcessStarted(ProcessStartedResponse),
1313    StdinWritten(StdinWrittenResponse),
1314    StdinClosed(StdinClosedResponse),
1315    ProcessKilled(ProcessKilledResponse),
1316    ProcessSnapshot(ProcessSnapshotResponse),
1317    ListenerSnapshot(ListenerSnapshotResponse),
1318    BoundUdpSnapshot(BoundUdpSnapshotResponse),
1319    VmFetchResult(VmFetchResponse),
1320    SignalState(SignalStateResponse),
1321    ZombieTimerCount(ZombieTimerCountResponse),
1322    FilesystemResult(FilesystemResultResponse),
1323    PermissionDecision(PermissionDecisionResponse),
1324    PersistenceState(PersistenceStateResponse),
1325    PersistenceFlushed(PersistenceFlushedResponse),
1326    Rejected(RejectedResponse),
1327    ExtResult(ExtEnvelope),
1328    GuestKernelResult(GuestKernelResultResponse),
1329    PtyResized(PtyResizedResponse),
1330    ResourceSnapshot(ResourceSnapshotResponse),
1331    PackageLinked(PackageLinkedResponse),
1332    ProvidedCommands(ProvidedCommandsResponse),
1333}
1334
1335#[derive(Debug, Clone, PartialEq, Eq)]
1336pub enum SidecarRequestPayload {
1337    HostCallback(HostCallbackRequest),
1338    JsBridgeCall(JsBridgeCallRequest),
1339    Ext(ExtEnvelope),
1340}
1341
1342#[derive(Debug, Clone, PartialEq, Eq)]
1343pub enum SidecarResponsePayload {
1344    HostCallbackResult(HostCallbackResultResponse),
1345    JsBridgeResult(JsBridgeResultResponse),
1346    ExtResult(ExtEnvelope),
1347}
1348
1349#[derive(Debug, Clone, PartialEq, Eq)]
1350pub enum EventPayload {
1351    VmLifecycle(VmLifecycleEvent),
1352    ProcessOutput(ProcessOutputEvent),
1353    ProcessExited(ProcessExitedEvent),
1354    Structured(StructuredEvent),
1355    Ext(ExtEnvelope),
1356}
1357
1358pub type SidecarPlacement = crate::wire::SidecarPlacement;
1359
1360pub type SidecarPlacementShared = crate::wire::SidecarPlacementShared;
1361
1362pub type SidecarPlacementExplicit = crate::wire::SidecarPlacementExplicit;
1363
1364pub type GuestRuntimeKind = crate::wire::GuestRuntimeKind;
1365
1366pub type DisposeReason = crate::wire::DisposeReason;
1367
1368pub type FilesystemOperation = crate::wire::FilesystemOperation;
1369
1370pub type GuestFilesystemOperation = crate::wire::GuestFilesystemOperation;
1371
1372pub type PermissionMode = crate::wire::PermissionMode;
1373
1374pub type FsPermissionRule = crate::wire::FsPermissionRule;
1375
1376pub type PatternPermissionRule = crate::wire::PatternPermissionRule;
1377
1378pub type FsPermissionRuleSet = crate::wire::FsPermissionRuleSet;
1379
1380pub type PatternPermissionRuleSet = crate::wire::PatternPermissionRuleSet;
1381
1382pub type FsPermissionScope = crate::wire::FsPermissionScope;
1383
1384pub type PatternPermissionScope = crate::wire::PatternPermissionScope;
1385
1386pub type PermissionsPolicy = crate::wire::PermissionsPolicy;
1387
1388pub type RootFilesystemEntryKind = crate::wire::RootFilesystemEntryKind;
1389
1390pub type RootFilesystemMode = crate::wire::RootFilesystemMode;
1391
1392pub type RootFilesystemLowerDescriptor = crate::wire::RootFilesystemLowerDescriptor;
1393
1394pub type SnapshotRootFilesystemLower = crate::wire::SnapshotRootFilesystemLower;
1395
1396pub type StreamChannel = crate::wire::StreamChannel;
1397
1398pub type VmLifecycleState = crate::wire::VmLifecycleState;
1399
1400pub type AuthenticateRequest = crate::wire::AuthenticateRequest;
1401
1402pub type OpenSessionRequest = crate::wire::OpenSessionRequest;
1403
1404pub type CreateVmRequest = crate::wire::CreateVmRequest;
1405
1406#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1407pub struct DisposeVmRequest {
1408    pub reason: DisposeReason,
1409}
1410
1411pub type BootstrapRootFilesystemRequest = crate::wire::BootstrapRootFilesystemRequest;
1412
1413pub type RootFilesystemDescriptor = crate::wire::RootFilesystemDescriptor;
1414
1415pub type RootFilesystemEntryEncoding = crate::wire::RootFilesystemEntryEncoding;
1416
1417pub type RootFilesystemEntry = crate::wire::RootFilesystemEntry;
1418
1419pub type ConfigureVmRequest = crate::wire::ConfigureVmRequest;
1420
1421#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1422pub struct CreateLayerRequest {}
1423
1424pub type SealLayerRequest = crate::wire::SealLayerRequest;
1425
1426pub type ImportSnapshotRequest = crate::wire::ImportSnapshotRequest;
1427
1428pub type ExportSnapshotRequest = crate::wire::ExportSnapshotRequest;
1429
1430pub type CreateOverlayRequest = crate::wire::CreateOverlayRequest;
1431
1432pub type GuestFilesystemCallRequest = crate::wire::GuestFilesystemCallRequest;
1433
1434pub type GuestKernelCallRequest = crate::wire::GuestKernelCallRequest;
1435pub type ResizePtyRequest = crate::wire::ResizePtyRequest;
1436pub type PackageDescriptor = crate::wire::PackageDescriptor;
1437pub type AgentosProjectedAgent = crate::wire::AgentosProjectedAgent;
1438pub type PackageCommands = crate::wire::PackageCommands;
1439pub type ProjectedCommand = crate::wire::ProjectedCommand;
1440pub type LinkPackageRequest = crate::wire::LinkPackageRequest;
1441
1442#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1443pub struct ProvidedCommandsRequest {}
1444
1445pub type GuestKernelResultResponse = crate::wire::GuestKernelResultResponse;
1446pub type PtyResizedResponse = crate::wire::PtyResizedResponse;
1447pub type PackageLinkedResponse = crate::wire::PackageLinkedResponse;
1448pub type ProvidedCommandsResponse = crate::wire::ProvidedCommandsResponse;
1449
1450pub type SnapshotRootFilesystemRequest = crate::wire::SnapshotRootFilesystemRequest;
1451
1452#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1453pub struct ListMountsRequest {}
1454
1455pub type MountDescriptor = crate::wire::MountDescriptor;
1456
1457pub type MountInfo = crate::wire::MountInfo;
1458
1459pub type MountPluginDescriptor = crate::wire::MountPluginDescriptor;
1460
1461pub type SoftwareDescriptor = crate::wire::SoftwareDescriptor;
1462
1463pub type ProjectedModuleDescriptor = crate::wire::ProjectedModuleDescriptor;
1464
1465pub type WasmPermissionTier = crate::wire::WasmPermissionTier;
1466
1467pub type ExecuteRequest = crate::wire::ExecuteRequest;
1468
1469pub type WriteStdinRequest = crate::wire::WriteStdinRequest;
1470
1471pub type CloseStdinRequest = crate::wire::CloseStdinRequest;
1472
1473pub type KillProcessRequest = crate::wire::KillProcessRequest;
1474
1475#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1476pub struct GetProcessSnapshotRequest {}
1477
1478#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1479pub struct GetResourceSnapshotRequest {}
1480
1481pub type FindListenerRequest = crate::wire::FindListenerRequest;
1482
1483pub type FindBoundUdpRequest = crate::wire::FindBoundUdpRequest;
1484
1485pub type VmFetchRequest = crate::wire::VmFetchRequest;
1486
1487pub type GetSignalStateRequest = crate::wire::GetSignalStateRequest;
1488
1489#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1490pub struct GetZombieTimerCountRequest {}
1491
1492pub type HostFilesystemCallRequest = crate::wire::HostFilesystemCallRequest;
1493
1494pub type PersistenceLoadRequest = crate::wire::PersistenceLoadRequest;
1495
1496pub type PersistenceFlushRequest = crate::wire::PersistenceFlushRequest;
1497
1498pub type RegisterHostCallbacksRequest = crate::wire::RegisterHostCallbacksRequest;
1499
1500pub type RegisteredHostCallbackDefinition = crate::wire::RegisteredHostCallbackDefinition;
1501
1502pub type RegisteredHostCallbackExample = crate::wire::RegisteredHostCallbackExample;
1503
1504pub type HostCallbackRequest = crate::wire::HostCallbackRequest;
1505
1506pub type JsBridgeCallRequest = crate::wire::JsBridgeCallRequest;
1507
1508pub type AuthenticatedResponse = crate::wire::AuthenticatedResponse;
1509
1510pub type SessionOpenedResponse = crate::wire::SessionOpenedResponse;
1511
1512pub type VmCreatedResponse = crate::wire::VmCreatedResponse;
1513
1514pub type VmDisposedResponse = crate::wire::VmDisposedResponse;
1515
1516pub type RootFilesystemBootstrappedResponse = crate::wire::RootFilesystemBootstrappedResponse;
1517
1518pub type VmConfiguredResponse = crate::wire::VmConfiguredResponse;
1519
1520pub type HostCallbacksRegisteredResponse = crate::wire::HostCallbacksRegisteredResponse;
1521
1522pub type GuestFilesystemStat = crate::wire::GuestFilesystemStat;
1523
1524pub type GuestDirEntry = crate::wire::GuestDirEntry;
1525
1526pub type GuestFilesystemResultResponse = crate::wire::GuestFilesystemResultResponse;
1527
1528pub type RootFilesystemSnapshotResponse = crate::wire::RootFilesystemSnapshotResponse;
1529
1530pub type ListMountsResponse = crate::wire::ListMountsResponse;
1531
1532pub type LayerCreatedResponse = crate::wire::LayerCreatedResponse;
1533
1534pub type LayerSealedResponse = crate::wire::LayerSealedResponse;
1535
1536pub type SnapshotImportedResponse = crate::wire::SnapshotImportedResponse;
1537
1538pub type SnapshotExportedResponse = crate::wire::SnapshotExportedResponse;
1539
1540pub type OverlayCreatedResponse = crate::wire::OverlayCreatedResponse;
1541
1542pub type ProcessStartedResponse = crate::wire::ProcessStartedResponse;
1543
1544pub type StdinWrittenResponse = crate::wire::StdinWrittenResponse;
1545
1546pub type StdinClosedResponse = crate::wire::StdinClosedResponse;
1547
1548pub type ProcessKilledResponse = crate::wire::ProcessKilledResponse;
1549
1550pub type ProcessSnapshotStatus = crate::wire::ProcessSnapshotStatus;
1551
1552pub type ProcessSnapshotEntry = crate::wire::ProcessSnapshotEntry;
1553
1554pub type ProcessSnapshotResponse = crate::wire::ProcessSnapshotResponse;
1555
1556pub type QueueSnapshotEntry = crate::wire::QueueSnapshotEntry;
1557
1558pub type ResourceSnapshotResponse = crate::wire::ResourceSnapshotResponse;
1559
1560pub type SocketStateEntry = crate::wire::SocketStateEntry;
1561
1562pub type ListenerSnapshotResponse = crate::wire::ListenerSnapshotResponse;
1563
1564pub type BoundUdpSnapshotResponse = crate::wire::BoundUdpSnapshotResponse;
1565
1566pub type VmFetchResponse = crate::wire::VmFetchResponse;
1567
1568pub type SignalDispositionAction = crate::wire::SignalDispositionAction;
1569
1570pub type SignalHandlerRegistration = crate::wire::SignalHandlerRegistration;
1571
1572pub type SignalStateResponse = crate::wire::SignalStateResponse;
1573
1574pub type ZombieTimerCountResponse = crate::wire::ZombieTimerCountResponse;
1575
1576pub type FilesystemResultResponse = crate::wire::FilesystemResultResponse;
1577
1578pub type PermissionDecisionResponse = crate::wire::PermissionDecisionResponse;
1579
1580pub type PersistenceStateResponse = crate::wire::PersistenceStateResponse;
1581
1582pub type PersistenceFlushedResponse = crate::wire::PersistenceFlushedResponse;
1583
1584pub type HostCallbackResultResponse = crate::wire::HostCallbackResultResponse;
1585
1586pub type JsBridgeResultResponse = crate::wire::JsBridgeResultResponse;
1587
1588pub type RejectedResponse = crate::wire::RejectedResponse;
1589
1590pub type VmLifecycleEvent = crate::wire::VmLifecycleEvent;
1591
1592pub type ProcessOutputEvent = crate::wire::ProcessOutputEvent;
1593
1594pub type ProcessExitedEvent = crate::wire::ProcessExitedEvent;
1595
1596pub type StructuredEvent = crate::wire::StructuredEvent;
1597
1598impl_bare_newtype_union_enum!(
1599    ProtocolFrame,
1600    JsonProtocolFrame,
1601    #[serde(tag = "frame_type", rename_all = "snake_case")]
1602    {
1603        Request(RequestFrame) = 0,
1604        Response(ResponseFrame) = 1,
1605        Event(EventFrame) = 2,
1606        SidecarRequest(SidecarRequestFrame) = 3,
1607        SidecarResponse(SidecarResponseFrame) = 4,
1608        Control(ControlFrame) = 5,
1609    }
1610);
1611
1612impl_bare_newtype_union_enum!(
1613    RequestPayload,
1614    JsonRequestPayload,
1615    #[serde(tag = "type", rename_all = "snake_case")]
1616    {
1617        Authenticate(AuthenticateRequest) = 0,
1618        OpenSession(OpenSessionRequest) = 1,
1619        CreateVm(CreateVmRequest) = 2,
1620        DisposeVm(DisposeVmRequest) = 3,
1621        BootstrapRootFilesystem(BootstrapRootFilesystemRequest) = 4,
1622        ConfigureVm(ConfigureVmRequest) = 5,
1623        RegisterHostCallbacks(RegisterHostCallbacksRequest) = 6,
1624        CreateLayer(CreateLayerRequest) = 7,
1625        SealLayer(SealLayerRequest) = 8,
1626        ImportSnapshot(ImportSnapshotRequest) = 9,
1627        ExportSnapshot(ExportSnapshotRequest) = 10,
1628        CreateOverlay(CreateOverlayRequest) = 11,
1629        GuestFilesystemCall(GuestFilesystemCallRequest) = 12,
1630        SnapshotRootFilesystem(SnapshotRootFilesystemRequest) = 13,
1631        Execute(ExecuteRequest) = 14,
1632        WriteStdin(WriteStdinRequest) = 15,
1633        CloseStdin(CloseStdinRequest) = 16,
1634        KillProcess(KillProcessRequest) = 17,
1635        GetProcessSnapshot(GetProcessSnapshotRequest) = 18,
1636        FindListener(FindListenerRequest) = 19,
1637        FindBoundUdp(FindBoundUdpRequest) = 20,
1638        GetSignalState(GetSignalStateRequest) = 21,
1639        GetZombieTimerCount(GetZombieTimerCountRequest) = 22,
1640        HostFilesystemCall(HostFilesystemCallRequest) = 23,
1641        PersistenceLoad(PersistenceLoadRequest) = 24,
1642        PersistenceFlush(PersistenceFlushRequest) = 25,
1643        VmFetch(VmFetchRequest) = 26,
1644        Ext(ExtEnvelope) = 27,
1645        GuestKernelCall(GuestKernelCallRequest) = 28,
1646        ResizePty(ResizePtyRequest) = 29,
1647        GetResourceSnapshot(GetResourceSnapshotRequest) = 30,
1648        LinkPackage(LinkPackageRequest) = 31,
1649        ProvidedCommands(ProvidedCommandsRequest) = 32,
1650        ListMounts(ListMountsRequest) = 33,
1651    }
1652);
1653
1654impl_bare_newtype_union_enum!(
1655    ResponsePayload,
1656    JsonResponsePayload,
1657    #[serde(tag = "type", rename_all = "snake_case")]
1658    {
1659        Authenticated(AuthenticatedResponse) = 0,
1660        SessionOpened(SessionOpenedResponse) = 1,
1661        VmCreated(VmCreatedResponse) = 2,
1662        VmDisposed(VmDisposedResponse) = 3,
1663        RootFilesystemBootstrapped(RootFilesystemBootstrappedResponse) = 4,
1664        VmConfigured(VmConfiguredResponse) = 5,
1665        HostCallbacksRegistered(HostCallbacksRegisteredResponse) = 6,
1666        LayerCreated(LayerCreatedResponse) = 7,
1667        LayerSealed(LayerSealedResponse) = 8,
1668        SnapshotImported(SnapshotImportedResponse) = 9,
1669        SnapshotExported(SnapshotExportedResponse) = 10,
1670        OverlayCreated(OverlayCreatedResponse) = 11,
1671        GuestFilesystemResult(GuestFilesystemResultResponse) = 12,
1672        RootFilesystemSnapshot(RootFilesystemSnapshotResponse) = 13,
1673        ProcessStarted(ProcessStartedResponse) = 14,
1674        StdinWritten(StdinWrittenResponse) = 15,
1675        StdinClosed(StdinClosedResponse) = 16,
1676        ProcessKilled(ProcessKilledResponse) = 17,
1677        ProcessSnapshot(ProcessSnapshotResponse) = 18,
1678        ListenerSnapshot(ListenerSnapshotResponse) = 19,
1679        BoundUdpSnapshot(BoundUdpSnapshotResponse) = 20,
1680        SignalState(SignalStateResponse) = 21,
1681        ZombieTimerCount(ZombieTimerCountResponse) = 22,
1682        FilesystemResult(FilesystemResultResponse) = 23,
1683        PermissionDecision(PermissionDecisionResponse) = 24,
1684        PersistenceState(PersistenceStateResponse) = 25,
1685        PersistenceFlushed(PersistenceFlushedResponse) = 26,
1686        Rejected(RejectedResponse) = 27,
1687        VmFetchResult(VmFetchResponse) = 28,
1688        ExtResult(ExtEnvelope) = 29,
1689        GuestKernelResult(GuestKernelResultResponse) = 30,
1690        PtyResized(PtyResizedResponse) = 31,
1691        ResourceSnapshot(ResourceSnapshotResponse) = 32,
1692        PackageLinked(PackageLinkedResponse) = 33,
1693        ProvidedCommands(ProvidedCommandsResponse) = 34,
1694        MountsListed(ListMountsResponse) = 35,
1695    }
1696);
1697
1698impl_bare_newtype_union_enum!(
1699    SidecarRequestPayload,
1700    JsonSidecarRequestPayload,
1701    #[serde(tag = "type", rename_all = "snake_case")]
1702    {
1703        HostCallback(HostCallbackRequest) = 0,
1704        JsBridgeCall(JsBridgeCallRequest) = 1,
1705        Ext(ExtEnvelope) = 2,
1706    }
1707);
1708
1709impl_bare_newtype_union_enum!(
1710    SidecarResponsePayload,
1711    JsonSidecarResponsePayload,
1712    #[allow(clippy::enum_variant_names)]
1713    #[serde(tag = "type", rename_all = "snake_case")]
1714    {
1715        HostCallbackResult(HostCallbackResultResponse) = 0,
1716        JsBridgeResult(JsBridgeResultResponse) = 1,
1717        ExtResult(ExtEnvelope) = 2,
1718    }
1719);
1720
1721impl_bare_newtype_union_enum!(
1722    EventPayload,
1723    JsonEventPayload,
1724    #[serde(tag = "type", rename_all = "snake_case")]
1725    {
1726        VmLifecycle(VmLifecycleEvent) = 0,
1727        ProcessOutput(ProcessOutputEvent) = 1,
1728        ProcessExited(ProcessExitedEvent) = 2,
1729        Structured(StructuredEvent) = 3,
1730        Ext(ExtEnvelope) = 4,
1731    }
1732);
1733
1734fn serialize_payload(
1735    frame: &ProtocolFrame,
1736    payload_codec: NativePayloadCodec,
1737) -> Result<Vec<u8>, ProtocolCodecError> {
1738    match payload_codec {
1739        NativePayloadCodec::Json => serde_json::to_vec(frame)
1740            .map_err(|error| ProtocolCodecError::SerializeFailure(error.to_string())),
1741        NativePayloadCodec::Bare => serde_bare::to_vec(&to_generated_protocol_frame(frame)?)
1742            .map_err(|error| ProtocolCodecError::SerializeFailure(error.to_string())),
1743    }
1744}
1745
1746fn deserialize_payload(
1747    payload: &[u8],
1748    payload_codec: NativePayloadCodec,
1749) -> Result<ProtocolFrame, ProtocolCodecError> {
1750    match payload_codec {
1751        NativePayloadCodec::Json => serde_json::from_slice(payload)
1752            .map_err(|error| ProtocolCodecError::DeserializeFailure(error.to_string())),
1753        NativePayloadCodec::Bare => {
1754            let frame: generated_protocol::ProtocolFrame = serde_bare::from_slice(payload)
1755                .map_err(|error| ProtocolCodecError::DeserializeFailure(error.to_string()))?;
1756            from_generated_protocol_frame(frame)
1757        }
1758    }
1759}
1760
1761#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1762pub enum NativePayloadCodec {
1763    Json,
1764    Bare,
1765}
1766
1767impl NativePayloadCodec {
1768    pub fn sniff(payload: &[u8]) -> Self {
1769        match payload.first() {
1770            Some(b'{') => Self::Json,
1771            _ => Self::Bare,
1772        }
1773    }
1774
1775    pub fn alternate(self) -> Self {
1776        match self {
1777            Self::Json => Self::Bare,
1778            Self::Bare => Self::Json,
1779        }
1780    }
1781}
1782
1783#[derive(Debug, Clone)]
1784pub struct NativeFrameCodec {
1785    max_frame_bytes: usize,
1786    payload_codec: NativePayloadCodec,
1787}
1788
1789impl NativeFrameCodec {
1790    pub fn new(max_frame_bytes: usize) -> Self {
1791        Self::with_payload_codec(max_frame_bytes, NativePayloadCodec::Json)
1792    }
1793
1794    pub fn with_payload_codec(max_frame_bytes: usize, payload_codec: NativePayloadCodec) -> Self {
1795        Self {
1796            max_frame_bytes,
1797            payload_codec,
1798        }
1799    }
1800
1801    pub fn max_frame_bytes(&self) -> usize {
1802        self.max_frame_bytes
1803    }
1804
1805    pub fn payload_codec(&self) -> NativePayloadCodec {
1806        self.payload_codec
1807    }
1808
1809    pub fn encode(&self, frame: &ProtocolFrame) -> Result<Vec<u8>, ProtocolCodecError> {
1810        self.encode_with_codec(frame, self.payload_codec)
1811    }
1812
1813    pub fn encode_with_codec(
1814        &self,
1815        frame: &ProtocolFrame,
1816        payload_codec: NativePayloadCodec,
1817    ) -> Result<Vec<u8>, ProtocolCodecError> {
1818        validate_frame(frame)?;
1819
1820        let payload = serialize_payload(frame, payload_codec)?;
1821        if payload.len() > self.max_frame_bytes {
1822            return Err(ProtocolCodecError::FrameTooLarge {
1823                size: payload.len(),
1824                max: self.max_frame_bytes,
1825            });
1826        }
1827
1828        let length =
1829            u32::try_from(payload.len()).map_err(|_| ProtocolCodecError::FrameTooLarge {
1830                size: payload.len(),
1831                max: u32::MAX as usize,
1832            })?;
1833
1834        let mut encoded = Vec::with_capacity(4 + payload.len());
1835        encoded.extend_from_slice(&length.to_be_bytes());
1836        encoded.extend_from_slice(&payload);
1837        Ok(encoded)
1838    }
1839
1840    pub fn decode(&self, bytes: &[u8]) -> Result<ProtocolFrame, ProtocolCodecError> {
1841        self.decode_detected(bytes).map(|(frame, _)| frame)
1842    }
1843
1844    pub fn decode_with_codec(
1845        &self,
1846        bytes: &[u8],
1847        payload_codec: NativePayloadCodec,
1848    ) -> Result<ProtocolFrame, ProtocolCodecError> {
1849        let payload = self.checked_payload(bytes)?;
1850        let frame = deserialize_payload(payload, payload_codec)?;
1851        validate_frame(&frame)?;
1852        Ok(frame)
1853    }
1854
1855    pub fn decode_detected(
1856        &self,
1857        bytes: &[u8],
1858    ) -> Result<(ProtocolFrame, NativePayloadCodec), ProtocolCodecError> {
1859        let payload = self.checked_payload(bytes)?;
1860        let primary = NativePayloadCodec::sniff(payload);
1861
1862        match deserialize_payload(payload, primary) {
1863            Ok(frame) => {
1864                validate_frame(&frame)?;
1865                Ok((frame, primary))
1866            }
1867            Err(primary_error) => {
1868                let alternate = primary.alternate();
1869                let frame = deserialize_payload(payload, alternate).map_err(|_| primary_error)?;
1870                validate_frame(&frame)?;
1871                Ok((frame, alternate))
1872            }
1873        }
1874    }
1875
1876    fn checked_payload<'a>(&self, bytes: &'a [u8]) -> Result<&'a [u8], ProtocolCodecError> {
1877        if bytes.len() < 4 {
1878            return Err(ProtocolCodecError::TruncatedFrame {
1879                actual: bytes.len(),
1880            });
1881        }
1882
1883        let declared =
1884            u32::from_be_bytes(bytes[..4].try_into().expect("length prefix is four bytes"))
1885                as usize;
1886        if declared > self.max_frame_bytes {
1887            return Err(ProtocolCodecError::FrameTooLarge {
1888                size: declared,
1889                max: self.max_frame_bytes,
1890            });
1891        }
1892
1893        let actual = bytes.len() - 4;
1894        if declared != actual {
1895            return Err(ProtocolCodecError::LengthPrefixMismatch { declared, actual });
1896        }
1897        Ok(&bytes[4..])
1898    }
1899}
1900
1901impl Default for NativeFrameCodec {
1902    fn default() -> Self {
1903        Self::new(DEFAULT_MAX_FRAME_BYTES)
1904    }
1905}
1906
1907#[derive(Debug)]
1908pub struct ResponseTracker {
1909    pending: HashMap<RequestId, PendingRequest>,
1910    completed: HashSet<RequestId>,
1911    completed_order: VecDeque<RequestId>,
1912    completed_cap: usize,
1913}
1914
1915#[derive(Debug)]
1916pub struct SidecarResponseTracker {
1917    pending: HashMap<RequestId, PendingSidecarRequest>,
1918    completed: HashSet<RequestId>,
1919    completed_order: VecDeque<RequestId>,
1920    completed_cap: usize,
1921}
1922
1923impl ResponseTracker {
1924    pub fn with_completed_cap(completed_cap: usize) -> Self {
1925        Self {
1926            pending: HashMap::new(),
1927            completed: HashSet::new(),
1928            completed_order: VecDeque::new(),
1929            completed_cap: completed_cap.max(1),
1930        }
1931    }
1932
1933    pub fn completed_count(&self) -> usize {
1934        self.completed.len()
1935    }
1936
1937    pub fn register_request(&mut self, request: &RequestFrame) -> Result<(), ResponseTrackerError> {
1938        if self.pending.contains_key(&request.request_id)
1939            || self.completed.contains(&request.request_id)
1940        {
1941            return Err(ResponseTrackerError::DuplicateRequestId {
1942                request_id: request.request_id,
1943            });
1944        }
1945
1946        self.pending.insert(
1947            request.request_id,
1948            PendingRequest {
1949                ownership: request.ownership.clone(),
1950                expected_response: request.payload.expected_response(),
1951            },
1952        );
1953        Ok(())
1954    }
1955
1956    pub fn accept_response(
1957        &mut self,
1958        response: &ResponseFrame,
1959    ) -> Result<(), ResponseTrackerError> {
1960        if self.completed.contains(&response.request_id) {
1961            return Err(ResponseTrackerError::DuplicateResponse {
1962                request_id: response.request_id,
1963            });
1964        }
1965
1966        let pending = self.pending.get(&response.request_id).ok_or(
1967            ResponseTrackerError::UnmatchedResponse {
1968                request_id: response.request_id,
1969            },
1970        )?;
1971
1972        if pending.ownership != response.ownership {
1973            return Err(ResponseTrackerError::OwnershipMismatch {
1974                request_id: response.request_id,
1975                expected: Box::new(pending.ownership.clone()),
1976                actual: Box::new(response.ownership.clone()),
1977            });
1978        }
1979
1980        if !pending.expected_response.matches(&response.payload) {
1981            return Err(ResponseTrackerError::ResponseKindMismatch {
1982                request_id: response.request_id,
1983                expected: pending.expected_response.as_str().to_string(),
1984                actual: response.payload.kind_name().to_string(),
1985            });
1986        }
1987
1988        self.pending
1989            .remove(&response.request_id)
1990            .expect("pending response should still exist after validation");
1991        self.completed.insert(response.request_id);
1992        self.completed_order.push_back(response.request_id);
1993        while self.completed.len() > self.completed_cap {
1994            if let Some(evicted) = self.completed_order.pop_front() {
1995                self.completed.remove(&evicted);
1996            }
1997        }
1998        Ok(())
1999    }
2000}
2001
2002impl Default for ResponseTracker {
2003    fn default() -> Self {
2004        Self::with_completed_cap(DEFAULT_COMPLETED_RESPONSE_CAP)
2005    }
2006}
2007
2008impl SidecarResponseTracker {
2009    pub fn with_completed_cap(completed_cap: usize) -> Self {
2010        Self {
2011            pending: HashMap::new(),
2012            completed: HashSet::new(),
2013            completed_order: VecDeque::new(),
2014            completed_cap: completed_cap.max(1),
2015        }
2016    }
2017
2018    pub fn pending_count(&self) -> usize {
2019        self.pending.len()
2020    }
2021
2022    pub fn completed_count(&self) -> usize {
2023        self.completed.len()
2024    }
2025
2026    pub fn register_request(
2027        &mut self,
2028        request: &SidecarRequestFrame,
2029    ) -> Result<(), SidecarResponseTrackerError> {
2030        if self.pending.contains_key(&request.request_id)
2031            || self.completed.contains(&request.request_id)
2032        {
2033            return Err(SidecarResponseTrackerError::DuplicateRequestId {
2034                request_id: request.request_id,
2035            });
2036        }
2037
2038        self.pending.insert(
2039            request.request_id,
2040            PendingSidecarRequest {
2041                ownership: request.ownership.clone(),
2042                expected_response: request.payload.expected_response(),
2043            },
2044        );
2045        Ok(())
2046    }
2047
2048    pub fn accept_response(
2049        &mut self,
2050        response: &SidecarResponseFrame,
2051    ) -> Result<(), SidecarResponseTrackerError> {
2052        if self.completed.contains(&response.request_id) {
2053            return Err(SidecarResponseTrackerError::DuplicateResponse {
2054                request_id: response.request_id,
2055            });
2056        }
2057
2058        let pending = self.pending.get(&response.request_id).ok_or(
2059            SidecarResponseTrackerError::UnmatchedResponse {
2060                request_id: response.request_id,
2061            },
2062        )?;
2063
2064        if pending.ownership != response.ownership {
2065            return Err(SidecarResponseTrackerError::OwnershipMismatch {
2066                request_id: response.request_id,
2067                expected: Box::new(pending.ownership.clone()),
2068                actual: Box::new(response.ownership.clone()),
2069            });
2070        }
2071
2072        if !pending.expected_response.matches(&response.payload) {
2073            return Err(SidecarResponseTrackerError::ResponseKindMismatch {
2074                request_id: response.request_id,
2075                expected: pending.expected_response.as_str().to_string(),
2076                actual: response.payload.kind_name().to_string(),
2077            });
2078        }
2079
2080        self.pending
2081            .remove(&response.request_id)
2082            .expect("pending sidecar response should still exist after validation");
2083        self.completed.insert(response.request_id);
2084        self.completed_order.push_back(response.request_id);
2085        while self.completed.len() > self.completed_cap {
2086            if let Some(evicted) = self.completed_order.pop_front() {
2087                self.completed.remove(&evicted);
2088            }
2089        }
2090        Ok(())
2091    }
2092}
2093
2094impl Default for SidecarResponseTracker {
2095    fn default() -> Self {
2096        Self::with_completed_cap(DEFAULT_COMPLETED_RESPONSE_CAP)
2097    }
2098}
2099
2100#[derive(Debug, Clone, PartialEq, Eq)]
2101pub enum ResponseTrackerError {
2102    DuplicateRequestId {
2103        request_id: RequestId,
2104    },
2105    UnmatchedResponse {
2106        request_id: RequestId,
2107    },
2108    DuplicateResponse {
2109        request_id: RequestId,
2110    },
2111    OwnershipMismatch {
2112        request_id: RequestId,
2113        expected: Box<OwnershipScope>,
2114        actual: Box<OwnershipScope>,
2115    },
2116    ResponseKindMismatch {
2117        request_id: RequestId,
2118        expected: String,
2119        actual: String,
2120    },
2121}
2122
2123impl fmt::Display for ResponseTrackerError {
2124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2125        match self {
2126            Self::DuplicateRequestId { request_id } => {
2127                write!(f, "request id {request_id} is already tracked")
2128            }
2129            Self::UnmatchedResponse { request_id } => {
2130                write!(
2131                    f,
2132                    "response id {request_id} does not match any pending request"
2133                )
2134            }
2135            Self::DuplicateResponse { request_id } => {
2136                write!(f, "response id {request_id} has already been completed")
2137            }
2138            Self::OwnershipMismatch {
2139                request_id,
2140                expected,
2141                actual,
2142            } => write!(
2143                f,
2144                "response id {request_id} used ownership {:?}, expected {:?}",
2145                actual, expected
2146            ),
2147            Self::ResponseKindMismatch {
2148                request_id,
2149                expected,
2150                actual,
2151            } => write!(
2152                f,
2153                "response id {request_id} carried {actual}, expected {expected}",
2154            ),
2155        }
2156    }
2157}
2158
2159impl Error for ResponseTrackerError {}
2160
2161#[derive(Debug, Clone, PartialEq, Eq)]
2162pub enum SidecarResponseTrackerError {
2163    DuplicateRequestId {
2164        request_id: RequestId,
2165    },
2166    UnmatchedResponse {
2167        request_id: RequestId,
2168    },
2169    DuplicateResponse {
2170        request_id: RequestId,
2171    },
2172    OwnershipMismatch {
2173        request_id: RequestId,
2174        expected: Box<OwnershipScope>,
2175        actual: Box<OwnershipScope>,
2176    },
2177    ResponseKindMismatch {
2178        request_id: RequestId,
2179        expected: String,
2180        actual: String,
2181    },
2182}
2183
2184impl fmt::Display for SidecarResponseTrackerError {
2185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2186        match self {
2187            Self::DuplicateRequestId { request_id } => {
2188                write!(f, "sidecar request id {request_id} is already tracked")
2189            }
2190            Self::UnmatchedResponse { request_id } => {
2191                write!(
2192                    f,
2193                    "sidecar response id {request_id} does not match any pending request"
2194                )
2195            }
2196            Self::DuplicateResponse { request_id } => {
2197                write!(
2198                    f,
2199                    "sidecar response id {request_id} has already been completed"
2200                )
2201            }
2202            Self::OwnershipMismatch {
2203                request_id,
2204                expected,
2205                actual,
2206            } => write!(
2207                f,
2208                "sidecar response id {request_id} used ownership {:?}, expected {:?}",
2209                actual, expected
2210            ),
2211            Self::ResponseKindMismatch {
2212                request_id,
2213                expected,
2214                actual,
2215            } => write!(
2216                f,
2217                "sidecar response id {request_id} carried {actual}, expected {expected}",
2218            ),
2219        }
2220    }
2221}
2222
2223impl Error for SidecarResponseTrackerError {}
2224
2225#[derive(Debug, Clone, PartialEq, Eq)]
2226struct PendingRequest {
2227    ownership: OwnershipScope,
2228    expected_response: ExpectedResponseKind,
2229}
2230
2231#[derive(Debug, Clone, PartialEq, Eq)]
2232struct PendingSidecarRequest {
2233    ownership: OwnershipScope,
2234    expected_response: ExpectedSidecarResponseKind,
2235}
2236
2237#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2238enum ExpectedResponseKind {
2239    Authenticated,
2240    SessionOpened,
2241    VmCreated,
2242    VmDisposed,
2243    RootFilesystemBootstrapped,
2244    VmConfigured,
2245    HostCallbacksRegistered,
2246    LayerCreated,
2247    LayerSealed,
2248    SnapshotImported,
2249    SnapshotExported,
2250    OverlayCreated,
2251    GuestFilesystemResult,
2252    RootFilesystemSnapshot,
2253    ProcessStarted,
2254    StdinWritten,
2255    StdinClosed,
2256    ProcessKilled,
2257    ProcessSnapshot,
2258    ResourceSnapshot,
2259    ListenerSnapshot,
2260    BoundUdpSnapshot,
2261    VmFetchResult,
2262    SignalState,
2263    ZombieTimerCount,
2264    FilesystemResult,
2265    // `PermissionDecision` is a sidecar-initiated callback response, so no host
2266    // request maps to it in `expected_response_kind`; kept for protocol symmetry.
2267    #[allow(dead_code)]
2268    PermissionDecision,
2269    PersistenceState,
2270    PersistenceFlushed,
2271    ExtResult,
2272    GuestKernelResult,
2273    PtyResized,
2274    PackageLinked,
2275    ProvidedCommands,
2276    MountsListed,
2277}
2278
2279#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2280enum ExpectedSidecarResponseKind {
2281    HostCallback,
2282    JsBridge,
2283    Ext,
2284}
2285
2286impl ExpectedResponseKind {
2287    fn as_str(self) -> &'static str {
2288        match self {
2289            Self::Authenticated => "authenticated",
2290            Self::SessionOpened => "session_opened",
2291            Self::VmCreated => "vm_created",
2292            Self::VmDisposed => "vm_disposed",
2293            Self::RootFilesystemBootstrapped => "root_filesystem_bootstrapped",
2294            Self::VmConfigured => "vm_configured",
2295            Self::HostCallbacksRegistered => "host_callbacks_registered",
2296            Self::LayerCreated => "layer_created",
2297            Self::LayerSealed => "layer_sealed",
2298            Self::SnapshotImported => "snapshot_imported",
2299            Self::SnapshotExported => "snapshot_exported",
2300            Self::OverlayCreated => "overlay_created",
2301            Self::GuestFilesystemResult => "guest_filesystem_result",
2302            Self::RootFilesystemSnapshot => "root_filesystem_snapshot",
2303            Self::ProcessStarted => "process_started",
2304            Self::StdinWritten => "stdin_written",
2305            Self::StdinClosed => "stdin_closed",
2306            Self::ProcessKilled => "process_killed",
2307            Self::ProcessSnapshot => "process_snapshot",
2308            Self::ResourceSnapshot => "resource_snapshot",
2309            Self::ListenerSnapshot => "listener_snapshot",
2310            Self::BoundUdpSnapshot => "bound_udp_snapshot",
2311            Self::VmFetchResult => "vm_fetch_result",
2312            Self::SignalState => "signal_state",
2313            Self::ZombieTimerCount => "zombie_timer_count",
2314            Self::FilesystemResult => "filesystem_result",
2315            Self::PermissionDecision => "permission_decision",
2316            Self::PersistenceState => "persistence_state",
2317            Self::PersistenceFlushed => "persistence_flushed",
2318            Self::ExtResult => "ext_result",
2319            Self::GuestKernelResult => "guest_kernel_result",
2320            Self::PtyResized => "pty_resized",
2321            Self::PackageLinked => "package_linked",
2322            Self::ProvidedCommands => "provided_commands_response",
2323            Self::MountsListed => "mounts_listed",
2324        }
2325    }
2326
2327    fn matches(self, payload: &ResponsePayload) -> bool {
2328        match payload {
2329            ResponsePayload::Rejected(_) => true,
2330            _ => payload.kind_name() == self.as_str(),
2331        }
2332    }
2333}
2334
2335impl ExpectedSidecarResponseKind {
2336    fn as_str(self) -> &'static str {
2337        match self {
2338            Self::HostCallback => "host_callback_result",
2339            Self::JsBridge => "js_bridge_result",
2340            Self::Ext => "ext_result",
2341        }
2342    }
2343
2344    fn matches(self, payload: &SidecarResponsePayload) -> bool {
2345        payload.kind_name() == self.as_str()
2346    }
2347}
2348
2349impl RequestPayload {
2350    fn ownership_requirement(&self) -> OwnershipRequirement {
2351        match self {
2352            Self::Authenticate(_) | Self::OpenSession(_) => OwnershipRequirement::Connection,
2353            Self::CreateVm(_) | Self::PersistenceLoad(_) | Self::PersistenceFlush(_) => {
2354                OwnershipRequirement::Session
2355            }
2356            Self::DisposeVm(_)
2357            | Self::BootstrapRootFilesystem(_)
2358            | Self::ConfigureVm(_)
2359            | Self::RegisterHostCallbacks(_)
2360            | Self::CreateLayer(_)
2361            | Self::SealLayer(_)
2362            | Self::ImportSnapshot(_)
2363            | Self::ExportSnapshot(_)
2364            | Self::CreateOverlay(_)
2365            | Self::GuestFilesystemCall(_)
2366            | Self::SnapshotRootFilesystem(_)
2367            | Self::ListMounts(_)
2368            | Self::Execute(_)
2369            | Self::WriteStdin(_)
2370            | Self::CloseStdin(_)
2371            | Self::KillProcess(_)
2372            | Self::GetProcessSnapshot(_)
2373            | Self::GetResourceSnapshot(_)
2374            | Self::FindListener(_)
2375            | Self::FindBoundUdp(_)
2376            | Self::VmFetch(_)
2377            | Self::GetSignalState(_)
2378            | Self::GetZombieTimerCount(_)
2379            | Self::GuestKernelCall(_)
2380            | Self::ResizePty(_)
2381            | Self::LinkPackage(_)
2382            | Self::ProvidedCommands(_)
2383            | Self::HostFilesystemCall(_) => OwnershipRequirement::Vm,
2384            Self::Ext(_) => OwnershipRequirement::Any,
2385        }
2386    }
2387
2388    fn expected_response(&self) -> ExpectedResponseKind {
2389        match self {
2390            Self::Authenticate(_) => ExpectedResponseKind::Authenticated,
2391            Self::OpenSession(_) => ExpectedResponseKind::SessionOpened,
2392            Self::CreateVm(_) => ExpectedResponseKind::VmCreated,
2393            Self::DisposeVm(_) => ExpectedResponseKind::VmDisposed,
2394            Self::BootstrapRootFilesystem(_) => ExpectedResponseKind::RootFilesystemBootstrapped,
2395            Self::ConfigureVm(_) => ExpectedResponseKind::VmConfigured,
2396            Self::RegisterHostCallbacks(_) => ExpectedResponseKind::HostCallbacksRegistered,
2397            Self::CreateLayer(_) => ExpectedResponseKind::LayerCreated,
2398            Self::SealLayer(_) => ExpectedResponseKind::LayerSealed,
2399            Self::ImportSnapshot(_) => ExpectedResponseKind::SnapshotImported,
2400            Self::ExportSnapshot(_) => ExpectedResponseKind::SnapshotExported,
2401            Self::CreateOverlay(_) => ExpectedResponseKind::OverlayCreated,
2402            Self::GuestFilesystemCall(_) => ExpectedResponseKind::GuestFilesystemResult,
2403            Self::SnapshotRootFilesystem(_) => ExpectedResponseKind::RootFilesystemSnapshot,
2404            Self::ListMounts(_) => ExpectedResponseKind::MountsListed,
2405            Self::Execute(_) => ExpectedResponseKind::ProcessStarted,
2406            Self::WriteStdin(_) => ExpectedResponseKind::StdinWritten,
2407            Self::CloseStdin(_) => ExpectedResponseKind::StdinClosed,
2408            Self::KillProcess(_) => ExpectedResponseKind::ProcessKilled,
2409            Self::GetProcessSnapshot(_) => ExpectedResponseKind::ProcessSnapshot,
2410            Self::GetResourceSnapshot(_) => ExpectedResponseKind::ResourceSnapshot,
2411            Self::FindListener(_) => ExpectedResponseKind::ListenerSnapshot,
2412            Self::FindBoundUdp(_) => ExpectedResponseKind::BoundUdpSnapshot,
2413            Self::VmFetch(_) => ExpectedResponseKind::VmFetchResult,
2414            Self::GetSignalState(_) => ExpectedResponseKind::SignalState,
2415            Self::GetZombieTimerCount(_) => ExpectedResponseKind::ZombieTimerCount,
2416            Self::HostFilesystemCall(_) => ExpectedResponseKind::FilesystemResult,
2417            Self::PersistenceLoad(_) => ExpectedResponseKind::PersistenceState,
2418            Self::PersistenceFlush(_) => ExpectedResponseKind::PersistenceFlushed,
2419            Self::Ext(_) => ExpectedResponseKind::ExtResult,
2420            Self::GuestKernelCall(_) => ExpectedResponseKind::GuestKernelResult,
2421            Self::ResizePty(_) => ExpectedResponseKind::PtyResized,
2422            Self::LinkPackage(_) => ExpectedResponseKind::PackageLinked,
2423            Self::ProvidedCommands(_) => ExpectedResponseKind::ProvidedCommands,
2424        }
2425    }
2426}
2427
2428impl SidecarRequestPayload {
2429    fn ownership_requirement(&self) -> OwnershipRequirement {
2430        OwnershipRequirement::Vm
2431    }
2432
2433    fn expected_response(&self) -> ExpectedSidecarResponseKind {
2434        match self {
2435            Self::HostCallback(_) => ExpectedSidecarResponseKind::HostCallback,
2436            Self::JsBridgeCall(_) => ExpectedSidecarResponseKind::JsBridge,
2437            Self::Ext(_) => ExpectedSidecarResponseKind::Ext,
2438        }
2439    }
2440}
2441
2442impl ResponsePayload {
2443    fn ownership_requirement(&self) -> OwnershipRequirement {
2444        match self {
2445            Self::Authenticated(_) | Self::SessionOpened(_) => OwnershipRequirement::Connection,
2446            Self::VmCreated(_) | Self::PersistenceState(_) | Self::PersistenceFlushed(_) => {
2447                OwnershipRequirement::Session
2448            }
2449            Self::Rejected(_) => OwnershipRequirement::Any,
2450            Self::VmDisposed(_)
2451            | Self::RootFilesystemBootstrapped(_)
2452            | Self::VmConfigured(_)
2453            | Self::HostCallbacksRegistered(_)
2454            | Self::LayerCreated(_)
2455            | Self::LayerSealed(_)
2456            | Self::SnapshotImported(_)
2457            | Self::SnapshotExported(_)
2458            | Self::OverlayCreated(_)
2459            | Self::GuestFilesystemResult(_)
2460            | Self::RootFilesystemSnapshot(_)
2461            | Self::MountsListed(_)
2462            | Self::ProcessStarted(_)
2463            | Self::StdinWritten(_)
2464            | Self::StdinClosed(_)
2465            | Self::ProcessKilled(_)
2466            | Self::ProcessSnapshot(_)
2467            | Self::ResourceSnapshot(_)
2468            | Self::ListenerSnapshot(_)
2469            | Self::BoundUdpSnapshot(_)
2470            | Self::VmFetchResult(_)
2471            | Self::SignalState(_)
2472            | Self::ZombieTimerCount(_)
2473            | Self::FilesystemResult(_)
2474            | Self::PermissionDecision(_)
2475            | Self::GuestKernelResult(_)
2476            | Self::PtyResized(_)
2477            | Self::PackageLinked(_)
2478            | Self::ProvidedCommands(_) => OwnershipRequirement::Vm,
2479            Self::ExtResult(_) => OwnershipRequirement::Any,
2480        }
2481    }
2482
2483    fn kind_name(&self) -> &'static str {
2484        match self {
2485            Self::Authenticated(_) => "authenticated",
2486            Self::SessionOpened(_) => "session_opened",
2487            Self::VmCreated(_) => "vm_created",
2488            Self::VmDisposed(_) => "vm_disposed",
2489            Self::RootFilesystemBootstrapped(_) => "root_filesystem_bootstrapped",
2490            Self::VmConfigured(_) => "vm_configured",
2491            Self::HostCallbacksRegistered(_) => "host_callbacks_registered",
2492            Self::LayerCreated(_) => "layer_created",
2493            Self::LayerSealed(_) => "layer_sealed",
2494            Self::SnapshotImported(_) => "snapshot_imported",
2495            Self::SnapshotExported(_) => "snapshot_exported",
2496            Self::OverlayCreated(_) => "overlay_created",
2497            Self::GuestFilesystemResult(_) => "guest_filesystem_result",
2498            Self::RootFilesystemSnapshot(_) => "root_filesystem_snapshot",
2499            Self::MountsListed(_) => "mounts_listed",
2500            Self::ProcessStarted(_) => "process_started",
2501            Self::StdinWritten(_) => "stdin_written",
2502            Self::StdinClosed(_) => "stdin_closed",
2503            Self::ProcessKilled(_) => "process_killed",
2504            Self::ProcessSnapshot(_) => "process_snapshot",
2505            Self::ResourceSnapshot(_) => "resource_snapshot",
2506            Self::ListenerSnapshot(_) => "listener_snapshot",
2507            Self::BoundUdpSnapshot(_) => "bound_udp_snapshot",
2508            Self::VmFetchResult(_) => "vm_fetch_result",
2509            Self::SignalState(_) => "signal_state",
2510            Self::ZombieTimerCount(_) => "zombie_timer_count",
2511            Self::FilesystemResult(_) => "filesystem_result",
2512            Self::PermissionDecision(_) => "permission_decision",
2513            Self::PersistenceState(_) => "persistence_state",
2514            Self::PersistenceFlushed(_) => "persistence_flushed",
2515            Self::Rejected(_) => "rejected",
2516            Self::ExtResult(_) => "ext_result",
2517            Self::GuestKernelResult(_) => "guest_kernel_result",
2518            Self::PtyResized(_) => "pty_resized",
2519            Self::PackageLinked(_) => "package_linked",
2520            Self::ProvidedCommands(_) => "provided_commands_response",
2521        }
2522    }
2523}
2524
2525impl SidecarResponsePayload {
2526    fn ownership_requirement(&self) -> OwnershipRequirement {
2527        OwnershipRequirement::Vm
2528    }
2529
2530    fn kind_name(&self) -> &'static str {
2531        match self {
2532            Self::HostCallbackResult(_) => "host_callback_result",
2533            Self::JsBridgeResult(_) => "js_bridge_result",
2534            Self::ExtResult(_) => "ext_result",
2535        }
2536    }
2537}
2538
2539impl EventPayload {
2540    fn ownership_requirement(&self) -> OwnershipRequirement {
2541        match self {
2542            Self::Structured(_) => OwnershipRequirement::SessionOrVm,
2543            Self::VmLifecycle(_) | Self::ProcessOutput(_) | Self::ProcessExited(_) => {
2544                OwnershipRequirement::Vm
2545            }
2546            Self::Ext(_) => OwnershipRequirement::Any,
2547        }
2548    }
2549}
2550
2551pub fn validate_frame(frame: &ProtocolFrame) -> Result<(), ProtocolCodecError> {
2552    match frame {
2553        ProtocolFrame::Request(request) => validate_request(request),
2554        ProtocolFrame::Response(response) => validate_response(response),
2555        ProtocolFrame::Event(event) => validate_event(event),
2556        ProtocolFrame::SidecarRequest(request) => validate_sidecar_request(request),
2557        ProtocolFrame::SidecarResponse(response) => validate_sidecar_response(response),
2558        ProtocolFrame::Control(control) => validate_schema(&control.schema),
2559    }
2560}
2561
2562fn validate_request(request: &RequestFrame) -> Result<(), ProtocolCodecError> {
2563    validate_schema(&request.schema)?;
2564    validate_request_id_direction(request.request_id, RequestDirection::Host)?;
2565
2566    validate_ownership(&request.ownership)?;
2567    validate_requirement(request.payload.ownership_requirement(), &request.ownership)?;
2568    if let RequestPayload::Authenticate(authenticate) = &request.payload {
2569        if authenticate.auth_token.is_empty() {
2570            return Err(ProtocolCodecError::EmptyAuthToken);
2571        }
2572    }
2573
2574    Ok(())
2575}
2576
2577fn validate_response(response: &ResponseFrame) -> Result<(), ProtocolCodecError> {
2578    validate_schema(&response.schema)?;
2579    validate_request_id_direction(response.request_id, RequestDirection::Host)?;
2580
2581    validate_ownership(&response.ownership)?;
2582    validate_requirement(
2583        response.payload.ownership_requirement(),
2584        &response.ownership,
2585    )?;
2586    Ok(())
2587}
2588
2589fn validate_sidecar_request(request: &SidecarRequestFrame) -> Result<(), ProtocolCodecError> {
2590    validate_schema(&request.schema)?;
2591    validate_request_id_direction(request.request_id, RequestDirection::Sidecar)?;
2592    validate_ownership(&request.ownership)?;
2593    validate_requirement(request.payload.ownership_requirement(), &request.ownership)?;
2594    Ok(())
2595}
2596
2597fn validate_sidecar_response(response: &SidecarResponseFrame) -> Result<(), ProtocolCodecError> {
2598    validate_schema(&response.schema)?;
2599    validate_request_id_direction(response.request_id, RequestDirection::Sidecar)?;
2600    validate_ownership(&response.ownership)?;
2601    validate_requirement(
2602        response.payload.ownership_requirement(),
2603        &response.ownership,
2604    )?;
2605    Ok(())
2606}
2607
2608fn validate_event(event: &EventFrame) -> Result<(), ProtocolCodecError> {
2609    validate_schema(&event.schema)?;
2610    validate_ownership(&event.ownership)?;
2611    validate_requirement(event.payload.ownership_requirement(), &event.ownership)?;
2612    Ok(())
2613}
2614
2615fn validate_schema(schema: &ProtocolSchema) -> Result<(), ProtocolCodecError> {
2616    if schema.name != PROTOCOL_NAME || schema.version != PROTOCOL_VERSION {
2617        return Err(ProtocolCodecError::UnsupportedSchema {
2618            name: schema.name.clone(),
2619            version: schema.version,
2620        });
2621    }
2622
2623    Ok(())
2624}
2625
2626fn validate_ownership(ownership: &OwnershipScope) -> Result<(), ProtocolCodecError> {
2627    match ownership {
2628        OwnershipScope::ConnectionOwnership(inner) => {
2629            validate_non_empty("connection_id", &inner.connection_id)
2630        }
2631        OwnershipScope::SessionOwnership(inner) => {
2632            validate_non_empty("connection_id", &inner.connection_id)?;
2633            validate_non_empty("session_id", &inner.session_id)
2634        }
2635        OwnershipScope::VmOwnership(inner) => {
2636            validate_non_empty("connection_id", &inner.connection_id)?;
2637            validate_non_empty("session_id", &inner.session_id)?;
2638            validate_non_empty("vm_id", &inner.vm_id)
2639        }
2640    }
2641}
2642
2643fn validate_non_empty(field: &'static str, value: &str) -> Result<(), ProtocolCodecError> {
2644    if value.is_empty() {
2645        return Err(ProtocolCodecError::EmptyOwnershipField { field });
2646    }
2647
2648    Ok(())
2649}
2650
2651fn validate_request_id_direction(
2652    request_id: RequestId,
2653    direction: RequestDirection,
2654) -> Result<(), ProtocolCodecError> {
2655    if request_id == 0 {
2656        return Err(ProtocolCodecError::InvalidRequestId);
2657    }
2658
2659    let matches_direction = match direction {
2660        RequestDirection::Host => request_id > 0,
2661        RequestDirection::Sidecar => request_id < 0,
2662    };
2663    if matches_direction {
2664        Ok(())
2665    } else {
2666        Err(ProtocolCodecError::InvalidRequestDirection {
2667            request_id,
2668            expected: direction,
2669        })
2670    }
2671}
2672
2673fn validate_requirement(
2674    required: OwnershipRequirement,
2675    ownership: &OwnershipScope,
2676) -> Result<(), ProtocolCodecError> {
2677    let actual = match ownership {
2678        OwnershipScope::ConnectionOwnership(..) => OwnershipRequirement::Connection,
2679        OwnershipScope::SessionOwnership(..) => OwnershipRequirement::Session,
2680        OwnershipScope::VmOwnership(..) => OwnershipRequirement::Vm,
2681    };
2682
2683    let valid = match required {
2684        OwnershipRequirement::Any => true,
2685        OwnershipRequirement::Connection => {
2686            matches!(ownership, OwnershipScope::ConnectionOwnership(..))
2687        }
2688        OwnershipRequirement::Session => matches!(ownership, OwnershipScope::SessionOwnership(..)),
2689        OwnershipRequirement::Vm => matches!(ownership, OwnershipScope::VmOwnership(..)),
2690        OwnershipRequirement::SessionOrVm => {
2691            matches!(
2692                ownership,
2693                OwnershipScope::SessionOwnership(..) | OwnershipScope::VmOwnership(..)
2694            )
2695        }
2696    };
2697
2698    if valid {
2699        Ok(())
2700    } else {
2701        Err(ProtocolCodecError::InvalidOwnershipScope { required, actual })
2702    }
2703}
2704
2705// ---------------------------------------------------------------------------
2706// JavaScript sync-RPC request types (deserialized from guest Node.js processes)
2707// ---------------------------------------------------------------------------
2708
2709#[derive(Debug, Clone, Deserialize)]
2710pub struct JavascriptPosixSpawnFileAction {
2711    pub command: u32,
2712    #[serde(rename = "guestFd", default)]
2713    pub guest_fd: Option<i32>,
2714    pub fd: i32,
2715    #[serde(rename = "sourceFd")]
2716    pub source_fd: i32,
2717    #[serde(rename = "guestSourceFd", default)]
2718    pub guest_source_fd: Option<i32>,
2719    pub oflag: i32,
2720    pub mode: u32,
2721    pub path: String,
2722    /// Runner-local public guest descriptors selected by closefrom. These do
2723    /// not have kernel mappings, but the child bootstrap must still suppress
2724    /// their untagged aliases while retaining private tagged preopens.
2725    #[serde(rename = "closeFromGuestFds", default)]
2726    pub close_from_guest_fds: Vec<u32>,
2727}
2728
2729#[derive(Debug, Clone, Deserialize, Serialize)]
2730#[serde(rename_all = "camelCase")]
2731pub struct JavascriptSpawnHostNetFd {
2732    pub guest_fd: u32,
2733    #[serde(default)]
2734    pub close_on_exec: bool,
2735    #[serde(default)]
2736    pub socket_id: Option<String>,
2737    #[serde(default)]
2738    pub server_id: Option<String>,
2739    #[serde(default)]
2740    pub udp_socket_id: Option<String>,
2741    /// Runner-visible socket metadata needed to reconstruct the libc-facing
2742    /// descriptor in the child. Resource ownership is never trusted from this
2743    /// object: the sidecar resolves and clones the named parent resource.
2744    #[serde(default)]
2745    pub metadata: Value,
2746}
2747
2748#[derive(Debug, Deserialize, Default)]
2749pub struct JavascriptChildProcessPtyOptions {
2750    #[serde(default)]
2751    pub cols: Option<u16>,
2752    #[serde(default)]
2753    pub rows: Option<u16>,
2754}
2755
2756#[derive(Debug, Deserialize, Default)]
2757pub struct JavascriptChildProcessSpawnOptions {
2758    #[serde(default)]
2759    pub argv0: Option<String>,
2760    /// Guest descriptors marked FD_CLOEXEC in libc's runner-local descriptor
2761    /// table. Native exec applies these at the same commit point as the kernel
2762    /// table; runner-local handles are closed by the in-place image swap.
2763    #[serde(rename = "cloexecFds", default)]
2764    pub cloexec_fds: Vec<u32>,
2765    /// The sidecar-managed WASM runner has already validated the replacement
2766    /// module and will swap images in place after the sidecar commits kernel
2767    /// metadata. Other process.exec callers use the separate-execution path.
2768    #[serde(rename = "localReplacement", default)]
2769    pub local_replacement: bool,
2770    /// Runner-private executable descriptor used only by the dedicated
2771    /// process.exec_fd_image_commit route. Generic guest process.exec requests
2772    /// cannot turn this into an FD-backed replacement.
2773    #[serde(rename = "executableFd", default)]
2774    pub executable_fd: Option<u32>,
2775    #[serde(default)]
2776    pub cwd: Option<String>,
2777    #[serde(default)]
2778    pub env: BTreeMap<String, String>,
2779    #[serde(rename = "internalBootstrapEnv", default)]
2780    pub internal_bootstrap_env: BTreeMap<String, String>,
2781    /// POSIX spawn attributes already validated by the WASM host-import
2782    /// boundary. The sidecar validates them again before applying attributes
2783    /// that belong to the kernel process table.
2784    #[serde(rename = "spawnAttrFlags", default)]
2785    pub spawn_attr_flags: u32,
2786    /// Exact `posix_spawn` bypasses PATH lookup, including for bare names.
2787    #[serde(rename = "spawnExactPath", default)]
2788    pub spawn_exact_path: bool,
2789    /// `posix_spawnp` uses the caller's PATH, which can differ from envp.
2790    #[serde(rename = "spawnSearchPath", default)]
2791    pub spawn_search_path: Option<String>,
2792    #[serde(rename = "spawnSchedPolicy", default)]
2793    pub spawn_sched_policy: Option<i32>,
2794    #[serde(rename = "spawnSchedPriority", default)]
2795    pub spawn_sched_priority: Option<i32>,
2796    #[serde(rename = "spawnPgroup", default)]
2797    pub spawn_pgroup: Option<i32>,
2798    #[serde(rename = "spawnSignalDefaults", default)]
2799    pub spawn_signal_defaults: Vec<u32>,
2800    #[serde(rename = "spawnSignalMask", default)]
2801    pub spawn_signal_mask: Vec<u32>,
2802    #[serde(rename = "spawnFileActions", default)]
2803    pub spawn_file_actions: Vec<JavascriptPosixSpawnFileAction>,
2804    /// Guest-to-kernel descriptor namespace captured by the WASM runner at
2805    /// spawn time. WASI preopens occupy guest descriptors that do not exist in
2806    /// the kernel table, so file actions cannot safely assume the two numeric
2807    /// namespaces are identical.
2808    #[serde(rename = "spawnFdMappings", default)]
2809    pub spawn_fd_mappings: Vec<[u32; 2]>,
2810    /// Host-network descriptors occupy the guest fd namespace but are backed
2811    /// by sidecar-owned socket descriptions rather than kernel fd-table slots.
2812    /// They must therefore be inherited explicitly instead of being coerced
2813    /// into the private kernel descriptor namespace.
2814    #[serde(rename = "spawnHostNetFds", default)]
2815    pub spawn_host_net_fds: Vec<JavascriptSpawnHostNetFd>,
2816    #[serde(default)]
2817    pub input: Option<Value>,
2818    #[serde(default)]
2819    pub shell: bool,
2820    #[serde(default)]
2821    pub detached: bool,
2822    #[serde(default)]
2823    pub stdio: Vec<String>,
2824    #[serde(default)]
2825    pub timeout: Option<u64>,
2826    #[serde(rename = "killSignal", default)]
2827    pub kill_signal: Option<String>,
2828    #[serde(default)]
2829    pub pty: Option<JavascriptChildProcessPtyOptions>,
2830}
2831
2832#[derive(Debug, Deserialize)]
2833pub struct JavascriptChildProcessSpawnRequest {
2834    pub command: String,
2835    #[serde(default)]
2836    pub args: Vec<String>,
2837    #[serde(default)]
2838    pub options: JavascriptChildProcessSpawnOptions,
2839}
2840
2841#[derive(Debug, Deserialize)]
2842pub struct JavascriptNetConnectRequest {
2843    #[serde(default)]
2844    pub host: Option<String>,
2845    #[serde(default)]
2846    pub port: Option<u16>,
2847    #[serde(default)]
2848    pub family: Option<u8>,
2849    #[serde(default)]
2850    pub path: Option<String>,
2851    #[serde(rename = "abstractPathHex", default)]
2852    pub abstract_path_hex: Option<String>,
2853    #[serde(rename = "boundServerId", default)]
2854    pub bound_server_id: Option<String>,
2855    #[serde(rename = "localAddress", default)]
2856    pub local_address: Option<String>,
2857    #[serde(rename = "localPort", default)]
2858    pub local_port: Option<u16>,
2859    #[serde(rename = "localReservation", default)]
2860    pub local_reservation: Option<String>,
2861}
2862
2863#[derive(Debug, Deserialize)]
2864pub struct JavascriptNetBindConnectedUnixRequest {
2865    #[serde(rename = "socketId")]
2866    pub socket_id: String,
2867    #[serde(default)]
2868    pub path: Option<String>,
2869    #[serde(rename = "abstractPathHex", default)]
2870    pub abstract_path_hex: Option<String>,
2871    #[serde(default)]
2872    pub autobind: bool,
2873}
2874
2875#[derive(Debug, Deserialize)]
2876pub struct JavascriptNetReserveTcpPortRequest {
2877    #[serde(default)]
2878    pub host: Option<String>,
2879    #[serde(default)]
2880    pub port: Option<u16>,
2881}
2882
2883#[derive(Debug, Deserialize)]
2884pub struct JavascriptNetListenRequest {
2885    #[serde(default)]
2886    pub host: Option<String>,
2887    #[serde(default)]
2888    pub port: Option<u16>,
2889    #[serde(default)]
2890    pub path: Option<String>,
2891    #[serde(rename = "abstractPathHex", default)]
2892    pub abstract_path_hex: Option<String>,
2893    #[serde(rename = "boundServerId", default)]
2894    pub bound_server_id: Option<String>,
2895    #[serde(default)]
2896    pub autobind: bool,
2897    #[serde(default)]
2898    pub backlog: Option<u32>,
2899    #[serde(rename = "localReservation", default)]
2900    pub local_reservation: Option<String>,
2901}
2902
2903#[derive(Debug, Deserialize)]
2904pub struct JavascriptDgramCreateSocketRequest {
2905    #[serde(rename = "type")]
2906    pub socket_type: String,
2907}
2908
2909#[derive(Debug, Deserialize)]
2910pub struct JavascriptDgramBindRequest {
2911    #[serde(default)]
2912    pub address: Option<String>,
2913    #[serde(default)]
2914    pub port: u16,
2915}
2916
2917#[derive(Debug, Deserialize)]
2918pub struct JavascriptDgramSendRequest {
2919    #[serde(default)]
2920    pub address: Option<String>,
2921    #[serde(default)]
2922    pub port: Option<u16>,
2923}
2924
2925#[derive(Debug, Deserialize)]
2926pub struct JavascriptDgramConnectRequest {
2927    #[serde(default)]
2928    pub address: Option<String>,
2929    pub port: u16,
2930}
2931
2932#[derive(Debug, Deserialize)]
2933pub struct JavascriptDnsLookupRequest {
2934    pub hostname: String,
2935    #[serde(default)]
2936    pub family: Option<u8>,
2937}
2938
2939#[derive(Debug, Deserialize)]
2940pub struct JavascriptDnsResolveRequest {
2941    pub hostname: String,
2942    #[serde(default)]
2943    pub rrtype: Option<String>,
2944}