1use javm_cap::{CNodeCap, CacheDirectory, Cap, CapHashOrRef, SlotIdx, SlotPath};
27
28use crate::error::VmError;
29
30pub struct MainFrame<'a> {
32 cnode: &'a CNodeCap,
33 pinned: &'a [SlotIdx],
34 cache: &'a CacheDirectory,
35}
36
37impl<'a> MainFrame<'a> {
38 pub fn new(cnode: &'a CNodeCap, pinned: &'a [SlotIdx], cache: &'a CacheDirectory) -> Self {
39 Self {
40 cnode,
41 pinned,
42 cache,
43 }
44 }
45
46 pub fn size_log(&self) -> u8 {
48 self.cnode.size_log
49 }
50
51 pub fn is_pinned(&self, idx: SlotIdx) -> bool {
53 self.pinned.binary_search(&idx).is_ok()
54 }
55
56 pub fn get(&self, idx: SlotIdx) -> Option<CapHashOrRef> {
58 self.cnode.get(idx)
59 }
60
61 pub fn resolve(&self, path: &SlotPath) -> Result<Option<CapHashOrRef>, VmError> {
69 let prefix = path.prefix();
70 if prefix.is_empty() {
71 return Ok(self.cnode.get(path.target()));
72 }
73 let mut current = self.cnode.clone();
79 for step in prefix {
80 let target = current.get(*step).ok_or(VmError::SlotEmpty(step.get()))?;
81 let cap = self
82 .cache
83 .get(target)
84 .ok_or(VmError::SlotKindMismatch(step.get()))?;
85 match &*cap {
86 Cap::CNode(inner) => {
87 current = inner.clone();
88 }
89 _ => return Err(VmError::SlotKindMismatch(step.get())),
90 }
91 }
92 Ok(current.get(path.target()))
93 }
94}
95
96pub struct BareFrame<'a> {
101 main: MainFrame<'a>,
102}
103
104impl<'a> BareFrame<'a> {
105 pub fn new(cnode: &'a CNodeCap, pinned: &'a [SlotIdx], cache: &'a CacheDirectory) -> Self {
106 Self {
107 main: MainFrame::new(cnode, pinned, cache),
108 }
109 }
110
111 pub fn get(&self, idx: SlotIdx) -> Option<CapHashOrRef> {
115 if self.main.is_pinned(idx) {
116 self.main.get(idx)
117 } else {
118 None
119 }
120 }
121
122 pub fn pinned_slots(&self) -> impl Iterator<Item = &SlotIdx> {
124 self.main.pinned.iter()
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use javm_cap::CacheDirectory;
132
133 fn empty_cache() -> CacheDirectory {
134 CacheDirectory::new()
135 }
136
137 #[test]
138 fn mainframe_get_root_slot() {
139 let mut cn = CNodeCap::new(8).unwrap();
140 cn.set(SlotIdx(5), Some(CapHashOrRef::Hash([1u8; 32])))
141 .unwrap();
142 let cache = empty_cache();
143 let m = MainFrame::new(&cn, &[], &cache);
144 assert!(m.get(SlotIdx(5)).is_some());
145 assert!(m.get(SlotIdx(6)).is_none());
146 }
147
148 #[test]
149 fn mainframe_is_pinned_reads_pinned_list() {
150 let cn = CNodeCap::new(8).unwrap();
151 let cache = empty_cache();
152 let pinned = vec![SlotIdx(2), SlotIdx(5)];
153 let m = MainFrame::new(&cn, &pinned, &cache);
154 assert!(m.is_pinned(SlotIdx(2)));
155 assert!(!m.is_pinned(SlotIdx(3)));
156 assert!(m.is_pinned(SlotIdx(5)));
157 }
158
159 #[test]
160 fn mainframe_resolve_root_path() {
161 let mut cn = CNodeCap::new(8).unwrap();
162 cn.set(SlotIdx(9), Some(CapHashOrRef::Hash([7u8; 32])))
163 .unwrap();
164 let cache = empty_cache();
165 let m = MainFrame::new(&cn, &[], &cache);
166 let p = SlotPath::root(SlotIdx(9));
167 let got = m.resolve(&p).unwrap();
168 assert_eq!(got, Some(CapHashOrRef::Hash([7u8; 32])));
169 }
170
171 #[test]
172 fn mainframe_resolve_empty_intermediate_errors() {
173 let cn = CNodeCap::new(8).unwrap();
174 let cache = empty_cache();
175 let m = MainFrame::new(&cn, &[], &cache);
176 let p = SlotPath::new(vec![SlotIdx(7), SlotIdx(0)]).unwrap();
177 let res = m.resolve(&p);
178 assert!(matches!(res, Err(VmError::SlotEmpty(7))));
179 }
180
181 #[test]
182 fn bareframe_only_reads_pinned() {
183 let mut cn = CNodeCap::new(8).unwrap();
184 cn.set(SlotIdx(2), Some(CapHashOrRef::Hash([3u8; 32])))
185 .unwrap();
186 cn.set(SlotIdx(3), Some(CapHashOrRef::Hash([4u8; 32])))
187 .unwrap();
188 let cache = empty_cache();
189 let pinned = vec![SlotIdx(2)];
190 let b = BareFrame::new(&cn, &pinned, &cache);
191 assert!(b.get(SlotIdx(2)).is_some());
193 assert!(b.get(SlotIdx(3)).is_none());
195 }
196}