use alloc::alloc::{alloc as malloc, dealloc as free, Layout};
use core::fmt;
use core::slice;
#[cfg(all(feature = "no_std_error", not(feature = "std")))]
use core::error;
#[cfg(feature = "std")]
use std::error;
#[derive(Clone, Debug, PartialEq)]
pub enum BytecodeError {
Alloc,
Length(usize),
}
impl fmt::Display for BytecodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use BytecodeError::*;
match self {
Alloc => write!(f, "failed to allocate SPIR-V bytecode buffer"),
Length(length) => write!(f, "invalid SPIR-V bytecode buffer length ({length})"),
}
}
}
#[cfg(any(feature = "std", feature = "no_std_error"))]
impl error::Error for BytecodeError {}
pub struct Bytecode(*mut u8, usize);
impl Bytecode {
pub fn new(bytecode: &[u8]) -> Result<Self, BytecodeError> {
if bytecode.is_empty() || bytecode.len() % 4 != 0 {
return Err(BytecodeError::Length(bytecode.len()));
}
let layout = Layout::from_size_align(bytecode.len(), 4).unwrap();
debug_assert!(layout.size() != 0);
let pointer = unsafe { malloc(layout) };
if pointer.is_null() {
return Err(BytecodeError::Alloc);
}
let slice = unsafe { slice::from_raw_parts_mut(pointer, layout.size()) };
slice.copy_from_slice(bytecode);
Ok(Self(pointer, layout.size()))
}
pub fn code_size(&self) -> usize {
self.1
}
pub fn code(&self) -> &[u32] {
let pointer: *const u32 = self.0.cast();
let length = self.1 / 4;
unsafe { slice::from_raw_parts(pointer, length) }
}
}
impl Drop for Bytecode {
fn drop(&mut self) {
let layout = Layout::from_size_align(self.1, 4).unwrap();
unsafe { free(self.0, layout) };
}
}