1#![allow(non_upper_case_globals)]
2use crate::config::Config;
3use bitflags::bitflags;
4use bytes::{Bytes, BytesMut};
5use num_traits::FromPrimitive;
6use serde::{de::DeserializeOwned, Deserialize, Serialize};
7use serde_cbor::Value;
8use std::collections::{BTreeMap, BTreeSet};
9use std::convert::{TryFrom, TryInto};
10use std::fmt;
11use std::io;
12use std::io::{Seek, SeekFrom};
13
14#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
60pub enum ResponseCode {
61 Success = 0x00000000,
63 Continuation = 0x00000001,
66
67 NeedsAuthentication = 0x00010000,
71 Forbidden = 0x00010001,
75 Closing = 0x00010002,
77 Errno = 0x00010003,
81 AuthenticationFailed = 0x00010004,
82 Gone = 0x00010005,
84 NotFound = 0x00010006,
85 InternalError = 0x00010007,
86 ChannelDead = 0x00010008,
88 Aborted = 0x00010009,
90 ContinuationNotFound = 0x0001000a,
92 OutOfRange = 0x0001000b,
96 NoSpace = 0x0001000c,
98 Conflict = 0x0001000d,
102 Unlistable = 0x0001000e,
107
108 NotEnabled = 0x00020000,
110 NotSupported = 0x00020001,
112 ParametersNotSupported = 0x00020002,
114 Invalid = 0x00020003,
116 TooLarge = 0x00020004,
118 TooManyMessages = 0x00020005,
120 InvalidParameters = 0x00020006,
124}
125
126impl ResponseCode {
127 fn from_u32(val: u32) -> Self {
128 FromPrimitive::from_u32(val).unwrap_or(Self::Invalid)
129 }
130}
131
132pub struct WrongTypeError(pub Error);
133
134#[derive(Debug, Clone)]
135pub struct Error {
136 pub code: ResponseCode,
137 pub body: Option<ErrorBody>,
138}
139
140impl fmt::Display for Error {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
142 fmt::Debug::fmt(self, f)
143 }
144}
145
146impl std::error::Error for Error {}
147
148impl Error {
149 pub fn from_errno(err: i32) -> Error {
150 io::Error::from_raw_os_error(err).into()
151 }
152}
153
154impl From<io::Error> for Error {
155 fn from(err: io::Error) -> Error {
156 let lerr: lawn_constants::Error = err.into();
157 Error {
158 code: ResponseCode::Errno,
159 body: Some(ErrorBody::Errno(Errno { errno: lerr as u32 })),
160 }
161 }
162}
163
164impl From<ResponseCode> for Error {
165 fn from(code: ResponseCode) -> Error {
166 Error { code, body: None }
167 }
168}
169
170impl TryInto<io::Error> for Error {
171 type Error = WrongTypeError;
172 fn try_into(self) -> Result<io::Error, Self::Error> {
173 if self.code == ResponseCode::Errno {
174 if let Some(ErrorBody::Errno(Errno { errno })) = self.body {
175 if let Some(e) = lawn_constants::Error::from_u32(errno) {
176 return Ok(e.into());
177 }
178 }
179 }
180 Err(WrongTypeError(self))
181 }
182}
183
184#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
185pub struct Empty {}
186
187#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
188pub struct Errno {
189 errno: u32,
190}
191
192#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
193#[serde(untagged)]
194pub enum ErrorBody {
195 Errno(Errno),
196 Exit(i32),
197}
198
199#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
200pub enum MessageKind {
201 Capability = 0x00000000,
203 Version = 0x00000001,
210 Ping = 0x00000002,
214 Authenticate = 0x00000003,
221 Continue = 0x00000004,
226 Abort = 0x00000005,
231
232 CloseAlert = 0x00001000,
236
237 CreateChannel = 0x00010000,
239 DeleteChannel = 0x00010001,
243 ReadChannel = 0x00010002,
245 WriteChannel = 0x00010003,
247 PollChannel = 0x00010004,
249 PingChannel = 0x00010005,
253 DetachChannelSelector = 0x00010011,
256 ChannelMetadataNotification = 0x00011000,
261
262 CreateExtensionRange = 0x00020000,
264
265 DeleteExtensionRange = 0x00020001,
267
268 ListExtensionRanges = 0x00020002,
270
271 OpenStore = 0x00030000,
273
274 CloseStore = 0x00030001,
276
277 ListStoreElements = 0x00030002,
279
280 AcquireStoreElement = 0x00030003,
282
283 CloseStoreElement = 0x00030004,
285
286 AuthenticateStoreElement = 0x00030005,
288
289 CreateStoreElement = 0x00030006,
291
292 DeleteStoreElement = 0x00030007,
294
295 UpdateStoreElement = 0x00030008,
297
298 ReadStoreElement = 0x00030009,
300
301 RenameStoreElement = 0x0003000a,
303
304 CopyStoreElement = 0x0003000b,
306
307 SearchStoreElements = 0x0003000c,
309
310 ReadServerContext = 0x00040000,
312
313 WriteServerContext = 0x00040001,
315}
316
317#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
318pub enum Capability {
319 AuthExternal,
320 AuthKeyboardInteractive,
321 AuthPlain,
322 ChannelCommand,
323 Channel9P,
324 ChannelSFTP,
325 ChannelClipboard,
326 ExtensionAllocate,
327 StoreCredential,
328 ContextTemplate,
329 Other(Bytes, Option<Bytes>),
330}
331
332impl Capability {
333 #[allow(clippy::mutable_key_type)]
334 pub fn implemented() -> BTreeSet<Capability> {
335 [
336 Self::AuthExternal,
337 Self::AuthKeyboardInteractive,
338 Self::AuthPlain,
339 Self::ChannelCommand,
340 Self::ChannelClipboard,
341 Self::Channel9P,
342 Self::ChannelSFTP,
343 Self::ExtensionAllocate,
344 Self::StoreCredential,
345 Self::ContextTemplate,
346 ]
347 .iter()
348 .cloned()
349 .collect()
350 }
351
352 pub fn is_implemented(&self) -> bool {
353 matches!(
354 self,
355 Self::AuthExternal
356 | Self::AuthKeyboardInteractive
357 | Self::AuthPlain
358 | Self::ChannelCommand
359 | Self::ChannelClipboard
360 | Self::Channel9P
361 | Self::ChannelSFTP
362 | Self::ExtensionAllocate
363 | Self::StoreCredential
364 | Self::ContextTemplate
365 )
366 }
367}
368
369impl From<Capability> for (Bytes, Option<Bytes>) {
370 fn from(capa: Capability) -> (Bytes, Option<Bytes>) {
371 match capa {
372 Capability::AuthExternal => (
373 (b"auth" as &[u8]).into(),
374 Some((b"EXTERNAL" as &[u8]).into()),
375 ),
376 Capability::AuthKeyboardInteractive => (
377 (b"auth" as &[u8]).into(),
378 Some((b"keyboard-interactive" as &[u8]).into()),
379 ),
380 Capability::AuthPlain => ((b"auth" as &[u8]).into(), Some((b"PLAIN" as &[u8]).into())),
381 Capability::ChannelCommand => (
382 (b"channel" as &[u8]).into(),
383 Some((b"command" as &[u8]).into()),
384 ),
385 Capability::Channel9P => ((b"channel" as &[u8]).into(), Some((b"9p" as &[u8]).into())),
386 Capability::ChannelSFTP => (
387 (b"channel" as &[u8]).into(),
388 Some((b"sftp" as &[u8]).into()),
389 ),
390 Capability::ChannelClipboard => (
391 (b"channel" as &[u8]).into(),
392 Some((b"clipboard" as &[u8]).into()),
393 ),
394 Capability::StoreCredential => (
395 (b"store" as &[u8]).into(),
396 Some((b"credential" as &[u8]).into()),
397 ),
398 Capability::ExtensionAllocate => (
399 (b"extension" as &[u8]).into(),
400 Some((b"allocate" as &[u8]).into()),
401 ),
402 Capability::ContextTemplate => (
403 (b"context" as &[u8]).into(),
404 Some((b"template" as &[u8]).into()),
405 ),
406 Capability::Other(name, subtype) => (name, subtype),
407 }
408 }
409}
410
411impl From<(&[u8], Option<&[u8]>)> for Capability {
412 fn from(data: (&[u8], Option<&[u8]>)) -> Capability {
413 match data {
414 (b"auth", Some(b"EXTERNAL")) => Capability::AuthExternal,
415 (b"auth", Some(b"PLAIN")) => Capability::AuthPlain,
416 (b"auth", Some(b"keyboard-interactive")) => Capability::AuthKeyboardInteractive,
417 (b"channel", Some(b"command")) => Capability::ChannelCommand,
418 (b"channel", Some(b"9p")) => Capability::Channel9P,
419 (b"channel", Some(b"sftp")) => Capability::ChannelSFTP,
420 (b"channel", Some(b"clipboard")) => Capability::ChannelClipboard,
421 (b"store", Some(b"credential")) => Capability::StoreCredential,
422 (b"extension", Some(b"allocate")) => Capability::ExtensionAllocate,
423 (b"context", Some(b"template")) => Capability::ContextTemplate,
424 (name, subtype) => {
425 Capability::Other(name.to_vec().into(), subtype.map(|s| s.to_vec().into()))
426 }
427 }
428 }
429}
430
431impl From<(Bytes, Option<Bytes>)> for Capability {
432 fn from(data: (Bytes, Option<Bytes>)) -> Capability {
433 match data {
434 (a, Some(b)) => (&a as &[u8], Some(&b as &[u8])).into(),
435 (a, None) => (&a as &[u8], None).into(),
436 }
437 }
438}
439
440#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
441#[serde(rename_all = "kebab-case")]
442pub struct CapabilityResponse {
443 pub version: Vec<u32>,
444 pub capabilities: Vec<(Bytes, Option<Bytes>)>,
445 pub user_agent: Option<String>,
446}
447
448#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
449#[serde(rename_all = "kebab-case")]
450pub struct VersionRequest {
451 pub version: u32,
452 pub enable: Vec<(Bytes, Option<Bytes>)>,
453 pub id: Option<Bytes>,
454 pub user_agent: Option<String>,
455}
456
457#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
458#[serde(rename_all = "kebab-case")]
459pub struct AuthenticateRequest {
460 pub last_id: Option<u32>,
461 pub method: Bytes,
464 pub message: Option<Bytes>,
465}
466
467#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
468#[serde(rename_all = "kebab-case")]
469pub struct AuthenticateResponse {
470 pub method: Bytes,
473 pub message: Option<Bytes>,
474}
475
476#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
477#[serde(rename_all = "kebab-case")]
478pub struct PartialContinueRequest {
479 pub id: u32,
480 pub kind: u32,
481}
482
483#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
484#[serde(rename_all = "kebab-case")]
485pub struct ContinueRequest<T> {
486 pub id: u32,
487 pub kind: u32,
488 pub message: Option<T>,
489}
490
491#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
492#[serde(rename_all = "kebab-case")]
493pub struct AbortRequest {
494 pub id: u32,
495 pub kind: u32,
496}
497
498#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
499#[serde(transparent)]
500pub struct ChannelID(pub u32);
501
502impl fmt::Display for ChannelID {
503 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504 write!(f, "{}", self.0)
505 }
506}
507
508#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
509#[serde(transparent)]
510pub struct ChannelSelectorID(pub u32);
511
512#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
524#[serde(rename_all = "kebab-case")]
525pub struct CreateChannelRequest {
526 pub kind: Bytes,
527 pub kind_args: Option<Vec<Bytes>>,
528 pub args: Option<Vec<Bytes>>,
529 pub env: Option<BTreeMap<Bytes, Bytes>>,
530 pub meta: Option<BTreeMap<Bytes, Value>>,
531 pub selectors: Vec<u32>,
532}
533
534#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
535#[serde(rename_all = "kebab-case")]
536pub struct CreateChannelResponse {
537 pub id: ChannelID,
538}
539
540#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
541#[serde(rename_all = "kebab-case")]
542pub struct DeleteChannelRequest {
543 pub id: ChannelID,
544 pub termination: Option<u32>,
545}
546
547#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
548#[serde(rename_all = "kebab-case")]
549pub struct ReadChannelRequest {
550 pub id: ChannelID,
551 pub selector: u32,
552 pub count: u64,
553}
554
555#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
556#[serde(rename_all = "kebab-case")]
557pub struct ReadChannelResponse {
558 pub bytes: Bytes,
559}
560
561#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
562#[serde(rename_all = "kebab-case")]
563pub struct WriteChannelRequest {
564 pub id: ChannelID,
565 pub selector: u32,
566 pub bytes: Bytes,
567}
568
569#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
570#[serde(rename_all = "kebab-case")]
571pub struct WriteChannelResponse {
572 pub count: u64,
573}
574
575#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
576#[serde(rename_all = "kebab-case")]
577pub struct DetachChannelSelectorRequest {
578 pub id: ChannelID,
579 pub selector: u32,
580}
581
582bitflags! {
583 #[derive(Default)]
584 pub struct PollChannelFlags: u64 {
585 const Input = 0x00000001;
586 const Output = 0x00000002;
587 const Error = 0x00000004;
588 const Hangup = 0x00000008;
589 const Invalid = 0x00000010;
590 const Gone = 0x00000020;
591 }
592}
593
594#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
595#[serde(rename_all = "kebab-case")]
596pub struct CreateExtensionRangeRequest {
597 pub extension: (Bytes, Option<Bytes>),
598 pub count: u32,
599}
600
601#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
602#[serde(rename_all = "kebab-case")]
603pub struct CreateExtensionRangeResponse {
604 pub range: (u32, u32),
605}
606
607#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
608#[serde(rename_all = "kebab-case")]
609pub struct DeleteExtensionRangeRequest {
610 pub extension: (Bytes, Option<Bytes>),
611 pub range: (u32, u32),
612}
613
614#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
615#[serde(rename_all = "kebab-case")]
616pub struct ListExtensionRangesResponse {
617 pub ranges: Vec<ExtensionRange>,
618}
619
620impl IntoIterator for ListExtensionRangesResponse {
621 type Item = ExtensionRange;
622 type IntoIter = std::vec::IntoIter<ExtensionRange>;
623
624 fn into_iter(self) -> Self::IntoIter {
625 self.ranges.into_iter()
626 }
627}
628
629impl<'a> IntoIterator for &'a ListExtensionRangesResponse {
630 type Item = &'a ExtensionRange;
631 type IntoIter = std::slice::Iter<'a, ExtensionRange>;
632
633 fn into_iter(self) -> Self::IntoIter {
634 self.ranges.iter()
635 }
636}
637
638impl<'a> IntoIterator for &'a mut ListExtensionRangesResponse {
639 type Item = &'a mut ExtensionRange;
640 type IntoIter = std::slice::IterMut<'a, ExtensionRange>;
641
642 fn into_iter(self) -> Self::IntoIter {
643 self.ranges.iter_mut()
644 }
645}
646
647#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
648#[serde(rename_all = "kebab-case")]
649pub struct ExtensionRange {
650 pub extension: (Bytes, Option<Bytes>),
651 pub range: (u32, u32),
652}
653
654#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
655pub enum ChannelMetadataNotificationKind {
656 WaitStatus = 0,
657}
658
659#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
660pub enum ChannelMetadataStatusKind {
661 Exited = 0,
662 Signalled = 1,
663 SignalledWithCore = 2,
664 Stopped = 3,
665 Unknown = 0x7fffffff,
666}
667
668#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
669#[serde(rename_all = "kebab-case")]
670pub struct PingChannelRequest {
671 pub id: ChannelID,
672}
673
674#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
675#[serde(rename_all = "kebab-case")]
676pub struct PollChannelRequest {
677 pub id: ChannelID,
678 pub selectors: Vec<u32>,
679 pub milliseconds: Option<u32>,
680 pub wanted: Option<Vec<u64>>,
681}
682
683#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
684#[serde(rename_all = "kebab-case")]
685pub struct PollChannelResponse {
686 pub id: ChannelID,
687 pub selectors: BTreeMap<u32, u64>,
688}
689
690#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
691#[serde(rename_all = "kebab-case")]
692pub struct ChannelMetadataNotification {
693 pub id: ChannelID,
694 pub kind: u32,
695 pub status: Option<u32>,
696 pub status_kind: Option<u32>,
697 pub meta: Option<BTreeMap<Bytes, Value>>,
698}
699
700#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
701pub enum ClipboardChannelTarget {
702 Primary,
703 Clipboard,
704}
705
706#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
707pub enum ClipboardChannelOperation {
708 Copy,
709 Paste,
710}
711
712#[derive(Serialize, Deserialize, Hash, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
713#[serde(transparent)]
714pub struct StoreID(pub u32);
715
716#[derive(Serialize, Deserialize, Hash, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
717#[serde(transparent)]
718pub struct StoreSelectorID(pub u32);
719
720#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
721#[serde(rename_all = "kebab-case")]
722pub enum StoreSelector {
723 Path(Bytes),
724 #[serde(rename = "id")]
725 ID(StoreSelectorID),
726}
727
728#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
729#[serde(rename_all = "kebab-case")]
730pub struct OpenStoreRequest {
731 pub kind: Bytes,
732 pub path: Option<Bytes>,
733 pub meta: Option<BTreeMap<Bytes, Value>>,
734}
735
736#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
737#[serde(rename_all = "kebab-case")]
738pub struct OpenStoreResponse {
739 pub id: StoreID,
740}
741
742#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
743#[serde(rename_all = "kebab-case")]
744pub struct CloseStoreRequest {
745 pub id: StoreID,
746}
747
748#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
749#[serde(rename_all = "kebab-case")]
750pub struct ListStoreElementsRequest {
751 pub id: StoreID,
752 pub selector: StoreSelector,
753}
754
755#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
756#[serde(rename_all = "kebab-case")]
757pub struct ListStoreElementsResponse {
758 pub elements: Vec<StoreElement>,
759}
760
761impl IntoIterator for ListStoreElementsResponse {
762 type Item = StoreElement;
763 type IntoIter = std::vec::IntoIter<StoreElement>;
764
765 fn into_iter(self) -> Self::IntoIter {
766 self.elements.into_iter()
767 }
768}
769
770impl<'a> IntoIterator for &'a ListStoreElementsResponse {
771 type Item = &'a StoreElement;
772 type IntoIter = std::slice::Iter<'a, StoreElement>;
773
774 fn into_iter(self) -> Self::IntoIter {
775 self.elements.iter()
776 }
777}
778
779impl<'a> IntoIterator for &'a mut ListStoreElementsResponse {
780 type Item = &'a mut StoreElement;
781 type IntoIter = std::slice::IterMut<'a, StoreElement>;
782
783 fn into_iter(self) -> Self::IntoIter {
784 self.elements.iter_mut()
785 }
786}
787
788#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
789#[serde(rename_all = "kebab-case")]
790pub struct AcquireStoreElementRequest {
791 pub id: StoreID,
792 pub selector: Bytes,
793}
794
795#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
796#[serde(rename_all = "kebab-case")]
797pub struct AcquireStoreElementResponse {
798 pub selector: StoreSelectorID,
799}
800
801#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
802#[serde(rename_all = "kebab-case")]
803pub struct CloseStoreElementRequest {
804 pub id: StoreID,
805 pub selector: StoreSelectorID,
806}
807
808#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
809#[serde(rename_all = "kebab-case")]
810pub struct AuthenticateStoreElementRequest {
811 pub id: StoreID,
812 pub selector: StoreSelectorID,
813 pub method: Bytes,
814 pub message: Option<Bytes>,
815}
816
817#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
818#[serde(rename_all = "kebab-case")]
819pub struct AuthenticateStoreElementResponse {
820 pub method: Bytes,
821 pub message: Option<Bytes>,
822}
823
824#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
825#[serde(rename_all = "kebab-case")]
826pub struct StoreElementBareRequest {
827 pub id: StoreID,
828 pub selector: StoreSelector,
829 pub kind: String,
830 pub needs_authentication: Option<bool>,
831 pub authentication_methods: Option<Vec<Bytes>>,
832 pub meta: Option<BTreeMap<Bytes, Value>>,
833}
834
835#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
836#[serde(rename_all = "kebab-case")]
837pub struct CreateStoreElementRequest<T> {
838 pub id: StoreID,
839 pub selector: StoreSelector,
840 pub kind: String,
841 pub needs_authentication: Option<bool>,
842 pub authentication_methods: Option<Vec<Bytes>>,
843 pub meta: Option<BTreeMap<Bytes, Value>>,
844 pub body: T,
845}
846
847#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
848#[serde(rename_all = "kebab-case")]
849pub struct DeleteStoreElementRequest {
850 pub id: StoreID,
851 pub selector: StoreSelector,
852}
853
854#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
855#[serde(rename_all = "kebab-case")]
856pub struct UpdateStoreElementRequest<T> {
857 pub id: StoreID,
858 pub selector: StoreSelector,
859 pub kind: String,
860 pub needs_authentication: Option<bool>,
861 pub authentication_methods: Option<Vec<Bytes>>,
862 pub meta: Option<BTreeMap<Bytes, Value>>,
863 pub body: T,
864}
865
866#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
867#[serde(rename_all = "kebab-case")]
868pub struct ReadStoreElementRequest {
869 pub id: StoreID,
870 pub selector: StoreSelector,
871}
872
873#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
874#[serde(rename_all = "kebab-case")]
875pub struct ReadStoreElementResponse<T> {
876 pub kind: String,
877 pub needs_authentication: Option<bool>,
878 pub authentication_methods: Option<Vec<Bytes>>,
879 pub meta: Option<BTreeMap<Bytes, Value>>,
880 pub body: T,
881}
882
883#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
884#[serde(rename_all = "kebab-case")]
885pub enum StoreSearchRecursionLevel {
886 Boolean(bool),
887 Levels(u32),
888}
889
890#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
891#[serde(rename_all = "kebab-case")]
892pub struct SearchStoreElementsBareRequest {
893 pub id: StoreID,
894 pub selector: StoreSelector,
895 pub recurse: StoreSearchRecursionLevel,
896 pub kind: Option<String>,
897}
898
899#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
900#[serde(rename_all = "kebab-case")]
901pub struct SearchStoreElementsRequest<T> {
902 pub id: StoreID,
903 pub selector: StoreSelector,
904 pub recurse: StoreSearchRecursionLevel,
905 pub kind: Option<String>,
906 pub body: Option<T>,
907}
908
909#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
910#[serde(rename_all = "kebab-case")]
911pub struct SearchStoreElementsResponse<T> {
912 pub elements: Vec<StoreElementWithBody<T>>,
913}
914
915impl<T> IntoIterator for SearchStoreElementsResponse<T> {
916 type Item = StoreElementWithBody<T>;
917 type IntoIter = std::vec::IntoIter<StoreElementWithBody<T>>;
918
919 fn into_iter(self) -> Self::IntoIter {
920 self.elements.into_iter()
921 }
922}
923
924impl<'a, T> IntoIterator for &'a SearchStoreElementsResponse<T> {
925 type Item = &'a StoreElementWithBody<T>;
926 type IntoIter = std::slice::Iter<'a, StoreElementWithBody<T>>;
927
928 fn into_iter(self) -> Self::IntoIter {
929 self.elements.iter()
930 }
931}
932
933impl<'a, T> IntoIterator for &'a mut SearchStoreElementsResponse<T> {
934 type Item = &'a mut StoreElementWithBody<T>;
935 type IntoIter = std::slice::IterMut<'a, StoreElementWithBody<T>>;
936
937 fn into_iter(self) -> Self::IntoIter {
938 self.elements.iter_mut()
939 }
940}
941
942#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
943#[serde(rename_all = "kebab-case")]
944pub struct StoreElement {
945 pub path: Bytes,
946 pub id: Option<StoreSelectorID>,
947 pub kind: String,
948 pub needs_authentication: Option<bool>,
949 pub authentication_methods: Option<Vec<Bytes>>,
950 pub meta: Option<BTreeMap<Bytes, Value>>,
951}
952
953#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
954#[serde(rename_all = "kebab-case")]
955pub struct StoreElementWithBody<T> {
956 pub path: Bytes,
957 pub id: Option<StoreSelectorID>,
958 pub kind: String,
959 pub needs_authentication: Option<bool>,
960 pub authentication_methods: Option<Vec<Bytes>>,
961 pub meta: Option<BTreeMap<Bytes, Value>>,
962 pub body: T,
963}
964
965impl<T> StoreElementWithBody<T> {
966 pub fn new(elem: StoreElement, body: T) -> Self {
967 Self {
968 path: elem.path,
969 id: elem.id,
970 kind: elem.kind,
971 needs_authentication: elem.needs_authentication,
972 authentication_methods: elem.authentication_methods,
973 meta: elem.meta,
974 body,
975 }
976 }
977}
978
979#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
980#[serde(rename_all = "kebab-case")]
981pub enum SearchStoreElementType {
982 Literal(Value),
983 Set(BTreeSet<SearchStoreElementType>),
984 Sequence(Vec<SearchStoreElementType>),
985 Any(()),
987 None(()),
988}
989
990#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
991#[serde(rename_all = "kebab-case")]
992pub struct CredentialStoreSearchElement {
993 pub username: SearchStoreElementType,
994 pub secret: SearchStoreElementType,
995 pub authtype: SearchStoreElementType,
996 pub kind: SearchStoreElementType,
997 pub protocol: SearchStoreElementType,
998 pub host: SearchStoreElementType,
999 pub title: SearchStoreElementType,
1000 pub description: SearchStoreElementType,
1001 pub path: SearchStoreElementType,
1002 pub service: SearchStoreElementType,
1003 pub extra: BTreeMap<String, SearchStoreElementType>,
1004 pub id: SearchStoreElementType,
1005}
1006
1007#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1008#[serde(rename_all = "kebab-case")]
1009pub struct CredentialStoreLocation {
1010 pub protocol: Option<String>,
1011 pub host: Option<String>,
1012 pub port: Option<u16>,
1013 pub path: Option<String>,
1014}
1015
1016#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1017#[serde(rename_all = "kebab-case")]
1018pub struct CredentialStoreElement {
1019 pub username: Option<Bytes>,
1020 pub secret: Option<Bytes>,
1021 pub authtype: Option<String>,
1022 #[serde(rename = "type")]
1023 pub kind: String,
1024 pub title: Option<String>,
1025 pub description: Option<String>,
1026 pub location: Vec<CredentialStoreLocation>,
1027 pub service: Option<String>,
1028 pub extra: BTreeMap<String, Value>,
1029 pub id: Bytes,
1030}
1031
1032#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1033pub struct KeyboardInteractiveAuthenticationPrompt {
1034 pub prompt: String,
1035 pub echo: bool,
1036}
1037
1038#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1039pub struct KeyboardInteractiveAuthenticationRequest {
1040 pub name: String,
1041 pub instruction: String,
1042 pub prompts: Vec<KeyboardInteractiveAuthenticationPrompt>,
1043}
1044
1045#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1046pub struct KeyboardInteractiveAuthenticationResponse {
1047 pub responses: Vec<String>,
1048}
1049
1050#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1051#[serde(rename_all = "kebab-case")]
1052pub struct ReadServerContextRequest {
1053 pub kind: String,
1054 pub id: Option<Bytes>,
1055 pub meta: Option<BTreeMap<Bytes, Value>>,
1056}
1057
1058#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1059#[serde(rename_all = "kebab-case")]
1060pub struct ReadServerContextResponse {
1061 pub id: Option<Bytes>,
1062 pub meta: Option<BTreeMap<Bytes, Value>>,
1063}
1064
1065#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1066#[serde(rename_all = "kebab-case")]
1067pub struct ReadServerContextResponseWithBody<T> {
1068 pub id: Option<Bytes>,
1069 pub meta: Option<BTreeMap<Bytes, Value>>,
1070 pub body: Option<T>,
1071}
1072
1073#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1074#[serde(rename_all = "kebab-case")]
1075pub struct WriteServerContextRequest {
1076 pub kind: String,
1077 pub id: Option<Bytes>,
1078 pub meta: Option<BTreeMap<Bytes, Value>>,
1079}
1080
1081#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1082#[serde(rename_all = "kebab-case")]
1083pub struct WriteServerContextRequestWithBody<T> {
1084 pub kind: String,
1085 pub id: Option<Bytes>,
1086 pub meta: Option<BTreeMap<Bytes, Value>>,
1087 pub body: Option<T>,
1088}
1089
1090#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1091#[serde(rename_all = "kebab-case")]
1092pub struct WriteServerContextResponse {
1093 pub id: Option<Bytes>,
1094 pub meta: Option<BTreeMap<Bytes, Value>>,
1095}
1096
1097#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1098#[serde(rename_all = "kebab-case")]
1099pub struct TemplateServerContextBody {
1100 pub senv: Option<BTreeMap<Bytes, Bytes>>,
1101 pub cenv: Option<BTreeMap<Bytes, Bytes>>,
1102 pub ctxsenv: Option<BTreeMap<Bytes, Bytes>>,
1103 pub args: Option<Vec<Bytes>>,
1104}
1105
1106#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1107#[serde(rename_all = "kebab-case")]
1108pub struct TemplateServerContextBodyWithBody<T> {
1109 pub senv: Option<BTreeMap<Bytes, Bytes>>,
1110 pub cenv: Option<BTreeMap<Bytes, Bytes>>,
1111 pub ctxsenv: Option<BTreeMap<Bytes, Bytes>>,
1112 pub args: Option<Vec<Bytes>>,
1113 pub body: Option<T>,
1114}
1115
1116#[derive(Clone, Debug)]
1118pub struct Message {
1119 pub id: u32,
1120 pub kind: u32,
1121 pub message: Option<Bytes>,
1122}
1123
1124#[derive(Clone, Debug)]
1125pub struct Response {
1126 pub id: u32,
1127 pub code: u32,
1128 pub message: Option<Bytes>,
1129}
1130
1131#[derive(Default)]
1132pub struct ProtocolSerializer {}
1133
1134pub enum Data {
1135 Message(Message),
1136 Response(Response),
1137}
1138
1139#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
1140pub enum ResponseValue<T: DeserializeOwned, U: DeserializeOwned> {
1141 Success(T),
1142 Continuation((u32, U)),
1143}
1144
1145impl ProtocolSerializer {
1146 const MAX_MESSAGE_SIZE: u32 = 0x00ffffff;
1147
1148 pub fn new() -> ProtocolSerializer {
1149 Self {}
1150 }
1151
1152 pub fn is_valid_size(&self, size: u32) -> bool {
1153 (8..=Self::MAX_MESSAGE_SIZE).contains(&size)
1154 }
1155
1156 pub fn serialize_header(&self, id: u32, next: u32, data_len: usize) -> Option<Bytes> {
1157 let size = data_len as u64 + 8;
1158 if size > Self::MAX_MESSAGE_SIZE as u64 {
1159 return None;
1160 }
1161 let mut b = BytesMut::with_capacity(size as usize);
1162 let size = size as u32;
1163 b.extend(&size.to_le_bytes());
1164 b.extend(&id.to_le_bytes());
1165 b.extend(&next.to_le_bytes());
1166 Some(b.into())
1167 }
1168
1169 pub fn serialize_message_simple(&self, msg: &Message) -> Option<Bytes> {
1170 let size = 8 + match &msg.message {
1171 Some(m) => m.len(),
1172 None => 0,
1173 };
1174 if size > Self::MAX_MESSAGE_SIZE as usize {
1175 return None;
1176 }
1177 let mut b = BytesMut::with_capacity(size);
1178 let size = size as u32;
1179 b.extend(&size.to_le_bytes());
1180 b.extend(&msg.id.to_le_bytes());
1181 b.extend(&msg.kind.to_le_bytes());
1182 match &msg.message {
1183 Some(m) => b.extend(m),
1184 None => (),
1185 };
1186 Some(b.into())
1187 }
1188
1189 pub fn serialize_message_typed<S: Serialize>(&self, msg: &Message, obj: &S) -> Option<Bytes> {
1190 let mut v: Vec<u8> = Vec::with_capacity(12);
1191 v.extend(&0u32.to_le_bytes());
1193 v.extend(&msg.id.to_le_bytes());
1194 v.extend(&msg.kind.to_le_bytes());
1195 let mut cursor = std::io::Cursor::new(&mut v);
1196 let _ = cursor.seek(SeekFrom::End(0));
1197 if serde_cbor::to_writer(&mut cursor, obj).is_err() {
1198 return None;
1199 }
1200 let size = match u32::try_from(v.len()) {
1201 Ok(sz) if (4..=Self::MAX_MESSAGE_SIZE).contains(&sz) => sz - 4,
1202 _ => return None,
1203 };
1204 v[0..4].copy_from_slice(&size.to_le_bytes());
1205 Some(v.into())
1206 }
1207
1208 pub fn serialize_body<S: Serialize>(&self, obj: &S) -> Option<Bytes> {
1209 match serde_cbor::to_vec(obj) {
1210 Ok(m) => Some(m.into()),
1211 Err(_) => None,
1212 }
1213 }
1214
1215 pub fn serialize_response_simple(&self, resp: &Response) -> Option<Bytes> {
1216 let size = 8 + match &resp.message {
1217 Some(m) => m.len(),
1218 None => 0,
1219 };
1220 if size > Self::MAX_MESSAGE_SIZE as usize {
1221 return None;
1222 }
1223 let mut b = BytesMut::with_capacity(size);
1224 let size = size as u32;
1225 b.extend(&size.to_le_bytes());
1226 b.extend(&resp.id.to_le_bytes());
1227 b.extend(&resp.code.to_le_bytes());
1228 match &resp.message {
1229 Some(m) => b.extend(m),
1230 None => (),
1231 };
1232 Some(b.into())
1233 }
1234
1235 pub fn serialize_response_typed<S: Serialize>(&self, msg: &Response, obj: &S) -> Option<Bytes> {
1236 let mut v: Vec<u8> = Vec::with_capacity(12);
1237 v.extend(&0u32.to_le_bytes());
1239 v.extend(&msg.id.to_le_bytes());
1240 v.extend(&msg.code.to_le_bytes());
1241 let mut cursor = std::io::Cursor::new(&mut v);
1242 let _ = cursor.seek(SeekFrom::End(0));
1243 if serde_cbor::to_writer(&mut cursor, obj).is_err() {
1244 return None;
1245 }
1246 let size = match u32::try_from(v.len()) {
1247 Ok(sz) if (4..=Self::MAX_MESSAGE_SIZE).contains(&sz) => sz - 4,
1248 _ => return None,
1249 };
1250 v[0..4].copy_from_slice(&size.to_le_bytes());
1251 Some(v.into())
1252 }
1253
1254 pub fn deserialize_data(
1255 &self,
1256 config: &Config,
1257 header: &[u8],
1258 body: Bytes,
1259 ) -> Result<Data, Error> {
1260 fn is_sender(config: &Config, id: u32) -> bool {
1261 let sender_mask = if config.is_server() { 0x80000000 } else { 0 };
1262 (id & 0x80000000) == sender_mask
1263 }
1264 let _size: u32 = u32::from_le_bytes(header[0..4].try_into().unwrap());
1265 let id: u32 = u32::from_le_bytes(header[4..8].try_into().unwrap());
1266 let arg: u32 = u32::from_le_bytes(header[8..12].try_into().unwrap());
1267 if is_sender(config, id) {
1268 Ok(Data::Response(Response {
1269 id,
1270 code: arg,
1271 message: if body.is_empty() { None } else { Some(body) },
1272 }))
1273 } else {
1274 Ok(Data::Message(Message {
1275 id,
1276 kind: arg,
1277 message: if body.is_empty() { None } else { Some(body) },
1278 }))
1279 }
1280 }
1281
1282 pub fn deserialize_message_typed<'a, D: Deserialize<'a>>(
1283 &self,
1284 msg: &'a Message,
1285 ) -> Result<Option<D>, Error> {
1286 match &msg.message {
1287 Some(body) => match serde_cbor::from_slice(body) {
1288 Ok(decoded) => Ok(Some(decoded)),
1289 Err(_) => Err(Error {
1290 code: ResponseCode::Invalid,
1291 body: None,
1292 }),
1293 },
1294 None => Ok(None),
1295 }
1296 }
1297
1298 pub fn deserialize_response_typed<D1: DeserializeOwned, D2: DeserializeOwned>(
1299 &self,
1300 resp: &Response,
1301 ) -> Result<Option<ResponseValue<D1, D2>>, Error> {
1302 if resp.code == ResponseCode::Success as u32 {
1303 match &resp.message {
1304 Some(body) => match serde_cbor::from_slice(body) {
1305 Ok(decoded) => Ok(Some(ResponseValue::Success(decoded))),
1306 Err(_) => Err(Error {
1307 code: ResponseCode::Invalid,
1308 body: None,
1309 }),
1310 },
1311 None => Ok(None),
1312 }
1313 } else if resp.code == ResponseCode::Continuation as u32 {
1314 match &resp.message {
1315 Some(body) => match serde_cbor::from_slice(body) {
1316 Ok(decoded) => Ok(Some(ResponseValue::Continuation((resp.id, decoded)))),
1317 Err(_) => Err(Error {
1318 code: ResponseCode::Invalid,
1319 body: None,
1320 }),
1321 },
1322 None => Ok(None),
1323 }
1324 } else {
1325 match &resp.message {
1326 Some(body) => match serde_cbor::from_slice(body) {
1327 Ok(decoded) => Err(Error {
1328 code: ResponseCode::from_u32(resp.code),
1329 body: Some(decoded),
1330 }),
1331 Err(_) => Err(Error {
1332 code: ResponseCode::from_u32(resp.code),
1333 body: None,
1334 }),
1335 },
1336 None => Err(Error {
1337 code: ResponseCode::from_u32(resp.code),
1338 body: None,
1339 }),
1340 }
1341 }
1342 }
1343}
1344
1345#[cfg(test)]
1346mod tests {
1347 use super::{
1348 ChannelID, Empty, Message, ProtocolSerializer, Response, ResponseValue,
1349 SearchStoreElementType, StoreID, StoreSelector, StoreSelectorID,
1350 };
1351 use bytes::Bytes;
1352 use serde::{de::DeserializeOwned, Deserialize, Serialize};
1353 use serde_cbor::Value;
1354 use std::convert::TryFrom;
1355 use std::fmt::Debug;
1356
1357 #[test]
1358 fn serialize_header() {
1359 let cases: &[(u32, u32, usize, Option<&[u8]>)] = &[
1360 (
1361 0x01234567,
1362 0xffeeddcc,
1363 0x00000000,
1364 Some(b"\x08\x00\x00\x00\x67\x45\x23\x01\xcc\xdd\xee\xff"),
1365 ),
1366 (
1367 0x87654321,
1368 0x00000000,
1369 0x00000099,
1370 Some(b"\xa1\x00\x00\x00\x21\x43\x65\x87\x00\x00\x00\x00"),
1371 ),
1372 (
1373 0x87654321,
1374 0x00000000,
1375 0x00fffff7,
1376 Some(b"\xff\xff\xff\x00\x21\x43\x65\x87\x00\x00\x00\x00"),
1377 ),
1378 (0x87654321, 0x00000000, 0x00fffff8, None),
1379 ];
1380 let ser = ProtocolSerializer::new();
1381 for (id, next, data_len, response) in cases {
1382 assert_eq!(
1383 ser.serialize_header(*id, *next, *data_len).as_deref(),
1384 *response
1385 );
1386 }
1387 }
1388
1389 fn assert_encode<'a, S: Serialize + Deserialize<'a> + Debug + Clone + PartialEq>(
1390 desc: &str,
1391 s: &S,
1392 seq: &[u8],
1393 ) {
1394 let id = 0x01234567u32;
1395 let next = 0xffeeddccu32;
1396 let mut header = [0u8; 12];
1397
1398 header[0..4].copy_from_slice(&u32::try_from(seq.len() + 8).unwrap().to_le_bytes());
1399 header[4..8].copy_from_slice(&id.to_le_bytes());
1400 header[8..12].copy_from_slice(&next.to_le_bytes());
1401
1402 let ser = ProtocolSerializer::new();
1403 let msg = Message {
1404 id,
1405 kind: next,
1406 message: Some(Bytes::copy_from_slice(seq)),
1407 };
1408
1409 let res = ser.serialize_header(id, next, seq.len()).unwrap();
1410 assert_eq!(&res, &header as &[u8], "header: {}", desc);
1411
1412 let res = ser.serialize_message_simple(&msg).unwrap();
1413 assert_eq!(res[0..12], header, "simple header: {}", desc);
1414 assert_eq!(res[12..], *seq, "simple body: {}", desc);
1415
1416 let res = ser.serialize_body(s).unwrap();
1417 assert_eq!(res, *seq, "body: {}", desc);
1418
1419 let msg = Message {
1420 id,
1421 kind: next,
1422 message: None,
1423 };
1424 let res = ser.serialize_message_typed(&msg, s).unwrap();
1425 assert_eq!(res[0..12], header, "typed header: {}", desc);
1426 assert_eq!(res[12..], *seq, "typed body: {}", desc);
1427 }
1428
1429 fn assert_round_trip<S: Serialize + DeserializeOwned + Debug + Clone + PartialEq>(
1430 desc: &str,
1431 s: &S,
1432 seq: &[u8],
1433 ) {
1434 assert_encode(desc, s, seq);
1435 assert_decode(desc, s, seq);
1436 }
1437
1438 fn assert_decode<S: Serialize + DeserializeOwned + Debug + Clone + PartialEq>(
1439 desc: &str,
1440 s: &S,
1441 seq: &[u8],
1442 ) {
1443 let id = 0x01234567u32;
1444 let next = 0u32;
1445 let mut header = [0u8; 12];
1446
1447 header[0..4].copy_from_slice(&u32::try_from(seq.len() + 8).unwrap().to_le_bytes());
1448 header[4..8].copy_from_slice(&id.to_le_bytes());
1449 header[8..12].copy_from_slice(&next.to_le_bytes());
1450
1451 let body = Bytes::copy_from_slice(seq);
1452
1453 let ser = ProtocolSerializer::new();
1454 let resp = Response {
1455 id,
1456 code: next,
1457 message: Some(body.clone()),
1458 };
1459
1460 let mut full_msg: Vec<u8> = header.into();
1461 full_msg.extend(seq);
1462
1463 let res = ser.deserialize_response_typed::<S, Empty>(&resp);
1464 assert_eq!(
1465 res.unwrap().unwrap(),
1466 ResponseValue::Success(s.clone()),
1467 "deserialize typed response: {}",
1468 desc
1469 );
1470 }
1471
1472 #[test]
1473 fn serialize_basic_types() {
1474 assert_round_trip("0u32", &0u32, b"\x00");
1475 assert_round_trip("all ones u32", &0xfedcba98u32, b"\x1a\xfe\xdc\xba\x98");
1476 assert_round_trip(
1477 "simple Bytes",
1478 &Bytes::from(b"Hello, world!\n" as &'static [u8]),
1479 b"\x4eHello, world!\n",
1480 );
1481 assert_encode("simple &str", &"Hello, world!\n", b"\x6eHello, world!\n");
1482 assert_round_trip(
1483 "simple String",
1484 &String::from("Hello, world!\n"),
1485 b"\x6eHello, world!\n",
1486 );
1487 }
1488
1489 #[test]
1490 fn serialize_encoded_types() {
1491 assert_round_trip("ChannelID 0", &ChannelID(0), b"\x00");
1492 assert_round_trip(
1493 "ChannelID all ones u32",
1494 &ChannelID(0xfedcba98u32),
1495 b"\x1a\xfe\xdc\xba\x98",
1496 );
1497 assert_round_trip("StoreID 0", &StoreID(0), b"\x00");
1498 assert_round_trip(
1499 "StoreID pattern",
1500 &StoreID(0xfedcba98u32),
1501 b"\x1a\xfe\xdc\xba\x98",
1502 );
1503 assert_round_trip("StoreSelectorID 0", &StoreSelectorID(0), b"\x00");
1504 assert_round_trip(
1505 "StoreSelectorID pattern",
1506 &StoreSelectorID(0xfedcba98u32),
1507 b"\x1a\xfe\xdc\xba\x98",
1508 );
1509 assert_round_trip(
1510 "StoreSelector path",
1511 &StoreSelector::Path(Bytes::from(b"/dev/null" as &[u8])),
1512 b"\xa1\x64path\x49/dev/null",
1513 );
1514 assert_round_trip(
1515 "StoreSelector ID",
1516 &StoreSelector::ID(StoreSelectorID(0xfedcba98u32)),
1517 b"\xa1\x62id\x1a\xfe\xdc\xba\x98",
1518 );
1519 assert_round_trip(
1520 "SearchStoreElementType literal text",
1521 &SearchStoreElementType::Literal(Value::Text(String::from("abc123"))),
1522 b"\xa1\x67literal\x66abc123",
1523 );
1524 assert_round_trip(
1525 "SearchStoreElementType literal bytes",
1526 &SearchStoreElementType::Literal(Value::Bytes("abc123".into())),
1527 b"\xa1\x67literal\x46abc123",
1528 );
1529 assert_round_trip(
1530 "SearchStoreElementType literal null",
1531 &SearchStoreElementType::Literal(Value::Null),
1532 b"\xa1\x67literal\xf6",
1533 );
1534 assert_round_trip(
1535 "SearchStoreElementType any",
1536 &SearchStoreElementType::Any(()),
1537 b"\xa1\x63any\xf6",
1538 );
1539 assert_round_trip(
1540 "SearchStoreElementType none",
1541 &SearchStoreElementType::None(()),
1542 b"\xa1\x64none\xf6",
1543 );
1544 }
1545
1546 #[test]
1547 fn serialize_requests() {
1548 assert_round_trip(
1549 "CreateExtensionRangeRequest with no second part",
1550 &super::CreateExtensionRangeRequest {
1551 extension: (
1552 Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1553 None,
1554 ),
1555 count: 5,
1556 },
1557 b"\xa2\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\xf6\x65count\x05",
1558 );
1559 assert_round_trip(
1560 "CreateExtensionRangeRequest with second part",
1561 &super::CreateExtensionRangeRequest {
1562 extension: (
1563 Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1564 Some(Bytes::from(b"v1" as &[u8])),
1565 ),
1566 count: 5,
1567 },
1568 b"\xa2\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\x42v1\x65count\x05",
1569 );
1570 }
1571
1572 #[test]
1573 fn deserialize_requests() {
1574 assert_decode(
1575 "CreateExtensionRangeRequest with extension field",
1576 &super::CreateExtensionRangeRequest {
1577 extension: (
1578 Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1579 None,
1580 ),
1581 count: 5,
1582 },
1583 b"\xa3\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\xf6\x58\x26extension@test.ns.crustytoothpaste.net\xf5\x65count\x05",
1584 );
1585 }
1586}