xwasmi_validation/
util.rs1use crate::Error;
2#[allow(unused_imports)]
3use alloc::prelude::v1::*;
4use xwasm::elements::{Local, ValueType};
5
6#[cfg(test)]
7use assert_matches::assert_matches;
8
9#[derive(Debug)]
15pub struct Locals<'a> {
16 params: &'a [ValueType],
17 local_groups: &'a [Local],
18 count: u32,
19}
20
21impl<'a> Locals<'a> {
22 pub fn new(params: &'a [ValueType], local_groups: &'a [Local]) -> Result<Locals<'a>, Error> {
24 let mut acc = params.len() as u32;
25 for locals_group in local_groups {
26 acc = acc
27 .checked_add(locals_group.count())
28 .ok_or_else(|| Error(String::from("Locals range not in 32-bit range")))?;
29 }
30
31 Ok(Locals {
32 params,
33 local_groups,
34 count: acc,
35 })
36 }
37
38 pub fn param_count(&self) -> u32 {
40 self.params.len() as u32
41 }
42
43 pub fn count(&self) -> u32 {
45 self.count
46 }
47
48 pub fn type_of_local(&self, idx: u32) -> Result<ValueType, Error> {
52 if let Some(param) = self.params.get(idx as usize) {
53 return Ok(*param);
54 }
55
56 let mut start_idx = self.param_count();
58 for locals_group in self.local_groups {
59 let end_idx = start_idx
60 .checked_add(locals_group.count())
61 .ok_or_else(|| Error(String::from("Locals range not in 32-bit range")))?;
62
63 if idx >= start_idx && idx < end_idx {
64 return Ok(locals_group.value_type());
65 }
66
67 start_idx = end_idx;
68 }
69
70 let total_count = start_idx;
74
75 Err(Error(format!(
76 "Trying to access local with index {} when there are only {} locals",
77 idx, total_count
78 )))
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn locals_it_works() {
88 let params = vec![ValueType::I32, ValueType::I64];
89 let local_groups = vec![Local::new(2, ValueType::F32), Local::new(2, ValueType::F64)];
90 let locals = Locals::new(¶ms, &local_groups).unwrap();
91
92 assert_matches!(locals.type_of_local(0), Ok(ValueType::I32));
93 assert_matches!(locals.type_of_local(1), Ok(ValueType::I64));
94 assert_matches!(locals.type_of_local(2), Ok(ValueType::F32));
95 assert_matches!(locals.type_of_local(3), Ok(ValueType::F32));
96 assert_matches!(locals.type_of_local(4), Ok(ValueType::F64));
97 assert_matches!(locals.type_of_local(5), Ok(ValueType::F64));
98 assert_matches!(locals.type_of_local(6), Err(_));
99 }
100
101 #[test]
102 fn locals_no_declared_locals() {
103 let params = vec![ValueType::I32];
104 let locals = Locals::new(¶ms, &[]).unwrap();
105
106 assert_matches!(locals.type_of_local(0), Ok(ValueType::I32));
107 assert_matches!(locals.type_of_local(1), Err(_));
108 }
109
110 #[test]
111 fn locals_no_params() {
112 let local_groups = vec![Local::new(2, ValueType::I32), Local::new(3, ValueType::I64)];
113 let locals = Locals::new(&[], &local_groups).unwrap();
114
115 assert_matches!(locals.type_of_local(0), Ok(ValueType::I32));
116 assert_matches!(locals.type_of_local(1), Ok(ValueType::I32));
117 assert_matches!(locals.type_of_local(2), Ok(ValueType::I64));
118 assert_matches!(locals.type_of_local(3), Ok(ValueType::I64));
119 assert_matches!(locals.type_of_local(4), Ok(ValueType::I64));
120 assert_matches!(locals.type_of_local(5), Err(_));
121 }
122
123 #[test]
124 fn locals_u32_overflow() {
125 let local_groups = vec![
126 Local::new(u32::max_value(), ValueType::I32),
127 Local::new(1, ValueType::I64),
128 ];
129 assert_matches!(Locals::new(&[], &local_groups), Err(_));
130 }
131}