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