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