Skip to main content

capnp/
lib.rs

1// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
2// Licensed under the MIT License:
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21
22//! # Cap'n Proto Runtime Library
23//!
24//! This crate contains basic facilities for reading and writing
25//! [Cap'n Proto](https://capnproto.org) messages in Rust. It is intended to
26//! be used in conjunction with code generated by the
27//! [capnpc-rust](https://crates.io/crates/capnpc) crate.
28
29#![cfg_attr(not(test), deny(clippy::cast_possible_truncation))]
30#![cfg_attr(feature = "rpc_try", feature(try_trait_v2))]
31#![cfg_attr(not(feature = "std"), no_std)]
32
33#[cfg(feature = "alloc")]
34#[macro_use]
35extern crate alloc;
36
37/// Code generated from
38/// [schema.capnp](https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
39pub mod schema_capnp;
40
41pub mod any_pointer;
42pub mod any_pointer_list;
43pub mod capability;
44pub mod capability_list;
45pub mod constant;
46pub mod data;
47pub mod data_list;
48pub mod dynamic_list;
49pub mod dynamic_struct;
50pub mod dynamic_value;
51pub mod enum_list;
52pub mod introspect;
53pub mod io;
54pub mod list_list;
55pub mod message;
56pub mod primitive_list;
57pub mod private;
58pub mod raw;
59pub mod schema;
60pub mod serialize;
61pub mod serialize_packed;
62pub(crate) mod stringify;
63pub mod struct_list;
64pub mod text;
65pub mod text_list;
66pub mod traits;
67
68/// Macro for importing Rust code that has been generated by `capnpc::CompilerCommand`.
69///
70/// For example:
71/// ```ignore
72/// generated_code!(pub mod foo_capnp);
73/// ```
74/// pulls in the generated code for `foo.capnp` into a module named `foo_capnp`.
75/// It expects to find the generated code in a file `$OUT_DIR/foo_capnp.rs`,
76/// where `OUT_DIR` is Cargo's standard environment variable giving the
77/// location of the output of `build.rs`.
78///
79/// If the generated code lives in a nonstandard location—perhaps in a subdirectory
80/// of `OUT_DIR`—you can specify its path as a second argument:
81/// ```ignore
82/// generated_code!(pub mod foo_capnp, "some_directory/foo_capnp.rs");
83/// ```
84#[macro_export]
85macro_rules! generated_code {
86    ($vis:vis mod $mod_name:ident, $file_name:expr) => {
87        $vis mod $mod_name {
88            #![allow(clippy::all)]
89            include!(concat!(env!("OUT_DIR"), "/", $file_name));
90        }
91    };
92
93    ($vis:vis mod $mod_name:ident) => {
94        $crate::generated_code!($vis mod $mod_name, concat!(stringify!($mod_name), ".rs"));
95    };
96}
97
98///
99/// 8 bytes, aligned to an 8-byte boundary.
100///
101/// Internally, capnproto-rust allocates message buffers using this type,
102/// to guarantee alignment.
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104#[repr(C, align(8))]
105pub struct Word {
106    raw_content: [u8; 8],
107}
108
109///
110/// Constructs a word with the given bytes.
111///
112#[allow(clippy::too_many_arguments)]
113pub const fn word(b0: u8, b1: u8, b2: u8, b3: u8, b4: u8, b5: u8, b6: u8, b7: u8) -> Word {
114    Word {
115        raw_content: [b0, b1, b2, b3, b4, b5, b6, b7],
116    }
117}
118
119impl Word {
120    /// Allocates a vec of `length` words, all set to zero.
121    #[cfg(feature = "alloc")]
122    pub fn allocate_zeroed_vec(length: usize) -> alloc::vec::Vec<Self> {
123        vec![word(0, 0, 0, 0, 0, 0, 0, 0); length]
124    }
125
126    pub fn words_to_bytes(words: &[Self]) -> &[u8] {
127        unsafe { core::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 8) }
128    }
129
130    pub fn words_to_bytes_mut(words: &mut [Self]) -> &mut [u8] {
131        unsafe { core::slice::from_raw_parts_mut(words.as_mut_ptr() as *mut u8, words.len() * 8) }
132    }
133}
134
135#[cfg(any(feature = "quickcheck", test))]
136impl quickcheck::Arbitrary for Word {
137    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
138        crate::word(
139            quickcheck::Arbitrary::arbitrary(g),
140            quickcheck::Arbitrary::arbitrary(g),
141            quickcheck::Arbitrary::arbitrary(g),
142            quickcheck::Arbitrary::arbitrary(g),
143            quickcheck::Arbitrary::arbitrary(g),
144            quickcheck::Arbitrary::arbitrary(g),
145            quickcheck::Arbitrary::arbitrary(g),
146            quickcheck::Arbitrary::arbitrary(g),
147        )
148    }
149}
150
151/// Size of a message. Every generated struct has a method `.total_size()` that returns this.
152#[derive(Clone, Copy, Debug, PartialEq)]
153pub struct MessageSize {
154    pub word_count: u64,
155
156    /// Size of the capability table.
157    pub cap_count: u32,
158}
159
160impl core::ops::AddAssign for MessageSize {
161    fn add_assign(&mut self, rhs: Self) {
162        self.word_count += rhs.word_count;
163        self.cap_count += rhs.cap_count;
164    }
165}
166
167/// An enum value or union discriminant that was not found among those defined in a schema.
168#[derive(PartialEq, Eq, Clone, Copy, Debug)]
169pub struct NotInSchema(pub u16);
170
171impl ::core::fmt::Display for NotInSchema {
172    fn fmt(
173        &self,
174        fmt: &mut ::core::fmt::Formatter,
175    ) -> ::core::result::Result<(), ::core::fmt::Error> {
176        write!(
177            fmt,
178            "Enum value or union discriminant {} was not present in the schema.",
179            self.0
180        )
181    }
182}
183
184impl ::core::error::Error for NotInSchema {
185    fn description(&self) -> &str {
186        "Enum value or union discriminant was not present in schema."
187    }
188}
189
190/// Because messages are lazily validated, the return type of any method that reads a pointer field
191/// must be wrapped in a Result.
192pub type Result<T> = ::core::result::Result<T, Error>;
193
194/// Describes an arbitrary error that prevented an operation from completing.
195#[derive(Debug, Clone)]
196pub struct Error {
197    /// The general kind of the error. Code that decides how to respond to an error
198    /// should read only this field in making its decision.
199    pub kind: ErrorKind,
200
201    /// Extra context about error
202    #[cfg(feature = "alloc")]
203    pub extra: alloc::string::String,
204}
205
206/// The general nature of an error. The purpose of this enum is not to describe the error itself,
207/// but rather to describe how the client might want to respond to the error.
208#[derive(Debug, Clone, Copy, PartialEq, Eq)]
209#[non_exhaustive]
210pub enum ErrorKind {
211    /// Something went wrong
212    Failed,
213
214    /// The call failed because of a temporary lack of resources. This could be space resources
215    /// (out of memory, out of disk space) or time resources (request queue overflow, operation
216    /// timed out).
217    ///
218    /// The operation might work if tried again, but it should NOT be repeated immediately as this
219    /// may simply exacerbate the problem.
220    Overloaded,
221
222    /// The call required communication over a connection that has been lost. The caller will need
223    /// to re-establish connections and try again.
224    Disconnected,
225
226    /// The requested method is not implemented. The caller may wish to revert to a fallback
227    /// approach based on other methods.
228    Unimplemented,
229
230    /// Buffer is not large enough
231    BufferNotLargeEnough,
232
233    /// Cannot create a canonical message with a capability
234    CannotCreateACanonicalMessageWithACapability,
235
236    /// Cannot set AnyPointer field to a primitive value
237    CannotSetAnyPointerFieldToAPrimitiveValue,
238
239    /// Don't know how to handle non-STRUCT inline composite.
240    CantHandleNonStructInlineComposite,
241
242    /// Empty buffer
243    EmptyBuffer,
244
245    /// Empty slice
246    EmptySlice,
247
248    /// Enum value or union discriminant {} was not present in schema
249    EnumValueOrUnionDiscriminantNotPresent(NotInSchema),
250
251    /// Called get_writable_{data|text}_pointer() but existing list pointer is not byte-sized.
252    ExistingListPointerIsNotByteSized,
253
254    /// Existing list value is incompatible with expected type.
255    ExistingListValueIsIncompatibleWithExpectedType,
256
257    /// Called get_writable_{data|text|list|struct_list}_pointer() but existing pointer is not a list.
258    ExistingPointerIsNotAList,
259
260    /// Expected a list or blob.
261    ExpectedAListOrBlob,
262
263    /// Expected a pointer list, but got a list of data-only structs
264    ExpectedAPointerListButGotAListOfDataOnlyStructs,
265
266    /// Expected a primitive list, but got a list of pointer-only structs
267    ExpectedAPrimitiveListButGotAListOfPointerOnlyStructs,
268
269    /// failed to fill the whole buffer
270    FailedToFillTheWholeBuffer,
271
272    /// field and default mismatch
273    FieldAndDefaultMismatch,
274
275    /// field not found
276    FieldNotFound,
277
278    /// Found bit list where struct list was expected; upgrading boolean lists to struct lists is no longer supported
279    FoundBitListWhereStructListWasExpected,
280
281    /// Found struct list where bit list was expected.
282    FoundStructListWhereBitListWasExpected,
283
284    /// Cannot represent 4 byte length as `usize`. This may indicate that you are running on 8 or 16 bit platform or message is too large.
285    FourByteLengthTooBigForUSize,
286
287    /// Cannot represent 4 byte segment length as usize. This may indicate that you are running on 8 or 16 bit platform or segment is too large
288    FourByteSegmentLengthTooBigForUSize,
289
290    /// group field but type is not Struct
291    GroupFieldButTypeIsNotStruct,
292
293    /// init() is only valid for struct and AnyPointer fields
294    InitIsOnlyValidForStructAndAnyPointerFields,
295
296    /// initn() is only valid for list, text, or data fields
297    InitnIsOnlyValidForListTextOrDataFields,
298
299    /// InlineComposite list with non-STRUCT elements not supported.
300    InlineCompositeListWithNonStructElementsNotSupported,
301
302    /// InlineComposite list's elements overrun its word count.
303    InlineCompositeListsElementsOverrunItsWordCount,
304
305    /// InlineComposite lists of non-STRUCT type are not supported.
306    InlineCompositeListsOfNonStructTypeAreNotSupported,
307
308    /// Too many or too few segments {segment_count}
309    InvalidNumberOfSegments(usize),
310
311    /// Invalid segment id {id}
312    InvalidSegmentId(u32),
313
314    /// List(AnyPointer) not supported.
315    ListAnyPointerNotSupported,
316
317    /// List(Capability) not supported
318    ListCapabilityNotSupported,
319
320    /// Malformed double-far pointer.
321    MalformedDoubleFarPointer,
322
323    /// Message contains invalid capability pointer.
324    MessageContainsInvalidCapabilityPointer,
325
326    /// Message contains list pointer of non-bytes where data was expected.
327    MessageContainsListPointerOfNonBytesWhereDataWasExpected,
328
329    /// Message contains list pointer of non-bytes where text was expected.
330    MessageContainsListPointerOfNonBytesWhereTextWasExpected,
331
332    /// Message contains list with incompatible element type.
333    MessageContainsListWithIncompatibleElementType,
334
335    /// Message contains non-capability pointer where capability pointer was expected.
336    MessageContainsNonCapabilityPointerWhereCapabilityPointerWasExpected,
337
338    /// Message contains non-struct pointer where struct pointer was expected.
339    MessageContainsNonStructPointerWhereStructPointerWasExpected,
340
341    /// Message contains non-list pointer where data was expected.
342    MessageContainsNonListPointerWhereDataWasExpected,
343
344    /// Message contains non-list pointer where list pointer was expected
345    MessageContainsNonListPointerWhereListPointerWasExpected,
346
347    /// Message contains non-list pointer where text was expected.
348    MessageContainsNonListPointerWhereTextWasExpected,
349
350    /// Message contains null capability pointer.
351    MessageContainsNullCapabilityPointer,
352
353    /// Message contains out-of-bounds pointer,
354    MessageContainsOutOfBoundsPointer,
355
356    /// Message contains text that is not NUL-terminated
357    MessageContainsTextThatIsNotNULTerminated,
358
359    /// Message ends prematurely. Header claimed {header} words, but message only has {body} words,
360    MessageEndsPrematurely(usize, usize),
361
362    /// Message is too deeply nested.
363    MessageIsTooDeeplyNested,
364
365    /// Message is too deeply-nested or contains cycles.
366    MessageIsTooDeeplyNestedOrContainsCycles,
367
368    /// Message was not aligned by 8 bytes boundary. Either ensure that message is properly aligned or compile `capnp` crate with \"unaligned\" feature enabled.
369    MessageNotAlignedBy8BytesBoundary,
370
371    /// Message's size cannot be represented in usize
372    MessageSizeOverflow,
373
374    /// Message is too large
375    MessageTooLarge(usize),
376
377    /// Nesting limit exceeded
378    NestingLimitExceeded,
379
380    /// Not a struct
381    NotAStruct,
382
383    /// Only one of the section pointers is pointing to ourself
384    OnlyOneOfTheSectionPointersIsPointingToOurself,
385
386    /// Packed input did not end cleanly on a segment boundary.
387    PackedInputDidNotEndCleanlyOnASegmentBoundary,
388
389    /// Premature end of file
390    PrematureEndOfFile,
391
392    /// Premature end of packed input.
393    PrematureEndOfPackedInput,
394
395    /// Read limit exceeded
396    ReadLimitExceeded,
397
398    /// setting dynamic capabilities is unsupported
399    SettingDynamicCapabilitiesIsUnsupported,
400
401    /// Struct reader had bitwidth other than 1
402    StructReaderHadBitwidthOtherThan1,
403
404    /// Text blob missing NUL terminator.
405    TextBlobMissingNULTerminator,
406
407    /// Text contains non-utf8 data
408    TextContainsNonUtf8Data(core::str::Utf8Error),
409
410    /// Tried to read from null arena
411    TriedToReadFromNullArena,
412
413    /// type mismatch
414    TypeMismatch,
415
416    /// Detected unaligned segment. You must either ensure all of your segments are 8-byte aligned,
417    /// or you must enable the "unaligned" feature in the capnp crate
418    UnalignedSegment,
419
420    /// Unexpected far pointer
421    UnexpectedFarPointer,
422
423    /// Unknown pointer type.
424    UnknownPointerType,
425}
426
427impl Error {
428    /// Writes to the `extra` field. Does nothing if the "alloc" feature is not enabled.
429    /// This is intended to be used with the `write!()` macro from core.
430    pub fn write_fmt(&mut self, fmt: core::fmt::Arguments<'_>) {
431        #[cfg(feature = "alloc")]
432        {
433            use core::fmt::Write;
434            let _ = self.extra.write_fmt(fmt);
435        }
436    }
437
438    #[cfg(feature = "alloc")]
439    pub fn failed(description: alloc::string::String) -> Self {
440        Self {
441            extra: description,
442            kind: ErrorKind::Failed,
443        }
444    }
445
446    pub fn from_kind(kind: ErrorKind) -> Self {
447        #[cfg(not(feature = "alloc"))]
448        return Self { kind };
449        #[cfg(feature = "alloc")]
450        return Self {
451            kind,
452            extra: alloc::string::String::new(),
453        };
454    }
455
456    #[cfg(feature = "alloc")]
457    pub fn overloaded(description: alloc::string::String) -> Self {
458        Self {
459            extra: description,
460            kind: ErrorKind::Overloaded,
461        }
462    }
463    #[cfg(feature = "alloc")]
464    pub fn disconnected(description: alloc::string::String) -> Self {
465        Self {
466            extra: description,
467            kind: ErrorKind::Disconnected,
468        }
469    }
470
471    #[cfg(feature = "alloc")]
472    pub fn unimplemented(description: alloc::string::String) -> Self {
473        Self {
474            extra: description,
475            kind: ErrorKind::Unimplemented,
476        }
477    }
478}
479
480#[cfg(feature = "std")]
481impl core::convert::From<::std::io::Error> for Error {
482    fn from(err: ::std::io::Error) -> Self {
483        use std::io;
484        let kind = match err.kind() {
485            io::ErrorKind::TimedOut => ErrorKind::Overloaded,
486            io::ErrorKind::BrokenPipe
487            | io::ErrorKind::ConnectionRefused
488            | io::ErrorKind::ConnectionReset
489            | io::ErrorKind::ConnectionAborted
490            | io::ErrorKind::NotConnected => ErrorKind::Disconnected,
491            io::ErrorKind::UnexpectedEof => ErrorKind::PrematureEndOfFile,
492            _ => ErrorKind::Failed,
493        };
494        #[cfg(feature = "alloc")]
495        return Self {
496            kind,
497            extra: format!("{err}"),
498        };
499        #[cfg(not(feature = "alloc"))]
500        return Self { kind };
501    }
502}
503
504#[cfg(feature = "embedded-io")]
505impl From<embedded_io::ErrorKind> for ErrorKind {
506    fn from(value: embedded_io::ErrorKind) -> Self {
507        match value {
508            embedded_io::ErrorKind::Other => Self::Failed,
509            embedded_io::ErrorKind::NotFound => Self::Failed,
510            embedded_io::ErrorKind::PermissionDenied => Self::Failed,
511            embedded_io::ErrorKind::ConnectionRefused => Self::Failed,
512            embedded_io::ErrorKind::ConnectionReset => Self::Failed,
513            embedded_io::ErrorKind::ConnectionAborted => Self::Failed,
514            embedded_io::ErrorKind::NotConnected => Self::Failed,
515            embedded_io::ErrorKind::AddrInUse => Self::Failed,
516            embedded_io::ErrorKind::AddrNotAvailable => Self::Failed,
517            embedded_io::ErrorKind::BrokenPipe => Self::Failed,
518            embedded_io::ErrorKind::AlreadyExists => Self::Failed,
519            embedded_io::ErrorKind::InvalidInput => Self::Failed,
520            embedded_io::ErrorKind::InvalidData => Self::Failed,
521            embedded_io::ErrorKind::TimedOut => Self::Failed,
522            embedded_io::ErrorKind::Interrupted => Self::Failed,
523            embedded_io::ErrorKind::Unsupported => Self::Failed,
524            embedded_io::ErrorKind::OutOfMemory => Self::Failed,
525            _ => Self::Failed,
526        }
527    }
528}
529
530#[cfg(feature = "alloc")]
531impl core::convert::From<alloc::string::FromUtf8Error> for Error {
532    fn from(err: alloc::string::FromUtf8Error) -> Self {
533        Self::failed(format!("{err}"))
534    }
535}
536
537impl core::convert::From<core::str::Utf8Error> for Error {
538    fn from(err: core::str::Utf8Error) -> Self {
539        Self::from_kind(ErrorKind::TextContainsNonUtf8Data(err))
540    }
541}
542
543impl core::convert::From<NotInSchema> for Error {
544    fn from(e: NotInSchema) -> Self {
545        Self::from_kind(ErrorKind::EnumValueOrUnionDiscriminantNotPresent(e))
546    }
547}
548
549impl core::fmt::Display for ErrorKind {
550    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
551        match self {
552            Self::Failed => write!(fmt, "Failed"),
553            Self::Overloaded => write!(fmt, "Overloaded"),
554            Self::Disconnected => write!(fmt, "Disconnected"),
555            Self::Unimplemented => write!(fmt, "Unimplemented"),
556            Self::BufferNotLargeEnough => write!(fmt, "buffer is not large enough"),
557            Self::ExistingListPointerIsNotByteSized => write!(fmt, "Called get_writable_{{data|text}}_pointer() but existing list pointer is not byte-sized."),
558            Self::ExistingPointerIsNotAList => write!(fmt, "Called get_writable_{{data|text|list|struct_list}}_pointer() but existing pointer is not a list."),
559            Self::CannotCreateACanonicalMessageWithACapability => write!(fmt, "Cannot create a canonical message with a capability"),
560            Self::FourByteLengthTooBigForUSize => write!(fmt, "Cannot represent 4 byte length as `usize`. This may indicate that you are running on 8 or 16 bit platform or message is too large."),
561            Self::FourByteSegmentLengthTooBigForUSize => write!(fmt, "Cannot represent 4 byte segment length as usize. This may indicate that you are running on 8 or 16 bit platform or segment is too large"),
562            Self::CannotSetAnyPointerFieldToAPrimitiveValue => write!(fmt, "cannot set AnyPointer field to a primitive value"),
563            Self::CantHandleNonStructInlineComposite => write!(fmt, "Don't know how to handle non-STRUCT inline composite."),
564            Self::EmptyBuffer => write!(fmt, "empty buffer"),
565            Self::EmptySlice => write!(fmt, "empty slice"),
566            Self::EnumValueOrUnionDiscriminantNotPresent(val) => write!(fmt, "Enum value or union discriminant {val} was not present in schema"),
567            Self::ExistingListValueIsIncompatibleWithExpectedType => write!(fmt, "Existing list value is incompatible with expected type."),
568            Self::ExpectedAListOrBlob => write!(fmt, "Expected a list or blob."),
569            Self::ExpectedAPointerListButGotAListOfDataOnlyStructs => write!(fmt, "Expected a pointer list, but got a list of data-only structs"),
570            Self::ExpectedAPrimitiveListButGotAListOfPointerOnlyStructs => write!(fmt, "Expected a primitive list, but got a list of pointer-only structs"),
571            Self::FailedToFillTheWholeBuffer => write!(fmt, "failed to fill the whole buffer"),
572            Self::FieldAndDefaultMismatch => write!(fmt, "field and default mismatch"),
573            Self::FieldNotFound => write!(fmt, "field not found"),
574            Self::FoundBitListWhereStructListWasExpected => write!(fmt, "Found bit list where struct list was expected; upgrading boolean lists to struct lists is no longer supported."),
575            Self::FoundStructListWhereBitListWasExpected => write!(fmt, "Found struct list where bit list was expected."),
576            Self::GroupFieldButTypeIsNotStruct => write!(fmt, "group field but type is not Struct"),
577            Self::InitIsOnlyValidForStructAndAnyPointerFields => write!(fmt, "init() is only valid for struct and AnyPointer fields"),
578            Self::InitnIsOnlyValidForListTextOrDataFields => write!(fmt, "initn() is only valid for list, text, or data fields"),
579            Self::InlineCompositeListWithNonStructElementsNotSupported => write!(fmt, "InlineComposite list with non-STRUCT elements not supported."),
580            Self::InlineCompositeListsElementsOverrunItsWordCount => write!(fmt, "InlineComposite list's elements overrun its word count."),
581            Self::InlineCompositeListsOfNonStructTypeAreNotSupported => write!(fmt, "InlineComposite lists of non-STRUCT type are not supported."),
582            Self::InvalidNumberOfSegments(segment_count) => write!(fmt, "Too many or too few segments {segment_count}"),
583            Self::InvalidSegmentId(id) => write!(fmt, "Invalid segment id {id}"),
584            Self::ListAnyPointerNotSupported => write!(fmt, "List(AnyPointer) not supported."),
585            Self::ListCapabilityNotSupported => write!(fmt, "List(Capability) not supported"),
586            Self::MalformedDoubleFarPointer => write!(fmt, "Malformed double-far pointer."),
587            Self::MessageContainsInvalidCapabilityPointer => write!(fmt, "Message contained invalid capability pointer."),
588            Self::MessageContainsListPointerOfNonBytesWhereDataWasExpected => write!(fmt, "Message contains list pointer of non-bytes where data was expected."),
589            Self::MessageContainsListPointerOfNonBytesWhereTextWasExpected => write!(fmt, "Message contains list pointer of non-bytes where text was expected."),
590            Self::MessageContainsListWithIncompatibleElementType => write!(fmt, "Message contains list with incompatible element type."),
591            Self::MessageContainsNonCapabilityPointerWhereCapabilityPointerWasExpected => write!(fmt, "Message contains non-capability pointer where capability pointer was expected."),
592            Self::MessageContainsNonListPointerWhereDataWasExpected => write!(fmt, "Message contains non-list pointer where data was expected."),
593            Self::MessageContainsNonListPointerWhereListPointerWasExpected => write!(fmt, "Message contains non-list pointer where list pointer was expected"),
594            Self::MessageContainsNonListPointerWhereTextWasExpected => write!(fmt, "Message contains non-list pointer where text was expected."),
595            Self::MessageContainsNonStructPointerWhereStructPointerWasExpected => write!(fmt, "Message contains non-struct pointer where struct pointer was expected."),
596            Self::MessageContainsNullCapabilityPointer => write!(fmt, "Message contains null capability pointer."),
597            Self::MessageContainsOutOfBoundsPointer => write!(fmt, "Message contains out-of-bounds pointer"),
598            Self::MessageContainsTextThatIsNotNULTerminated => write!(fmt, "Message contains text that is not NUL-terminated"),
599            Self::MessageEndsPrematurely(header, body) => write!(fmt, "Message ends prematurely. Header claimed {header} words, but message only has {body} words"),
600            Self::MessageIsTooDeeplyNested => write!(fmt, "Message is too deeply nested."),
601            Self::MessageIsTooDeeplyNestedOrContainsCycles => write!(fmt, "Message is too deeply-nested or contains cycles."),
602            Self::MessageSizeOverflow => write!(fmt, "Message's size cannot be represented in usize"),
603            Self::MessageTooLarge(val) => write!(fmt, "Message is too large: {val}"),
604            Self::MessageNotAlignedBy8BytesBoundary => write!(fmt, "Message was not aligned by 8 bytes boundary. Either ensure that message is properly aligned or compile `capnp` crate with \"unaligned\" feature enabled."),
605            Self::NestingLimitExceeded => write!(fmt, "nesting limit exceeded"),
606            Self::NotAStruct => write!(fmt, "not a struct"),
607            Self::OnlyOneOfTheSectionPointersIsPointingToOurself => write!(fmt, "Only one of the section pointers is pointing to ourself"),
608            Self::PackedInputDidNotEndCleanlyOnASegmentBoundary => write!(fmt, "Packed input did not end cleanly on a segment boundary."),
609            Self::PrematureEndOfFile => write!(fmt, "Premature end of file"),
610            Self::PrematureEndOfPackedInput => write!(fmt, "Premature end of packed input."),
611            Self::ReadLimitExceeded => write!(fmt, "Read limit exceeded"),
612            Self::SettingDynamicCapabilitiesIsUnsupported => write!(fmt, "setting dynamic capabilities is unsupported"),
613            Self::StructReaderHadBitwidthOtherThan1 => write!(fmt, "struct reader had bitwidth other than 1"),
614            Self::TextBlobMissingNULTerminator => write!(fmt, "Text blob missing NUL terminator."),
615            Self::TextContainsNonUtf8Data(e) => write!(fmt, "Text contains non-utf8 data: {e}"),
616            Self::TriedToReadFromNullArena => write!(fmt, "Tried to read from null arena"),
617            Self::TypeMismatch => write!(fmt, "type mismatch"),
618            Self::UnalignedSegment => write!(fmt, "Detected unaligned segment. You must either ensure all of your segments are 8-byte aligned, or you must enable the \"unaligned\" feature in the capnp crate"),
619            Self::UnexpectedFarPointer => write!(fmt, "Unexpected far pointer"),
620            Self::UnknownPointerType => write!(fmt, "Unknown pointer type."),
621        }
622    }
623}
624
625impl core::fmt::Display for Error {
626    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
627        #[cfg(feature = "alloc")]
628        let result = if self.extra.is_empty() {
629            write!(fmt, "{}", self.kind)
630        } else {
631            write!(fmt, "{}: {}", self.kind, self.extra)
632        };
633        #[cfg(not(feature = "alloc"))]
634        let result = write!(fmt, "{}", self.kind);
635        result
636    }
637}
638
639impl core::error::Error for Error {
640    #[cfg(feature = "alloc")]
641    fn description(&self) -> &str {
642        &self.extra
643    }
644    fn cause(&self) -> Option<&dyn ::core::error::Error> {
645        None
646    }
647}
648
649/// Helper struct that allows `MessageBuilder::get_segments_for_output()` to avoid heap allocations
650/// in the single-segment case.
651pub enum OutputSegments<'a> {
652    SingleSegment([&'a [u8]; 1]),
653
654    #[cfg(feature = "alloc")]
655    MultiSegment(alloc::vec::Vec<&'a [u8]>),
656}
657
658impl<'a> core::ops::Deref for OutputSegments<'a> {
659    type Target = [&'a [u8]];
660    fn deref(&self) -> &[&'a [u8]] {
661        match self {
662            OutputSegments::SingleSegment(s) => s,
663
664            #[cfg(feature = "alloc")]
665            OutputSegments::MultiSegment(v) => v,
666        }
667    }
668}
669
670impl message::ReaderSegments for OutputSegments<'_> {
671    fn get_segment(&self, id: u32) -> Option<&[u8]> {
672        match self {
673            OutputSegments::SingleSegment(s) => s.get(id as usize).copied(),
674
675            #[cfg(feature = "alloc")]
676            OutputSegments::MultiSegment(v) => v.get(id as usize).copied(),
677        }
678    }
679}