image4 0.8.2

A no_std-friendly library for parsing and generation of Image4 images written in pure Rust.
Documentation
//! Contains everything needed to implement Image4 properties parsing.
//!
//! # Warning
//!
//! This module exposes an implementation detail of the Image4 format and isn't very useful on its
//! own. Please use types from the [`manifest`] and [`payload`] modules if you want to parse
//! manifests or payload properties.
//!
//! # `no_alloc` API
//!
//! The `no_alloc` API expects you to drive the decoding yourself. The [`ValueRef`] type that
//! represents a value of a property only decodes values of primitive types. Data buffers are stored
//! as slices of the original decoded buffer, dictionaries and arrays are returned as the
//! [`DictRef`] and [`ArrayRef`] types which store a reference to their DER-encoded contents rather
//! than decode the actual values and store them elsewhere. Decoding the latter is possible by using
//! the iterators returned by their `.iter()` method:
//!
//! ```
//! # use image4::property::ValueDictRef;
//! # use der::Decode;
//! # fn main() -> der::Result<()> {
//! # let bytes = include_bytes!("../../tests/data/small-dict.der");
//! let dict = ValueDictRef::from_der(bytes)?;
//!
//! for result in dict.iter()? {
//!     let (_tag, _value) = result?;
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # `alloc` API
//!
//! The `alloc` API, unlike its `no_alloc` counterpart, has access to a memory allocator and takes
//! a different approach: it provides the [`Value`] type that decodes the property completely even
//! for complex types. Dictionaries and arrays are represented using [`BTreeMap`]s and [`Vec`]s and
//! thus are completely decoded when the property itself is decoded.
//!
//! The `alloc` feature also adds [`Dict`] and [`Array`] types that are just owned versions of
//! [`DictRef`] and [`ArrayRef`].
//!
//! # Constraints and traits
//!
//! There are three places where you can find Image4 property lists currently: manifest bodies,
//! payload properties (the `PAYP` blobs) and extensions inside X.509 certificates which are used to
//! sign the manifests. The first two contain regular plist-like values, but since the latter is
//! used to check if a certificate is allowed to sign a particular manifest it has two additional
//! values: a catch-all *"any"* value that matches anything and a *"deny"* value that disallows
//! presence of a specific tag. That allows to make certificates with fine-grained permissions while
//! ensuring that even when the key is leaked one can not use it to sign manifests for chips the
//! certificate wasn't intended to be used with. I've called properties which may take these
//! additional values *constraints*.
//!
//! *Constraints* are represented using two types similarly to regular values: [`ConstraintRef`] and
//! [`Constraint`], the first one is a `no_alloc` version another one is its `alloc` counterpart. This
//! creates a little confusion: both [`DictRef`] and [`ArrayRef`] are used by [`ValueRef`] and
//! [`ConstraintRef`] types. What should their iterators return when decoding values?
//!
//! This is solved by using generics:
//!
//! * The iterators depend on values implementing the [`DecodeProperty`] trait. It's needed to
//!   restrict what types can be used as generic arguments by sealing the trait. All types
//!   representing any kind of Image4 property implement it.
//! * [`DictRef`] and [`ArrayRef`] need the [`PropertyRef`] trait. Another trait is required to
//!   allow easy conversion to their owned counterparts. [`ValueRef`] and [`ConstraintRef`] implement
//!   this trait.
//! * [`Dict`] and [`Array`] need the [`PropertyOwned`] trait which serves the same purpose as the
//!   [`PropertyRef`] trait but in the other direction. This one is implemented by [`Value`] and
//!   [`Constraint`] types. These types are used more like markers in this case.
//!
//! [`BTreeMap`]: alloc::collections::BTreeMap
//! [`Vec`]: alloc::vec::Vec
//! [`manifest`]: crate::manifest
//! [`payload`]: crate::payload

mod borrowed;
mod common;
pub mod iter;
#[cfg(any(feature = "alloc", test))]
mod owned;

pub use borrowed::{ArrayRef, ConstraintRef, DictRef, ValueRef};
pub use common::{DecodeProperty, PropertyRef};
#[cfg(any(feature = "alloc", test))]
pub use {
    common::PropertyOwned,
    owned::{Array, Constraint, Dict, Value},
};

/// An alias for a [`DictRef`] that stores regular values.
pub type ValueDictRef<'a> = DictRef<'a, ValueRef<'a>>;

/// An alias for a [`DictRef`] that stores constraints.
pub type ConstraintDictRef<'a> = DictRef<'a, ConstraintRef<'a>>;

/// An alias for a [`DictRef`] that stores regular values.
#[cfg(any(feature = "alloc", test))]
pub type ValueDict = Dict<Value>;

/// An alias for a [`DictRef`] that stores constraints.
#[cfg(any(feature = "alloc", test))]
pub type ConstraintDict = Dict<Constraint>;

/// An alias for an [`ArrayRef`] that stores regular values.
pub type ValueArrayRef<'a> = ArrayRef<'a, ValueRef<'a>>;

/// An alias for an [`ArrayRef`] that stores constraints.
pub type ConstraintArrayRef<'a> = ArrayRef<'a, ConstraintRef<'a>>;

/// An alias for an [`Array`] that stores regular values.
#[cfg(any(feature = "alloc", test))]
pub type ValueArray = Array<Value>;

/// An alias for an [`Array`] that stores constraints.
#[cfg(any(feature = "alloc", test))]
pub type ConstraintArray = Array<Constraint>;

#[cfg(test)]
mod tests;