use alloc::borrow::ToOwned;
use alloc::collections::BTreeMap;
use alloc::string::String;
use core::marker::PhantomData;
use super::constants::LIBS_MAX_TOTAL;
use super::*;
use crate::isa::InstructionSet;
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[cfg_attr(feature = "std", derive(Error))]
#[display(doc_comments)]
pub enum LibError {
IsaNotSupported(String),
TooManyLibs,
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "strict_encoding", derive(StrictEncode, StrictDecode))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]
pub struct Program<Isa, const RUNTIME_MAX_TOTAL_LIBS: u16 = LIBS_MAX_TOTAL>
where
Isa: InstructionSet,
{
libs: BTreeMap<LibId, Lib>,
entrypoint: LibSite,
#[cfg_attr(feature = "strict_encoding", strict_encoding(skip))]
#[cfg_attr(feature = "serde", serde(skip))]
phantom: PhantomData<Isa>,
}
impl<Isa, const RUNTIME_MAX_TOTAL_LIBS: u16> Program<Isa, RUNTIME_MAX_TOTAL_LIBS>
where
Isa: InstructionSet,
{
const RUNTIME_MAX_TOTAL_LIBS: u16 = RUNTIME_MAX_TOTAL_LIBS;
fn empty_unchecked() -> Self {
Program {
libs: BTreeMap::new(),
entrypoint: LibSite::with(0, zero!()),
phantom: default!(),
}
}
pub fn new(lib: Lib) -> Self {
let mut runtime = Self::empty_unchecked();
let id = lib.id();
runtime.add_lib(lib).expect("adding single library to lib segment overflows");
runtime.set_entrypoint(LibSite::with(0, id));
runtime
}
pub fn with(
libs: impl IntoIterator<Item = Lib>,
entrypoint: LibSite,
) -> Result<Self, LibError> {
let mut runtime = Self::empty_unchecked();
for lib in libs {
runtime.add_lib(lib)?;
}
runtime.set_entrypoint(entrypoint);
Ok(runtime)
}
pub fn lib(&self, id: LibId) -> Option<&Lib> { self.libs.get(&id) }
#[inline]
pub fn add_lib(&mut self, lib: Lib) -> Result<bool, LibError> {
if self.libs_count() >= LIBS_MAX_TOTAL.min(Self::RUNTIME_MAX_TOTAL_LIBS) {
return Err(LibError::TooManyLibs);
}
for isa in &lib.isae {
if !Isa::is_supported(isa) {
return Err(LibError::IsaNotSupported(isa.to_owned()));
}
}
Ok(self.libs.insert(lib.id(), lib).is_none())
}
pub fn libs_count(&self) -> u16 { self.libs.len() as u16 }
pub fn entrypoint(&self) -> LibSite { self.entrypoint }
pub fn set_entrypoint(&mut self, entrypoint: LibSite) { self.entrypoint = entrypoint; }
}