use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum ValidationLevel {
Structure = 1,
Metadata = 2,
Integrity = 3,
Fidelity = 4,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum IssueSeverity {
Error,
Warning,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IssueCode {
BufferTooShort,
InvalidMagic,
PreambleParseFailed,
TotalLengthOverflow,
TotalLengthExceedsBuffer,
TotalLengthTooSmall,
PostambleInvalid,
FooterOffsetOutOfRange,
FooterOffsetMismatch,
TruncatedFrameHeader,
InvalidFrameHeader,
FrameLengthOverflow,
FrameTooSmall,
FrameExceedsMessage,
MissingEndMarker,
FrameOrderViolation,
PrecederNotFollowedByObject,
DanglingPreceder,
CborOffsetInvalid,
CborBeforeBoundaryUnknown,
DataObjectTooSmall,
NonZeroPadding,
FlagMismatch,
NoMetadataFrame,
MetadataCborParseFailed,
MetadataCborNonCanonical,
IndexCborParseFailed,
IndexCountMismatch,
IndexOffsetMismatch,
HashFrameCborParseFailed,
HashFrameCountMismatch,
PrecederCborParseFailed,
PrecederCborNonCanonical,
PrecederBaseCountWrong,
BaseCountExceedsObjects,
DescriptorCborParseFailed,
DescriptorCborNonCanonical,
NdimShapeMismatch,
StridesShapeMismatch,
ShapeOverflow,
UnknownEncoding,
UnknownFilter,
UnknownCompression,
EmptyObjType,
ReservedNotAMap,
ReservedMissingTensor,
HashMismatch,
HashVerificationError,
UnknownHashAlgorithm,
NoHashAvailable,
DecodePipelineFailed,
PipelineConfigFailed,
DecodeObjectFailed,
DecodedSizeMismatch,
NanDetected,
InfDetected,
}
pub(crate) enum DecodeState {
NotDecoded,
Decoded(Vec<u8>),
DecodeFailed,
}
pub(crate) struct ObjectContext<'a> {
pub descriptor: Option<crate::types::DataObjectDescriptor>,
pub descriptor_failed: bool,
pub cbor_bytes: &'a [u8],
pub payload: &'a [u8],
pub frame_offset: usize,
pub decode_state: DecodeState,
}
#[derive(Debug, Clone, Serialize)]
pub struct ValidationIssue {
pub code: IssueCode,
pub level: ValidationLevel,
pub severity: IssueSeverity,
#[serde(skip_serializing_if = "Option::is_none")]
pub object_index: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub byte_offset: Option<usize>,
pub description: String,
}
#[derive(Debug, Clone)]
pub struct ValidateOptions {
pub max_level: ValidationLevel,
pub check_canonical: bool,
pub checksum_only: bool,
}
impl Default for ValidateOptions {
fn default() -> Self {
Self {
max_level: ValidationLevel::Integrity,
check_canonical: false,
checksum_only: false,
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct ValidationReport {
pub issues: Vec<ValidationIssue>,
pub object_count: usize,
pub hash_verified: bool,
}
impl ValidationReport {
pub fn is_ok(&self) -> bool {
!self
.issues
.iter()
.any(|i| i.severity == IssueSeverity::Error)
}
}
#[derive(Debug, Clone, Serialize)]
pub struct FileIssue {
pub byte_offset: usize,
pub length: usize,
pub description: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct FileValidationReport {
pub file_issues: Vec<FileIssue>,
pub messages: Vec<ValidationReport>,
}
impl FileValidationReport {
pub fn is_ok(&self) -> bool {
self.file_issues.is_empty() && self.messages.iter().all(|r| r.is_ok())
}
pub fn total_objects(&self) -> usize {
self.messages.iter().map(|r| r.object_count).sum()
}
pub fn hash_verified(&self) -> bool {
!self.messages.is_empty() && self.messages.iter().all(|r| r.hash_verified)
}
}
pub(crate) fn issue(
code: IssueCode,
level: ValidationLevel,
severity: IssueSeverity,
object_index: Option<usize>,
byte_offset: Option<usize>,
description: impl Into<String>,
) -> ValidationIssue {
ValidationIssue {
code,
level,
severity,
object_index,
byte_offset,
description: description.into(),
}
}
pub(crate) fn err(
code: IssueCode,
level: ValidationLevel,
object_index: Option<usize>,
byte_offset: Option<usize>,
description: impl Into<String>,
) -> ValidationIssue {
issue(
code,
level,
IssueSeverity::Error,
object_index,
byte_offset,
description,
)
}
pub(crate) fn warn(
code: IssueCode,
level: ValidationLevel,
object_index: Option<usize>,
byte_offset: Option<usize>,
description: impl Into<String>,
) -> ValidationIssue {
issue(
code,
level,
IssueSeverity::Warning,
object_index,
byte_offset,
description,
)
}