Skip to main content

nox_spirv/
stream.rs

1//! SPIR-V streams.
2
3use crate::{
4    core::*,
5    ParseResult, ParseError,
6    op,
7};
8
9/// An iterator over [`instructions`][1] in SPIR-V code.
10///
11/// [1]: InstructionStream
12#[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/// Represents a single SPIR-V instruction.
35#[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}