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