1use crate::{
4 core::*,
5 ParseResult, ParseError,
6 op,
7};
8
9#[derive(Clone, Copy)]
13pub struct Stream<'a> {
14 spirv: &'a [u32],
15 pos: usize,
16}
17
18impl<'a> Stream<'a> {
19
20 #[inline(always)]
21 pub fn new(spirv: &'a [u32]) -> Self {
22 Self {
23 spirv: &spirv[5..],
24 pos: 0,
25 }
26 }
27
28 #[inline(always)]
29 pub fn reset(&mut self) {
30 self.pos = 0;
31 }
32}
33
34#[derive(Clone, Copy)]
36pub struct InstructionStream<'a> {
37 op: op::Code,
38 words: &'a [u32],
39 pos: usize,
40}
41
42impl<'a> InstructionStream<'a> {
43
44 #[inline]
45 pub fn code(&self) -> op::Code {
46 self.op
47 }
48
49 #[inline]
50 pub fn is_eos(&self) -> bool {
51 self.pos == self.words.len()
52 }
53
54 #[inline]
55 pub fn reset(&mut self) {
56 self.pos = 1;
57 }
58
59 #[inline]
60 pub fn read(&mut self) -> ParseResult<u32> {
61 let len = self.words.len();
62 let pos = self.pos;
63 if pos == len { Err(ParseError::EndOfStream) }
64 else {
65 self.pos += 1;
66 Ok(self.words[pos])
67 }
68 }
69
70 #[inline]
71 pub fn read_words(&mut self, count: Option<u32>) -> ParseResult<&'a [u32]> {
72 let len = self.words.len();
73 let pos = self.pos;
74 if pos == len { Ok(Default::default()) }
75 else {
76 let end = count
77 .map(|count| pos + count as usize)
78 .unwrap_or(len);
79 if end > len { Err(ParseError::EndOfStream) }
80 else {
81 self.pos = end;
82 Ok(&self.words[pos..end])
83 }
84 }
85 }
86
87 #[inline]
88 pub fn read_string(&mut self) -> ParseResult<CompilerStr<'a>> {
89 let pos = self.pos;
90 if pos == self.words.len() { Err(ParseError::EndOfStream) }
91 else {
92 let str = CompilerStr::new(&self.words[pos..]);
93 self.pos = pos + str.len().div_ceil(8);
94 Ok(str)
95 }
96 }
97}
98
99impl<'a> Iterator for Stream<'a> {
100
101 type Item = InstructionStream<'a>;
102
103 #[inline]
104 fn next(&mut self) -> Option<Self::Item> {
105 let len = self.spirv.len();
106 let pos = self.pos;
107 if pos == len { None }
108 else {
109 let word = self.spirv[pos];
110 let (count, op_code) = (word >> 16, word & 0xFFFF);
111 let end = pos + count as usize;
112 if end > len { None }
113 else {
114 let instruction = InstructionStream {
115 op: op::Code(op_code as u16),
116 words: &self.spirv[pos..end],
117 pos: 1,
118 };
119 self.pos = end;
120 Some(instruction)
121 }
122 }
123 }
124}