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
use num_traits::FromPrimitive;
use super::{Error, Result};
pub struct Instrs<'a>(&'a [u32]);
impl<'a> Instrs<'a> {
pub fn new(spv: &'a [u32]) -> Instrs<'a> {
const HEADER_LEN: usize = 5;
if spv.len() < HEADER_LEN { return Instrs(&[] as &[u32]) }
Instrs(&spv[HEADER_LEN..])
}
}
impl<'a> Iterator for Instrs<'a> {
type Item = Instr<'a>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(head) = self.0.first() {
let len = ((*head as u32) >> 16) as usize;
if len <= self.0.len() {
let opcode = head & 0xFFFF;
let instr = Instr {
opcode: opcode,
operands: &self.0[1..len],
};
self.0 = &self.0[len..];
return Some(instr);
}
}
None
}
}
#[derive(Debug, Clone)]
pub struct Instr<'a> {
opcode: u32,
operands: &'a [u32],
}
impl<'a> Instr<'a> {
pub fn opcode(&self) -> u32 {
self.opcode as u32
}
pub fn word_count(&self) -> usize {
self.operands.len() + 1
}
pub fn operands(&self) -> Operands<'a> {
Operands(self.operands)
}
}
pub struct Operands<'a>(&'a [u32]);
impl<'a> Operands<'a> {
pub fn read_bool(&mut self) -> Result<bool> {
self.read_u32()
.map(|x| x != 0)
}
pub fn read_u32(&mut self) -> Result<u32> {
if let Some(x) = self.0.first() {
self.0 = &self.0[1..];
Ok(*x)
} else {
Err(Error::INSTR_TOO_SHORT)
}
}
pub fn read_str(&mut self) -> Result<&'a str> {
use std::os::raw::c_char;
use std::ffi::CStr;
let ptr = self.0.as_ptr() as *const c_char;
let char_slice = unsafe {
std::slice::from_raw_parts(ptr, self.0.len() * 4)
};
if let Some(nul_pos) = char_slice.into_iter().position(|x| *x == 0) {
let nword = nul_pos / 4 + 1;
self.0 = &self.0[nword..];
if let Ok(string) = unsafe { CStr::from_ptr(ptr) }.to_str() {
return Ok(string);
}
}
Err(Error::STR_NOT_TERMINATED)
}
pub fn read_enum<E: FromPrimitive>(&mut self) -> Result<E> {
self.read_u32()
.and_then(|x| {
FromPrimitive::from_u32(x)
.ok_or(Error::UNENCODED_ENUM)
})
}
pub fn read_list(&mut self) -> Result<&'a [u32]> {
let rv = self.0;
self.0 = &[];
Ok(rv)
}
}