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