use crate::spirv;
use super::DecodeError as Error;
use std::convert::TryInto;
use std::result;
use std::str;
pub type Result<T> = result::Result<T, Error>;
const WORD_NUM_BYTES: usize = 4;
pub struct Decoder<'a> {
bytes: &'a [u8],
offset: usize,
limit: Option<usize>,
}
impl<'a> Decoder<'a> {
pub fn new(bytes: &'a [u8]) -> Decoder<'a> {
Decoder {
bytes,
offset: 0,
limit: None,
}
}
pub fn offset(&self) -> usize {
self.offset
}
pub fn word(&mut self) -> Result<spirv::Word> {
if self.has_limit() {
if self.limit_reached() {
return Err(Error::LimitReached(self.offset));
} else {
*self.limit.as_mut().unwrap() -= 1
}
}
if self.offset >= self.bytes.len() || self.offset + WORD_NUM_BYTES > self.bytes.len() {
Err(Error::StreamExpected(self.offset))
} else {
self.offset += WORD_NUM_BYTES;
Ok(spirv::Word::from_le_bytes(
self.bytes[self.offset - 4..self.offset].try_into().unwrap(),
))
}
}
pub fn words(&mut self, n: usize) -> Result<Vec<spirv::Word>> {
let mut words = Vec::new();
for _ in 0..n {
words.push(self.word()?);
}
Ok(words)
}
}
impl<'a> Decoder<'a> {
pub fn set_limit(&mut self, num_words: usize) {
self.limit = Some(num_words)
}
pub fn clear_limit(&mut self) {
self.limit = None
}
pub fn has_limit(&self) -> bool {
self.limit.is_some()
}
pub fn limit_reached(&self) -> bool {
if let Some(left) = self.limit {
left == 0
} else {
false
}
}
}
impl<'a> Decoder<'a> {
pub fn id(&mut self) -> Result<spirv::Word> {
self.word()
}
pub fn string(&mut self) -> Result<String> {
let slice = match self.limit {
Some(limit) => &self.bytes[self.offset..(self.offset + limit * WORD_NUM_BYTES)],
None => &self.bytes[self.offset..],
};
let first_null_byte = slice.iter().position(|&c| c == 0).ok_or(match self.limit {
Some(_) => Error::LimitReached(self.offset + slice.len()),
None => Error::StreamExpected(self.offset),
})?;
let result = str::from_utf8(&slice[..first_null_byte])
.map_err(|e| Error::DecodeStringFailed(self.offset, format!("{}", e)))?;
let consumed_words = (first_null_byte / WORD_NUM_BYTES) + 1;
self.offset += consumed_words * WORD_NUM_BYTES;
if let Some(ref mut limit) = self.limit {
*limit -= consumed_words;
}
Ok(result.to_string())
}
pub fn bit32(&mut self) -> Result<u32> {
self.word()
}
pub fn bit64(&mut self) -> Result<u64> {
let low = u64::from(self.word()?);
let high = u64::from(self.word()?);
Ok((high << 32) | low)
}
pub fn ext_inst_integer(&mut self) -> Result<u32> {
self.word()
}
}
include!("autogen_decode_operand.rs");
#[cfg(test)]
mod tests {
use crate::spirv;
use super::Decoder;
use crate::binary::DecodeError as Error;
#[test]
fn test_decoding_word_from_one_bytes() {
let b = vec![1];
let mut d = Decoder::new(&b);
assert_eq!(Err(Error::StreamExpected(0)), d.word());
}
#[test]
fn test_decoding_word_from_two_bytes() {
let b = vec![1, 2];
let mut d = Decoder::new(&b);
assert_eq!(Err(Error::StreamExpected(0)), d.word());
}
#[test]
fn test_decoding_word_from_three_bytes() {
let b = vec![1, 2, 3];
let mut d = Decoder::new(&b);
assert_eq!(Err(Error::StreamExpected(0)), d.word());
}
#[test]
fn test_decoding_word_from_four_bytes() {
let b = vec![0x12, 0x34, 0x56, 0x78];
let mut d = Decoder::new(&b);
assert_eq!(Ok(0x78563412), d.word());
}
#[test]
#[rustfmt::skip]
fn test_decoding_words() {
let b = vec![0x12, 0x34, 0x56, 0x78,
0x90, 0xab, 0xcd, 0xef,
0x01, 0x23, 0x45, 0x67,
0x89, 0xfe, 0xdc, 0xba];
let mut d = Decoder::new(&b);
assert_eq!(Ok(vec![0x78563412, 0xefcdab90]), d.words(2));
assert_eq!(Ok(vec![0x67452301]), d.words(1));
assert_eq!(Ok(vec![0xbadcfe89]), d.words(1));
}
#[test]
fn test_decoding_string() {
{
let b = vec![0x00, 0x00, 0x00, 0x00];
let mut d = Decoder::new(&b);
assert_eq!(Ok(String::new()), d.string());
}
{
let b = b"ok".to_vec();
let mut d = Decoder::new(&b);
assert_eq!(Err(Error::StreamExpected(0)), d.string());
}
{
let b = b"ok\0\0".to_vec();
let mut d = Decoder::new(&b);
assert_eq!(Ok("ok".to_string()), d.string());
}
{
let b = b"ok\0\0rust\0\0\0\0rocks\0\0\0".to_vec();
let mut d = Decoder::new(&b);
assert_eq!(Ok("ok".to_string()), d.string());
assert_eq!(Ok("rust".to_string()), d.string());
assert_eq!(Ok("rocks".to_string()), d.string());
}
{
let b = b"I..don't know..\0".to_vec();
let mut d = Decoder::new(&b);
assert_eq!(Ok("I..don't know..".to_string()), d.string());
}
}
#[test]
fn test_decoding_source_language() {
let b = vec![0x02, 0x00, 0x00, 0x00];
let mut d = Decoder::new(&b);
assert_eq!(Ok(spirv::SourceLanguage::GLSL), d.source_language());
}
#[test]
fn test_decoding_unknown_execution_model() {
let b = vec![0xef, 0xbe, 0xad, 0xde];
let mut d = Decoder::new(&b);
assert_eq!(
Err(Error::ExecutionModelUnknown(0, 0xdeadbeef)),
d.execution_model()
);
}
#[test]
#[rustfmt::skip]
fn test_offset() {
let b = vec![0x12, 0x34, 0x56, 0x78,
0x90, 0xab, 0xcd, 0xef,
0x01, 0x23, 0x45, 0x67,
0x89, 0xfe, 0xdc, 0xba,
0x01, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff];
let mut d = Decoder::new(&b);
assert_eq!(0, d.offset());
assert!(d.words(1).is_ok());
assert_eq!(4, d.offset());
assert!(d.words(2).is_ok());
assert_eq!(12, d.offset());
assert!(d.words(1).is_ok());
assert_eq!(16, d.offset());
assert!(d.source_language().is_ok());
assert_eq!(20, d.offset());
assert!(d.execution_model().is_err());
assert_eq!(24, d.offset());
}
#[test]
fn test_decoding_after_errors() {
let b = vec![0x12, 0x34, 0x56, 0x78];
let mut d = Decoder::new(&b);
assert_eq!(Ok(0x78563412), d.word());
assert_eq!(Err(Error::StreamExpected(4)), d.word());
assert_eq!(Err(Error::StreamExpected(4)), d.word());
assert_eq!(Err(Error::StreamExpected(4)), d.word());
}
#[test]
fn test_limit() {
let v = vec![0xff; 12];
let mut d = Decoder::new(&v);
assert!(!d.has_limit());
assert!(!d.limit_reached());
d.set_limit(4);
assert!(d.has_limit());
assert!(!d.limit_reached());
d.clear_limit();
assert!(!d.has_limit());
assert!(!d.limit_reached());
d.set_limit(2);
assert!(d.has_limit());
assert!(!d.limit_reached());
assert_eq!(Ok(0xffffffff), d.word());
assert!(d.has_limit());
assert!(!d.limit_reached());
assert_eq!(Ok(0xffffffff), d.word());
assert!(d.has_limit());
assert!(d.limit_reached());
assert_eq!(Err(Error::LimitReached(8)), d.word());
assert!(d.has_limit());
assert!(d.limit_reached());
assert_eq!(Err(Error::LimitReached(8)), d.word());
assert!(d.has_limit());
assert!(d.limit_reached());
d.clear_limit();
assert_eq!(Ok(0xffffffff), d.word());
assert!(!d.has_limit());
assert!(!d.limit_reached());
d.set_limit(0);
assert_eq!(Err(Error::LimitReached(12)), d.word());
assert!(d.has_limit());
assert!(d.limit_reached());
d.clear_limit();
assert_eq!(Err(Error::StreamExpected(12)), d.word());
}
#[test]
fn test_decode_bit32() {
let b = [0x12, 0x34, 0x56, 0x78];
let mut d = Decoder::new(&b);
assert_eq!(Ok(0x78563412), d.bit32());
let b = [0x14, 0xAE, 0x29, 0x42];
let mut d = Decoder::new(&b);
assert_eq!(Ok(42.42f32.to_bits()), d.bit32());
let b = [0xA4, 0x70, 0x45, 0xC1];
let mut d = Decoder::new(&b);
assert_eq!(Ok((-12.34f32).to_bits()), d.bit32());
}
#[test]
fn test_decode_bit64() {
let b = [0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef];
let mut d = Decoder::new(&b);
assert_eq!(Ok(0xefcdab9078563412), d.bit64());
let b = [0xF6, 0x28, 0x5C, 0x8F, 0xC2, 0x35, 0x45, 0x40];
let mut d = Decoder::new(&b);
assert_eq!(Ok(42.42f64.to_bits()), d.bit64());
let b = [0xAE, 0x47, 0xE1, 0x7A, 0x14, 0xAE, 0x28, 0xC0];
let mut d = Decoder::new(&b);
assert_eq!(Ok((-12.34f64).to_bits()), d.bit64());
}
}