use alloc::borrow::Cow;
use alloc::vec::Vec;
use wasefire_error::{Code, Error};
use wasefire_wire::Wire;
use crate::common::AppletKind;
use crate::{Service as _, applet, platform};
pub const MAGIC: [u8; 4] = [0x3a, 0x5e, 0xf1, 0x2e];
pub const EXTENSION: &str = "wfb";
#[derive(Debug, Wire)]
#[wire(range = 2)]
pub enum Bundle<'a> {
#[wire(tag = 0)]
Platform0(Platform0<'a>),
#[wire(tag = 1)]
Applet0(Applet0<'a>),
}
impl<'a> Bundle<'a> {
pub fn encode(&self) -> Result<Vec<u8>, Error> {
let mut content = MAGIC.to_vec();
wasefire_wire::encode_suffix(&mut content, self)?;
Ok(content)
}
pub fn decode(content: &'a [u8]) -> Result<Self, Error> {
let Some((&magic, content)) = content.split_first_chunk::<4>() else {
return Err(Error::user(Code::InvalidLength));
};
if magic != MAGIC {
return Err(Error::user(Code::InvalidState));
}
wasefire_wire::decode(content)
}
pub fn platform(self) -> Result<Platform<'a>, Error> {
match self {
Bundle::Platform0(x) => Ok(Platform::V0(x)),
_ => Err(Error::user(Code::InvalidArgument)),
}
}
pub fn applet(self) -> Result<Applet<'a>, Error> {
match self {
Bundle::Applet0(x) => Ok(Applet::V0(x)),
_ => Err(Error::user(Code::InvalidArgument)),
}
}
}
#[derive(Debug, Wire)]
pub struct Platform0<'a> {
pub metadata: platform::SideInfo0<'a>,
pub side_a: Cow<'a, [u8]>,
pub side_b: Cow<'a, [u8]>,
}
pub enum Platform<'a> {
V0(Platform0<'a>),
}
impl<'a> Platform<'a> {
pub fn payloads(&self) -> (Vec<u8>, Vec<u8>) {
(self.side_a().to_vec(), self.side_b().to_vec())
}
pub fn side_a(&self) -> &[u8] {
match self {
Platform::V0(x) => &x.side_a,
}
}
pub fn side_b(&self) -> &[u8] {
match self {
Platform::V0(x) => &x.side_b,
}
}
}
#[derive(Debug, Wire)]
pub struct Applet0<'a> {
pub kind: AppletKind,
pub metadata: applet::Metadata0<'a>,
pub data: Cow<'a, [u8]>,
}
pub enum Applet<'a> {
V0(Applet0<'a>),
}
impl<'a> Applet<'a> {
pub fn payload(&self, version: u32) -> Result<Vec<u8>, Error> {
let mut result = self.data().to_vec();
let len = result.len() as u32;
match self {
Applet::V0(x) => {
if !crate::AppletMetadata0::VERSIONS.contains(version)? {
return Err(Error::internal(Code::NotImplemented));
}
wasefire_wire::encode_suffix(&mut result, &x.metadata)?;
}
}
result.extend_from_slice(&len.to_be_bytes());
Ok(result)
}
pub fn kind(&self) -> AppletKind {
match self {
Applet::V0(x) => x.kind,
}
}
pub fn data(&self) -> &[u8] {
match self {
Applet::V0(x) => &x.data,
}
}
}