1#![deny(
19 clippy::arithmetic_side_effects,
20 clippy::indexing_slicing,
21 clippy::cast_possible_truncation
22)]
23#![deny(missing_docs)]
24#![deny(clippy::disallowed_methods, clippy::disallowed_types)]
25
26pub mod decode;
27mod opcodes;
28pub mod reflection;
29pub mod statistics;
30
31pub use decode::{
32 Declaration, Declared, Decoded, Index, Instruction, Operand, ProgramType, Register, Selection, decode,
33 opcode_name,
34};
35pub use reflection::{
36 Rdef, RdefBinding, RdefBuffer, RdefMember, RdefType, RdefVariable, SignatureElement,
37 patch_signature_elements, program_type, rdef, rdef_target, signature, signature_elements,
38};
39pub use statistics::{Statistics, statistics};
40
41#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
43#[error("DXBC at word {word}: {detail}")]
44pub struct Error {
45 pub word: usize,
47 pub detail: String,
49}
50
51pub type Result<T> = std::result::Result<T, Error>;
53
54pub(crate) fn error(word: usize, detail: impl Into<String>) -> Error {
55 Error {
56 word,
57 detail: detail.into(),
58 }
59}
60
61pub fn parts(bytes: &[u8]) -> Result<Vec<dxcontainer::Chunk<'_>>> {
63 dxcontainer::chunks(bytes).map_err(|e| error(e.offset / 4, e.detail))
64}
65
66pub fn chunk<'a>(directory: &[dxcontainer::Chunk<'a>], tag: &[u8; 4]) -> Result<&'a [u8]> {
68 let shown = String::from_utf8_lossy(tag);
69 let mut matching = directory.iter().filter(|c| &c.kind == tag);
70 let data = matching
71 .next()
72 .ok_or_else(|| error(0, format!("the container has no {shown} part")))?
73 .data;
74 if matching.next().is_some() {
75 return Err(error(
76 0,
77 format!("the container has the {shown} part more than once"),
78 ));
79 }
80 Ok(data)
81}
82
83pub fn code(bytes: &[u8]) -> Result<Vec<u32>> {
85 let directory = parts(bytes)?;
86 let code = directory
87 .iter()
88 .find(|c| matches!(&c.kind, b"SHDR" | b"SHEX"))
89 .ok_or_else(|| error(0, "missing shader code chunk"))?;
90 if code.data.len() % 4 != 0 {
91 return Err(error(
92 code.data.len() / 4,
93 format!(
94 "the code part is {} bytes, expected a multiple of 4 (32-bit tokens)",
95 code.data.len()
96 ),
97 ));
98 }
99 Ok(code
100 .data
101 .as_chunks::<4>()
102 .0
103 .iter()
104 .map(|b| u32::from_le_bytes(*b))
105 .collect())
106}