1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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; }
}