Skip to main content

nox_spirv/
core.rs

1use core::{
2    ffi::{CStr, FromBytesWithNulError},
3    slice,
4    fmt::{self, Display},
5    ops::Deref,
6};
7
8/// A trait for types, which can be trivially created from a [`u32`].
9pub trait Word: Sized {
10    
11    fn from_word(word: u32) -> Self;
12}
13
14impl Word for u32 { 
15
16    #[inline]
17    fn from_word(word: u32) -> Self {
18        word
19    }
20}
21
22#[inline]
23pub(crate) fn slice_as_bytes<T>(slice: &[T]) -> &[u8] {
24    unsafe {
25        slice::from_raw_parts(slice.as_ptr() as *const u8, size_of_val(slice))
26    }
27}
28
29/// Represents a string inside SPIR-V.
30///
31/// Doesn't do any extra allocations and is trivially copyable.
32#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, Hash)]
33pub struct CompilerStr<'a> {
34    bytes: &'a [u8],
35}
36
37impl<'a> Deref for CompilerStr<'a> {
38
39    type Target = [u8];
40
41    fn deref(&self) -> &Self::Target {
42        self.bytes
43    }
44}
45
46impl<'a> CompilerStr<'a> {
47
48    /// Constructs a new string from words.
49    pub fn new(words: &'a [u32]) -> Self {
50        let bytes = slice_as_bytes(words);
51        let len = bytes
52            .iter()
53            .copied()
54            .take_while(|&byte| byte != 0)
55            .count() + 1;
56        Self {
57            bytes: &bytes[0..len],
58        }
59    }
60
61    /// Converts self to a [`CStr`].
62    #[inline]
63    pub fn to_cstr(&self) -> Result<&'a CStr, FromBytesWithNulError> {
64        CStr::from_bytes_with_nul(
65            self.bytes
66        )
67    }
68}
69
70impl Display for CompilerStr<'_> {
71
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(f, "{}", str
74            ::from_utf8(&self.bytes[0..self.bytes.len().saturating_sub(1)])
75            .unwrap_or("<utf8-error>"
76        ))
77    }
78}
79
80/// Specifies the value of a literal constant.
81#[derive(Clone, Copy, Debug)]
82pub enum Literal {
83    /// 16-bit floating point literal.
84    ///
85    /// Not representable in Rust without nightly.
86    F16(u16),
87    /// 32-bit floating point literal.
88    F32(f32),
89    /// 64-bit floating point literal.
90    F64(f64),
91    /// 8-bit signed integer literal.
92    I8(i8),
93    /// 16-bit signed integer literal.
94    I16(i16),
95    /// 32-bit signed integer literal.
96    I32(i32),
97    /// 64-bit signed integer literal.
98    I64(i64),
99    /// 8-bit unsigned integer literal.
100    U8(u8),
101    /// 16-bit unsigned integer literal.
102    U16(u16),
103    /// 32-bit unsigned integer literal.
104    U32(u32),
105    /// 64-bit unsigned integer literal.
106    U64(u64),
107}
108
109impl Literal {
110
111    /// Converts self to an usize, if its an integer literal.
112    #[inline]
113    pub fn as_usize(self) -> Option<usize> {
114        match self {
115            Self::I8(x) => Some(x as usize),
116            Self::I16(x) => Some(x as usize),
117            Self::I32(x) => Some(x as usize),
118            Self::I64(x) => Some(x as usize),
119            Self::U8(x) => Some(x as usize),
120            Self::U16(x) => Some(x as usize),
121            Self::U32(x) => Some(x as usize),
122            Self::U64(x) => Some(x as usize),
123            _ => None,
124        }
125    }
126}
127
128impl Display for Literal {
129
130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131        match self {
132            Self::F16(x) => write!(f, "{x:#x}"),
133            Self::F32(x) => write!(f, "{x}"),
134            Self::F64(x) => write!(f, "{x}"),
135            Self::I8(x) => write!(f, "{x}"),
136            Self::I16(x) => write!(f, "{x}"),
137            Self::I32(x) => write!(f, "{x}"),
138            Self::I64(x) => write!(f, "{x}"),
139            Self::U8(x) => write!(f, "{x}"),
140            Self::U16(x) => write!(f, "{x}"),
141            Self::U32(x) => write!(f, "{x}"),
142            Self::U64(x) => write!(f, "{x}"),
143        }
144    }
145}