image4 0.8.2

A no_std-friendly library for parsing and generation of Image4 images written in pure Rust.
Documentation
use super::ImageRef;
use crate::{Manifest, Payload, RestoreInfo, Tag};
use alloc::{boxed::Box, vec::Vec};
use der::{
    referenced::{OwnedToRef, RefToOwned},
    Decode, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Writer,
};

/// An Image4 image that owns its data.
#[derive(Clone, Debug)]
pub struct Image {
    pub(super) payload: Payload,
    pub(super) manifest: Option<Box<Manifest>>,
    pub(super) restore_info: Option<RestoreInfo>,
}

impl Image {
    /// Creates a new [`Image`] which only contains a payload.
    pub fn new(tag: Tag, builder_string: &str, data: Vec<u8>) -> der::Result<Self> {
        Ok(Self {
            payload: Payload::new(tag, builder_string, data)?,
            manifest: None,
            restore_info: None,
        })
    }

    /// Creates a new image from a payload.
    pub fn from_payload(payload: Payload) -> Self {
        Self {
            payload,
            manifest: None,
            restore_info: None,
        }
    }

    /// Parses a DER encoded payload and creates an [`Image`] that contains it.
    pub fn from_payload_bytes(bytes: &[u8]) -> der::Result<Self> {
        Ok(Self {
            payload: Payload::from_der(bytes)?,
            manifest: None,
            restore_info: None,
        })
    }

    /// Parses a DER encoded Image4 manifest and stores the parsed [`Manifest`] in the image.
    pub fn parse_manifest(&mut self, bytes: &[u8]) -> der::Result<()> {
        self.manifest = Some(Box::new(Manifest::from_der(bytes)?));

        Ok(())
    }

    /// Returns an immutable reference to the payload of the image.
    pub fn payload(&self) -> &Payload {
        &self.payload
    }

    /// Returns a mutable reference to the payload of the image.
    pub fn payload_mut(&mut self) -> &mut Payload {
        &mut self.payload
    }

    /// Returns an immutable reference to the manifest of the image if any.
    pub fn manifest(&self) -> Option<&Manifest> {
        self.manifest.as_deref()
    }

    /// Returns a mutable reference to the manifest of the image if any.
    pub fn manifest_mut(&mut self) -> Option<&mut Manifest> {
        self.manifest.as_deref_mut()
    }

    /// Sets a new manifest for the image and returns the old one if any.
    pub fn set_manifest(&mut self, manifest: Option<Box<Manifest>>) -> Option<Box<Manifest>> {
        core::mem::replace(&mut self.manifest, manifest)
    }

    /// Returns an immutable reference to the restore info of the image if any.
    pub fn restore_info(&self) -> Option<&RestoreInfo> {
        self.restore_info.as_ref()
    }

    /// Returns a mutable reference to the restore info of the image if any.
    pub fn restore_info_mut(&mut self) -> Option<&mut RestoreInfo> {
        self.restore_info.as_mut()
    }

    /// Sets restore info of the image.
    pub fn set_restore_info(&mut self, restore_info: Option<RestoreInfo>) {
        self.restore_info = restore_info;
    }

    /// Decodes the part of an image after the magic string.
    ///
    /// May be used when it is required to first identify what kind of buffer you're looking at by
    /// checking the magic string.
    pub fn decode_after_magic<'a, R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
        ImageRef::decode_after_magic(decoder).map(Into::into)
    }
}

impl FixedTag for Image {
    const TAG: der::Tag = der::Tag::Sequence;
}

impl<'a> DecodeValue<'a> for Image {
    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
        ImageRef::decode_value(reader, header).map(Into::into)
    }
}

impl EncodeValue for Image {
    fn value_len(&self) -> der::Result<Length> {
        ImageRef::from(self).value_len()
    }

    fn encode_value(&self, encoder: &mut impl Writer) -> der::Result<()> {
        ImageRef::from(self).encode_value(encoder)
    }
}

impl From<&'_ ImageRef<'_>> for Image {
    fn from(value: &'_ ImageRef<'_>) -> Self {
        Self {
            payload: value.payload.ref_to_owned(),
            manifest: value.manifest.as_ref().map(|m| Box::new(m.ref_to_owned())),
            restore_info: value.restore_info.as_ref().map(RefToOwned::ref_to_owned),
        }
    }
}

impl From<ImageRef<'_>> for Image {
    fn from(value: ImageRef<'_>) -> Self {
        (&value).into()
    }
}

impl OwnedToRef for Image {
    type Borrowed<'a> = ImageRef<'a>;

    fn owned_to_ref(&self) -> Self::Borrowed<'_> {
        self.into()
    }
}