#![cfg_attr(feature = "rpc_try", feature(try_trait_v2))]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;
pub mod schema_capnp;
pub mod any_pointer;
pub mod any_pointer_list;
pub mod capability;
pub mod capability_list;
pub mod constant;
pub mod data;
pub mod data_list;
pub mod dynamic_list;
pub mod dynamic_struct;
pub mod dynamic_value;
pub mod enum_list;
pub mod introspect;
pub mod io;
pub mod list_list;
pub mod message;
pub mod primitive_list;
pub mod private;
pub mod raw;
pub mod schema;
pub mod serialize;
pub mod serialize_packed;
pub(crate) mod stringify;
pub mod struct_list;
pub mod text;
pub mod text_list;
pub mod traits;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C, align(8))]
pub struct Word {
raw_content: [u8; 8],
}
#[allow(clippy::too_many_arguments)]
pub const fn word(b0: u8, b1: u8, b2: u8, b3: u8, b4: u8, b5: u8, b6: u8, b7: u8) -> Word {
Word {
raw_content: [b0, b1, b2, b3, b4, b5, b6, b7],
}
}
impl Word {
#[cfg(feature = "alloc")]
pub fn allocate_zeroed_vec(length: usize) -> Vec<Self> {
vec![word(0, 0, 0, 0, 0, 0, 0, 0); length]
}
pub fn words_to_bytes(words: &[Self]) -> &[u8] {
unsafe { core::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 8) }
}
pub fn words_to_bytes_mut(words: &mut [Self]) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(words.as_mut_ptr() as *mut u8, words.len() * 8) }
}
}
#[cfg(any(feature = "quickcheck", test))]
impl quickcheck::Arbitrary for Word {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
crate::word(
quickcheck::Arbitrary::arbitrary(g),
quickcheck::Arbitrary::arbitrary(g),
quickcheck::Arbitrary::arbitrary(g),
quickcheck::Arbitrary::arbitrary(g),
quickcheck::Arbitrary::arbitrary(g),
quickcheck::Arbitrary::arbitrary(g),
quickcheck::Arbitrary::arbitrary(g),
quickcheck::Arbitrary::arbitrary(g),
)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MessageSize {
pub word_count: u64,
pub cap_count: u32,
}
impl core::ops::AddAssign for MessageSize {
fn add_assign(&mut self, rhs: Self) {
self.word_count += rhs.word_count;
self.cap_count += rhs.cap_count;
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct NotInSchema(pub u16);
impl ::core::fmt::Display for NotInSchema {
fn fmt(
&self,
fmt: &mut ::core::fmt::Formatter,
) -> ::core::result::Result<(), ::core::fmt::Error> {
write!(
fmt,
"Enum value or union discriminant {} was not present in the schema.",
self.0
)
}
}
#[cfg(feature = "std")]
impl ::std::error::Error for NotInSchema {
fn description(&self) -> &str {
"Enum value or union discriminant was not present in schema."
}
}
pub type Result<T> = ::core::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct Error {
pub kind: ErrorKind,
#[cfg(feature = "alloc")]
pub extra: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
Failed,
Overloaded,
Disconnected,
Unimplemented,
BufferNotLargeEnough,
CannotCreateACanonicalMessageWithACapability,
CannotSetAnyPointerFieldToAPrimitiveValue,
CantHandleNonStructInlineComposite,
EmptyBuffer,
EmptySlice,
EnumValueOrUnionDiscriminantNotPresent(NotInSchema),
ExistingListPointerIsNotByteSized,
ExistingListValueIsIncompatibleWithExpectedType,
ExistingPointerIsNotAList,
ExpectedAListOrBlob,
ExpectedAPointerListButGotAListOfDataOnlyStructs,
ExpectedAPrimitiveListButGotAListOfPointerOnlyStructs,
FailedToFillTheWholeBuffer,
FieldAndDefaultMismatch,
FieldNotFound,
FoundBitListWhereStructListWasExpected,
FoundStructListWhereBitListWasExpected,
FourByteLengthTooBigForUSize,
FourByteSegmentLengthTooBigForUSize,
GroupFieldButTypeIsNotStruct,
InitIsOnlyValidForStructAndAnyPointerFields,
InitnIsOnlyValidForListTextOrDataFields,
InlineCompositeListWithNonStructElementsNotSupported,
InlineCompositeListsElementsOverrunItsWordCount,
InlineCompositeListsOfNonStructTypeAreNotSupported,
InvalidNumberOfSegments(usize),
InvalidSegmentId(u32),
ListAnyPointerNotSupported,
ListCapabilityNotSupported,
MalformedDoubleFarPointer,
MessageContainsInvalidCapabilityPointer,
MessageContainsListPointerOfNonBytesWhereDataWasExpected,
MessageContainsListPointerOfNonBytesWhereTextWasExpected,
MessageContainsListWithIncompatibleElementType,
MessageContainsNonCapabilityPointerWhereCapabilityPointerWasExpected,
MessageContainsNonStructPointerWhereStructPointerWasExpected,
MessageContainsNonListPointerWhereDataWasExpected,
MessageContainsNonListPointerWhereListPointerWasExpected,
MessageContainsNonListPointerWhereTextWasExpected,
MessageContainsNullCapabilityPointer,
MessageContainsOutOfBoundsPointer,
MessageContainsTextThatIsNotNULTerminated,
MessageEndsPrematurely(usize, usize),
MessageIsTooDeeplyNested,
MessageIsTooDeeplyNestedOrContainsCycles,
MessageNotAlignedBy8BytesBoundary,
MessageSizeOverflow,
MessageTooLarge(usize),
NestingLimitExceeded,
NotAStruct,
OnlyOneOfTheSectionPointersIsPointingToOurself,
PackedInputDidNotEndCleanlyOnASegmentBoundary,
PrematureEndOfFile,
PrematureEndOfPackedInput,
ReadLimitExceeded,
SettingDynamicCapabilitiesIsUnsupported,
StructReaderHadBitwidthOtherThan1,
TextBlobMissingNULTerminator,
TextContainsNonUtf8Data(core::str::Utf8Error),
TriedToReadFromNullArena,
TypeMismatch,
UnalignedSegment,
UnexepectedFarPointer,
UnknownPointerType,
}
impl Error {
pub fn write_fmt(&mut self, fmt: core::fmt::Arguments<'_>) {
#[cfg(feature = "alloc")]
{
use core::fmt::Write;
let _ = self.extra.write_fmt(fmt);
}
}
#[cfg(feature = "alloc")]
pub fn failed(description: String) -> Self {
Self {
extra: description,
kind: ErrorKind::Failed,
}
}
pub fn from_kind(kind: ErrorKind) -> Self {
#[cfg(not(feature = "alloc"))]
return Self { kind };
#[cfg(feature = "alloc")]
return Self {
kind,
extra: String::new(),
};
}
#[cfg(feature = "alloc")]
pub fn overloaded(description: String) -> Self {
Self {
extra: description,
kind: ErrorKind::Overloaded,
}
}
#[cfg(feature = "alloc")]
pub fn disconnected(description: String) -> Self {
Self {
extra: description,
kind: ErrorKind::Disconnected,
}
}
#[cfg(feature = "alloc")]
pub fn unimplemented(description: String) -> Self {
Self {
extra: description,
kind: ErrorKind::Unimplemented,
}
}
}
#[cfg(feature = "std")]
impl core::convert::From<::std::io::Error> for Error {
fn from(err: ::std::io::Error) -> Self {
use std::io;
let kind = match err.kind() {
io::ErrorKind::TimedOut => ErrorKind::Overloaded,
io::ErrorKind::BrokenPipe
| io::ErrorKind::ConnectionRefused
| io::ErrorKind::ConnectionReset
| io::ErrorKind::ConnectionAborted
| io::ErrorKind::NotConnected => ErrorKind::Disconnected,
io::ErrorKind::UnexpectedEof => ErrorKind::PrematureEndOfFile,
_ => ErrorKind::Failed,
};
#[cfg(feature = "alloc")]
return Self {
kind,
extra: format!("{err}"),
};
#[cfg(not(feature = "alloc"))]
return Self { kind };
}
}
#[cfg(feature = "embedded-io")]
impl From<embedded_io::ErrorKind> for ErrorKind {
fn from(value: embedded_io::ErrorKind) -> Self {
match value {
embedded_io::ErrorKind::Other => Self::Failed,
embedded_io::ErrorKind::NotFound => Self::Failed,
embedded_io::ErrorKind::PermissionDenied => Self::Failed,
embedded_io::ErrorKind::ConnectionRefused => Self::Failed,
embedded_io::ErrorKind::ConnectionReset => Self::Failed,
embedded_io::ErrorKind::ConnectionAborted => Self::Failed,
embedded_io::ErrorKind::NotConnected => Self::Failed,
embedded_io::ErrorKind::AddrInUse => Self::Failed,
embedded_io::ErrorKind::AddrNotAvailable => Self::Failed,
embedded_io::ErrorKind::BrokenPipe => Self::Failed,
embedded_io::ErrorKind::AlreadyExists => Self::Failed,
embedded_io::ErrorKind::InvalidInput => Self::Failed,
embedded_io::ErrorKind::InvalidData => Self::Failed,
embedded_io::ErrorKind::TimedOut => Self::Failed,
embedded_io::ErrorKind::Interrupted => Self::Failed,
embedded_io::ErrorKind::Unsupported => Self::Failed,
embedded_io::ErrorKind::OutOfMemory => Self::Failed,
_ => Self::Failed,
}
}
}
#[cfg(feature = "alloc")]
impl core::convert::From<alloc::string::FromUtf8Error> for Error {
fn from(err: alloc::string::FromUtf8Error) -> Self {
Self::failed(format!("{err}"))
}
}
impl core::convert::From<core::str::Utf8Error> for Error {
fn from(err: core::str::Utf8Error) -> Self {
Self::from_kind(ErrorKind::TextContainsNonUtf8Data(err))
}
}
impl core::convert::From<NotInSchema> for Error {
fn from(e: NotInSchema) -> Self {
Self::from_kind(ErrorKind::EnumValueOrUnionDiscriminantNotPresent(e))
}
}
impl core::fmt::Display for ErrorKind {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
match self {
Self::Failed => write!(fmt, "Failed"),
Self::Overloaded => write!(fmt, "Overloaded"),
Self::Disconnected => write!(fmt, "Disconnected"),
Self::Unimplemented => write!(fmt, "Unimplemented"),
Self::BufferNotLargeEnough => write!(fmt, "buffer is not large enough"),
Self::ExistingListPointerIsNotByteSized => write!(fmt, "Called get_writable_{{data|text}}_pointer() but existing list pointer is not byte-sized."),
Self::ExistingPointerIsNotAList => write!(fmt, "Called get_writable_{{data|text|list|struct_list}}_pointer() but existing pointer is not a list."),
Self::CannotCreateACanonicalMessageWithACapability => write!(fmt, "Cannot create a canonical message with a capability"),
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."),
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"),
Self::CannotSetAnyPointerFieldToAPrimitiveValue => write!(fmt, "cannot set AnyPointer field to a primitive value"),
Self::CantHandleNonStructInlineComposite => write!(fmt, "Don't know how to handle non-STRUCT inline composite."),
Self::EmptyBuffer => write!(fmt, "empty buffer"),
Self::EmptySlice => write!(fmt, "empty slice"),
Self::EnumValueOrUnionDiscriminantNotPresent(val) => write!(fmt, "Enum value or union discriminant {val} was not present in schema"),
Self::ExistingListValueIsIncompatibleWithExpectedType => write!(fmt, "Existing list value is incompatible with expected type."),
Self::ExpectedAListOrBlob => write!(fmt, "Expected a list or blob."),
Self::ExpectedAPointerListButGotAListOfDataOnlyStructs => write!(fmt, "Expected a pointer list, but got a list of data-only structs"),
Self::ExpectedAPrimitiveListButGotAListOfPointerOnlyStructs => write!(fmt, "Expected a primitive list, but got a list of pointer-only structs"),
Self::FailedToFillTheWholeBuffer => write!(fmt, "failed to fill the whole buffer"),
Self::FieldAndDefaultMismatch => write!(fmt, "field and default mismatch"),
Self::FieldNotFound => write!(fmt, "field not found"),
Self::FoundBitListWhereStructListWasExpected => write!(fmt, "Found bit list where struct list was expected; upgrading boolean lists to struct lists is no longer supported."),
Self::FoundStructListWhereBitListWasExpected => write!(fmt, "Found struct list where bit list was expected."),
Self::GroupFieldButTypeIsNotStruct => write!(fmt, "group field but type is not Struct"),
Self::InitIsOnlyValidForStructAndAnyPointerFields => write!(fmt, "init() is only valid for struct and AnyPointer fields"),
Self::InitnIsOnlyValidForListTextOrDataFields => write!(fmt, "initn() is only valid for list, text, or data fields"),
Self::InlineCompositeListWithNonStructElementsNotSupported => write!(fmt, "InlineComposite list with non-STRUCT elements not supported."),
Self::InlineCompositeListsElementsOverrunItsWordCount => write!(fmt, "InlineComposite list's elements overrun its word count."),
Self::InlineCompositeListsOfNonStructTypeAreNotSupported => write!(fmt, "InlineComposite lists of non-STRUCT type are not supported."),
Self::InvalidNumberOfSegments(segment_count) => write!(fmt, "Too many or too few segments {segment_count}"),
Self::InvalidSegmentId(id) => write!(fmt, "Invalid segment id {id}"),
Self::ListAnyPointerNotSupported => write!(fmt, "List(AnyPointer) not supported."),
Self::ListCapabilityNotSupported => write!(fmt, "List(Capability) not supported"),
Self::MalformedDoubleFarPointer => write!(fmt, "Malformed double-far pointer."),
Self::MessageContainsInvalidCapabilityPointer => write!(fmt, "Message contained invalid capability pointer."),
Self::MessageContainsListPointerOfNonBytesWhereDataWasExpected => write!(fmt, "Message contains list pointer of non-bytes where data was expected."),
Self::MessageContainsListPointerOfNonBytesWhereTextWasExpected => write!(fmt, "Message contains list pointer of non-bytes where text was expected."),
Self::MessageContainsListWithIncompatibleElementType => write!(fmt, "Message contains list with incompatible element type."),
Self::MessageContainsNonCapabilityPointerWhereCapabilityPointerWasExpected => write!(fmt, "Message contains non-capability pointer where capability pointer was expected."),
Self::MessageContainsNonListPointerWhereDataWasExpected => write!(fmt, "Message contains non-list pointer where data was expected."),
Self::MessageContainsNonListPointerWhereListPointerWasExpected => write!(fmt, "Message contains non-list pointer where list pointer was expected"),
Self::MessageContainsNonListPointerWhereTextWasExpected => write!(fmt, "Message contains non-list pointer where text was expected."),
Self::MessageContainsNonStructPointerWhereStructPointerWasExpected => write!(fmt, "Message contains non-struct pointer where struct pointer was expected."),
Self::MessageContainsNullCapabilityPointer => write!(fmt, "Message contains null capability pointer."),
Self::MessageContainsOutOfBoundsPointer => write!(fmt, "Message contains out-of-bounds pointer"),
Self::MessageContainsTextThatIsNotNULTerminated => write!(fmt, "Message contains text that is not NUL-terminated"),
Self::MessageEndsPrematurely(header, body) => write!(fmt, "Message ends prematurely. Header claimed {header} words, but message only has {body} words"),
Self::MessageIsTooDeeplyNested => write!(fmt, "Message is too deeply nested."),
Self::MessageIsTooDeeplyNestedOrContainsCycles => write!(fmt, "Message is too deeply-nested or contains cycles."),
Self::MessageSizeOverflow => write!(fmt, "Message's size cannot be represented in usize"),
Self::MessageTooLarge(val) => write!(fmt, "Message is too large: {val}"),
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."),
Self::NestingLimitExceeded => write!(fmt, "nesting limit exceeded"),
Self::NotAStruct => write!(fmt, "not a struct"),
Self::OnlyOneOfTheSectionPointersIsPointingToOurself => write!(fmt, "Only one of the section pointers is pointing to ourself"),
Self::PackedInputDidNotEndCleanlyOnASegmentBoundary => write!(fmt, "Packed input did not end cleanly on a segment boundary."),
Self::PrematureEndOfFile => write!(fmt, "Premature end of file"),
Self::PrematureEndOfPackedInput => write!(fmt, "Premature end of packed input."),
Self::ReadLimitExceeded => write!(fmt, "Read limit exceeded"),
Self::SettingDynamicCapabilitiesIsUnsupported => write!(fmt, "setting dynamic capabilities is unsupported"),
Self::StructReaderHadBitwidthOtherThan1 => write!(fmt, "struct reader had bitwidth other than 1"),
Self::TextBlobMissingNULTerminator => write!(fmt, "Text blob missing NUL terminator."),
Self::TextContainsNonUtf8Data(e) => write!(fmt, "Text contains non-utf8 data: {e}"),
Self::TriedToReadFromNullArena => write!(fmt, "Tried to read from null arena"),
Self::TypeMismatch => write!(fmt, "type mismatch"),
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"),
Self::UnexepectedFarPointer => write!(fmt, "Unexpected far pointer"),
Self::UnknownPointerType => write!(fmt, "Unknown pointer type."),
}
}
}
impl core::fmt::Display for Error {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
#[cfg(feature = "alloc")]
let result = if self.extra.is_empty() {
write!(fmt, "{}", self.kind)
} else {
write!(fmt, "{}: {}", self.kind, self.extra)
};
#[cfg(not(feature = "alloc"))]
let result = write!(fmt, "{}", self.kind);
result
}
}
#[cfg(feature = "std")]
impl ::std::error::Error for Error {
#[cfg(feature = "alloc")]
fn description(&self) -> &str {
&self.extra
}
fn cause(&self) -> Option<&dyn (::std::error::Error)> {
None
}
}
pub enum OutputSegments<'a> {
SingleSegment([&'a [u8]; 1]),
#[cfg(feature = "alloc")]
MultiSegment(Vec<&'a [u8]>),
}
impl<'a> core::ops::Deref for OutputSegments<'a> {
type Target = [&'a [u8]];
fn deref(&self) -> &[&'a [u8]] {
match self {
OutputSegments::SingleSegment(s) => s,
#[cfg(feature = "alloc")]
OutputSegments::MultiSegment(v) => v,
}
}
}
impl<'s> message::ReaderSegments for OutputSegments<'s> {
fn get_segment(&self, id: u32) -> Option<&[u8]> {
match self {
OutputSegments::SingleSegment(s) => s.get(id as usize).copied(),
#[cfg(feature = "alloc")]
OutputSegments::MultiSegment(v) => v.get(id as usize).copied(),
}
}
}