use super::{ChunkOffset, ExternalDictionaryRequest, ResourceDataPosition, ResourceIndex};
use crate::{DecodeError, dictionary::DecodeDictionaryError};
use core::ops::Range;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FramedLimitKind {
InputBytes,
OutputBytes,
DecodedBytes,
ResourceBytes,
WorkspaceBytes,
FramingBytes,
DictionaryBytes,
MetadataBytes,
MetadataFields,
Resources,
Chunks,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum UnexpectedInputKind {
SerializedDictionary,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct FramedDecodeLocation {
pub offset: u64,
pub(super) chunk: Option<core::num::NonZeroU64>,
pub(super) resource: Option<core::num::NonZeroU64>,
}
impl FramedDecodeLocation {
pub const fn chunk(self) -> Option<ChunkOffset> {
match self.chunk {
Some(n) => Some(ChunkOffset(n.get())),
None => None,
}
}
pub const fn resource(self) -> Option<ResourceIndex> {
match self.resource {
Some(n) => Some(ResourceIndex(n.get() - 1)),
None => None,
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FramedDecodeError {
#[error("invalid framing signature")]
InvalidSignature,
#[error("invalid framing header")]
InvalidHeader,
#[error("invalid chunk header or content")]
InvalidChunk,
#[error("invalid chunk order")]
InvalidOrder,
#[error("invalid metadata fields")]
InvalidMetadata,
#[error("invalid internal dictionary reference")]
InvalidDictionaryReference,
#[error("internal dictionary references are disabled by policy")]
InternalDictionaryReferencesDisabled,
#[error("central directory does not match wire records")]
InvalidDirectory,
#[error("invalid container footer")]
InvalidFooter,
#[error("unexpected end of input")]
UnexpectedEndOfInput,
#[error("data follows the top-level object")]
TrailingData,
#[error("output slice cannot hold resource payload")]
OutputTooSmall,
#[error("framing size overflow")]
SizeOverflow,
#[error("framing allocation failed")]
AllocationFailed,
#[error("decoder has an abandoned session")]
AbandonedSession,
#[error("invalid framed decoder state")]
InvalidState,
#[error("unexpected input kind: {0:?}")]
UnexpectedInputKind(UnexpectedInputKind),
#[error("unsupported framing version {0}")]
UnsupportedVersion(u8),
#[error("declared size {expected} differs from decoded size {actual}")]
DeclaredSizeMismatch {
expected: u64,
actual: u64,
},
#[error("framing {kind:?} exceeds {limit}")]
LimitExceeded {
kind: FramedLimitKind,
limit: u64,
},
#[error("missing dictionary {request:?} at {location:?}")]
MissingDictionary {
request: ExternalDictionaryRequest,
location: FramedDecodeLocation,
},
#[error("Brotli decoding failed at {location:?}: {source}")]
Decode {
#[source]
source: DecodeError,
location: FramedDecodeLocation,
},
#[error("dictionary preparation failed at {location:?}: {source}")]
Dictionary {
#[source]
source: DecodeDictionaryError,
location: FramedDecodeLocation,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ProducedFragment {
pub range: Range<usize>,
pub position: ResourceDataPosition,
}
#[derive(Debug, thiserror::Error)]
#[error("{error}")]
pub struct FramedDecodeFailure {
#[source]
pub error: FramedDecodeError,
pub consumed: usize,
pub produced: usize,
pub last_output: Option<ProducedFragment>,
}
impl FramedDecodeFailure {
pub fn into_error(self) -> FramedDecodeError {
self.error
}
}