1use anyhow::Result;
2use spirv::{MAJOR_VERSION, MINOR_VERSION};
3use std::{convert::TryInto, iter::FromIterator};
4
5use super::Instrs;
6
7#[derive(Debug, Clone)]
8pub struct SpirvHeader {
9    pub magic: u32,
10    pub version: u32,
11    pub generator: u32,
12    pub bound: u32,
13    pub schema: u32,
14}
15impl Default for SpirvHeader {
16    fn default() -> Self {
17        SpirvHeader {
18            magic: 0x07230203,
19            version: ((MAJOR_VERSION as u32) << 16) | ((MINOR_VERSION as u32) << 8),
20            generator: 0,
21            bound: 0,
22            schema: 0,
23        }
24    }
25}
26impl SpirvHeader {
27    pub fn new(version: u32, generator: u32) -> Self {
28        SpirvHeader {
29            version,
30            generator,
31            ..Default::default()
32        }
33    }
34    pub fn words(&self) -> [u32; 5] {
35        [
36            self.magic,
37            self.version,
38            self.generator,
39            self.bound,
40            self.schema,
41        ]
42    }
43}
44
45#[derive(Debug, Default, Clone)]
47pub struct SpirvBinary(Vec<u32>);
48impl From<Vec<u32>> for SpirvBinary {
49    fn from(x: Vec<u32>) -> Self {
50        SpirvBinary(x)
51    }
52}
53impl From<&[u32]> for SpirvBinary {
54    fn from(x: &[u32]) -> Self {
55        SpirvBinary(x.to_owned())
56    }
57}
58impl FromIterator<u32> for SpirvBinary {
59    fn from_iter<I: IntoIterator<Item = u32>>(iter: I) -> Self {
60        SpirvBinary(iter.into_iter().collect::<Vec<u32>>())
61    }
62}
63impl From<&[u8]> for SpirvBinary {
64    fn from(x: &[u8]) -> Self {
65        if x.len() == 0 {
66            return SpirvBinary::default();
67        }
68        x.chunks_exact(4)
69            .map(|x| x.try_into().unwrap())
70            .map(match x[0] {
71                0x03 => u32::from_le_bytes,
72                0x07 => u32::from_be_bytes,
73                _ => return SpirvBinary::default(),
74            })
75            .collect::<SpirvBinary>()
76    }
77}
78impl From<Vec<u8>> for SpirvBinary {
79    fn from(x: Vec<u8>) -> Self {
80        SpirvBinary::from(x.as_ref() as &[u8])
81    }
82}
83
84impl SpirvBinary {
85    pub fn words(&self) -> &[u32] {
86        &self.0
87    }
88    pub fn into_words(self) -> Vec<u32> {
89        self.0
90    }
91    pub fn into_bytes(self) -> Vec<u8> {
92        self.0
93            .iter()
94            .flat_map(|x| x.to_le_bytes().to_vec())
95            .collect::<Vec<u8>>()
96    }
97
98    pub fn instrs(&self) -> Result<Instrs> {
99        const HEADER_LEN: usize = 5;
100        Instrs::new(&self.words()[HEADER_LEN..])
101    }
102
103    pub fn header(&self) -> Option<SpirvHeader> {
104        let header = &self.words()[..5];
105        if header.len() < 5 {
106            return None;
107        }
108        Some(SpirvHeader {
109            magic: header[0],
110            version: header[1],
111            generator: header[2],
112            bound: header[3],
113            schema: header[4],
114        })
115    }
116}