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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use anyhow::Result;
use spirv::{MAJOR_VERSION, MINOR_VERSION};
use std::{convert::TryInto, iter::FromIterator};

use super::Instrs;

#[derive(Debug, Clone)]
pub struct SpirvHeader {
    pub magic: u32,
    pub version: u32,
    pub generator: u32,
    pub bound: u32,
    pub schema: u32,
}
impl Default for SpirvHeader {
    fn default() -> Self {
        SpirvHeader {
            magic: 0x07230203,
            version: ((MAJOR_VERSION as u32) << 16) | ((MINOR_VERSION as u32) << 8),
            generator: 0,
            bound: 0,
            schema: 0,
        }
    }
}
impl SpirvHeader {
    pub fn new(version: u32, generator: u32) -> Self {
        SpirvHeader {
            version,
            generator,
            ..Default::default()
        }
    }
    pub fn words(&self) -> [u32; 5] {
        [
            self.magic,
            self.version,
            self.generator,
            self.bound,
            self.schema,
        ]
    }
}

/// SPIR-V program binary.
#[derive(Debug, Default, Clone)]
pub struct SpirvBinary(Vec<u32>);
impl From<Vec<u32>> for SpirvBinary {
    fn from(x: Vec<u32>) -> Self {
        SpirvBinary(x)
    }
}
impl From<&[u32]> for SpirvBinary {
    fn from(x: &[u32]) -> Self {
        SpirvBinary(x.to_owned())
    }
}
impl FromIterator<u32> for SpirvBinary {
    fn from_iter<I: IntoIterator<Item = u32>>(iter: I) -> Self {
        SpirvBinary(iter.into_iter().collect::<Vec<u32>>())
    }
}
impl From<&[u8]> for SpirvBinary {
    fn from(x: &[u8]) -> Self {
        if x.len() == 0 {
            return SpirvBinary::default();
        }
        x.chunks_exact(4)
            .map(|x| x.try_into().unwrap())
            .map(match x[0] {
                0x03 => u32::from_le_bytes,
                0x07 => u32::from_be_bytes,
                _ => return SpirvBinary::default(),
            })
            .collect::<SpirvBinary>()
    }
}
impl From<Vec<u8>> for SpirvBinary {
    fn from(x: Vec<u8>) -> Self {
        SpirvBinary::from(x.as_ref() as &[u8])
    }
}

impl SpirvBinary {
    pub fn words(&self) -> &[u32] {
        &self.0
    }
    pub fn into_words(self) -> Vec<u32> {
        self.0
    }
    pub fn into_bytes(self) -> Vec<u8> {
        self.0
            .iter()
            .flat_map(|x| x.to_le_bytes().to_vec())
            .collect::<Vec<u8>>()
    }

    pub fn instrs(&self) -> Result<Instrs> {
        const HEADER_LEN: usize = 5;
        Instrs::new(&self.words()[HEADER_LEN..])
    }

    pub fn header(&self) -> Option<SpirvHeader> {
        let header = &self.words()[..5];
        if header.len() < 5 {
            return None;
        }
        Some(SpirvHeader {
            magic: header[0],
            version: header[1],
            generator: header[2],
            bound: header[3],
            schema: header[4],
        })
    }
}