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