1use std::any::Any;
3use num_enum::TryFromPrimitive;
4use super::BinHashMappers;
5use cdragon_hashes::{
6 define_hash_type,
7 HashOrStr,
8 bin::{BinHashKind, compute_binhash},
9 wad::compute_wad_hash,
10};
11pub use cdragon_hashes::bin::BinHashMapper;
12
13
14#[derive(Debug)]
16pub struct BinField {
17 pub name: BinFieldName,
19 pub vtype: BinType,
21 pub(crate) value: Box<dyn Any>, }
23
24impl BinField {
25 pub fn downcast<T: BinValue + 'static>(&self) -> Option<&T> {
27 self.value.downcast_ref::<T>()
28 }
29}
30
31
32macro_rules! declare_bin_hash {
34 (
35 $(#[$meta:meta])*
36 $name:ident => $kind:expr
37 ) => {
38 define_hash_type! {
39 $(#[$meta])*
40 $name(u32) => compute_binhash
41 }
42
43 impl $name {
44 const KIND: BinHashKind = $kind;
46 pub fn get_str<'a>(&self, mapper: &'a BinHashMappers) -> Option<&'a str> {
48 mapper.get(Self::KIND).get(self.hash)
49 }
50 pub fn seek_str<'a>(&self, mapper: &'a BinHashMappers) -> HashOrStr<u32, &'a str> {
52 mapper.get(Self::KIND).seek(self.hash)
53 }
54 }
55 }
56}
57
58declare_bin_hash! {
59 BinEntryPath => BinHashKind::EntryPath
61}
62declare_bin_hash! {
63 BinClassName => BinHashKind::ClassName
66}
67declare_bin_hash! {
68 BinFieldName => BinHashKind::FieldName
70}
71declare_bin_hash! {
72 BinHashValue => BinHashKind::HashValue
74}
75
76define_hash_type! {
77 BinPathValue(u64) => compute_wad_hash
79}
80impl BinPathValue {
81 pub fn get_str<'a>(&self, mapper: &'a BinHashMappers) -> Option<&'a str> {
83 mapper.path_value.get(self.hash)
84 }
85 pub fn seek_str<'a>(&self, mapper: &'a BinHashMappers) -> HashOrStr<u64, &'a str> {
87 mapper.path_value.seek(self.hash)
88 }
89}
90
91
92pub trait BinValue {
94 const TYPE: BinType;
96}
97
98macro_rules! declare_bintype_struct {
99 ($type:ident ($t:ty) [$($d:ident),* $(,)?]) => {
100 #[allow(missing_docs)]
101 #[derive(Debug,$($d),*)]
102 pub struct $type(pub $t);
103 impl From<$t> for $type {
104 fn from(v: $t) -> Self { Self(v) }
105 }
106 };
107 ($type:ident ($($v:ident: $t:ty),* $(,)?)) => {
108 #[allow(missing_docs)]
109 #[derive(Debug)]
110 pub struct $type($(pub $t,)*);
111 impl From<($($t),*)> for $type {
112 fn from(($($v),*): ($($t),*)) -> Self {
113 Self($($v),*)
114 }
115 }
116 };
117}
118
119declare_bintype_struct!{ BinNone() }
120declare_bintype_struct!{ BinBool(bool) [Eq,PartialEq,Hash] }
121declare_bintype_struct!{ BinS8(i8) [Eq,PartialEq,Hash] }
122declare_bintype_struct!{ BinU8(u8) [Eq,PartialEq,Hash] }
123declare_bintype_struct!{ BinS16(i16) [Eq,PartialEq,Hash] }
124declare_bintype_struct!{ BinU16(u16) [Eq,PartialEq,Hash] }
125declare_bintype_struct!{ BinS32(i32) [Eq,PartialEq,Hash] }
126declare_bintype_struct!{ BinU32(u32) [Eq,PartialEq,Hash] }
127declare_bintype_struct!{ BinS64(i64) [Eq,PartialEq,Hash] }
128declare_bintype_struct!{ BinU64(u64) [Eq,PartialEq,Hash] }
129declare_bintype_struct!{ BinFloat(f32) [] }
130declare_bintype_struct!{ BinVec2(a: f32, b: f32) }
131declare_bintype_struct!{ BinVec3(a: f32, b: f32, c: f32) }
132declare_bintype_struct!{ BinVec4(a: f32, b: f32, c: f32, d: f32) }
133declare_bintype_struct!{ BinMatrix([[f32; 4]; 4]) [] }
134#[allow(missing_docs)]
136#[derive(Debug)]
137pub struct BinColor { pub r: u8, pub g: u8, pub b: u8, pub a: u8 }
138declare_bintype_struct!{ BinString(String) [Eq,PartialEq,Hash] }
139declare_bintype_struct!{ BinHash(BinHashValue) [Eq,PartialEq,Hash] }
140declare_bintype_struct!{ BinPath(BinPathValue) [Eq,PartialEq,Hash] }
141declare_bintype_struct!{ BinLink(BinEntryPath) [Eq,PartialEq,Hash] }
142declare_bintype_struct!{ BinFlag(bool) [Eq,PartialEq,Hash] }
143
144
145pub struct BinList {
149 pub vtype: BinType,
151 pub(crate) values: Box<dyn Any>, }
153
154impl BinList {
155 pub fn downcast<T: BinValue + 'static>(&self) -> Option<&Vec<T>> {
157 self.values.downcast_ref::<Vec<T>>()
158 }
159}
160
161pub struct BinStruct {
163 pub ctype: BinClassName,
165 pub fields: Vec<BinField>,
167}
168
169impl BinStruct {
170 pub fn get(&self, name: BinFieldName) -> Option<&BinField> {
172 self.fields.iter().find(|f| f.name == name)
173 }
174
175 pub fn getv<T: BinValue + 'static>(&self, name: BinFieldName) -> Option<&T> {
177 self.get(name).and_then(|field| field.downcast::<T>())
178 }
179}
180
181pub struct BinEmbed {
183 pub ctype: BinClassName,
185 pub fields: Vec<BinField>,
187}
188
189impl BinEmbed {
190 pub fn get(&self, name: BinFieldName) -> Option<&BinField> {
192 self.fields.iter().find(|f| f.name == name)
193 }
194
195 pub fn getv<T: BinValue + 'static>(&self, name: BinFieldName) -> Option<&T> {
197 self.get(name).and_then(|field| field.downcast::<T>())
198 }
199}
200
201pub struct BinOption {
203 pub vtype: BinType,
205 pub(crate) value: Option<Box<dyn Any>>, }
207
208impl BinOption {
209 pub fn is_some(&self) -> bool {
211 self.value.is_some()
212 }
213
214 pub fn downcast<T: BinValue + 'static>(&self) -> Option<&T> {
216 match self.value {
217 Some(ref v) => Some(v.downcast_ref::<T>()?),
218 None => None,
219 }
220 }
221}
222
223
224pub struct BinMap {
226 pub ktype: BinType,
228 pub vtype: BinType,
230 pub(crate) values: Box<dyn Any>, }
232
233impl BinMap {
234 pub fn downcast<K: BinValue + 'static, V: BinValue + 'static>(&self) -> Option<&Vec<(K, V)>> {
236 self.values.downcast_ref::<Vec<(K, V)>>()
237 }
238}
239
240impl BinValue for BinNone { const TYPE: BinType = BinType::None; }
241impl BinValue for BinBool { const TYPE: BinType = BinType::Bool; }
242impl BinValue for BinS8 { const TYPE: BinType = BinType::S8; }
243impl BinValue for BinU8 { const TYPE: BinType = BinType::U8; }
244impl BinValue for BinS16 { const TYPE: BinType = BinType::S16; }
245impl BinValue for BinU16 { const TYPE: BinType = BinType::U16; }
246impl BinValue for BinS32 { const TYPE: BinType = BinType::S32; }
247impl BinValue for BinU32 { const TYPE: BinType = BinType::U32; }
248impl BinValue for BinS64 { const TYPE: BinType = BinType::S64; }
249impl BinValue for BinU64 { const TYPE: BinType = BinType::U64; }
250impl BinValue for BinFloat { const TYPE: BinType = BinType::Float; }
251impl BinValue for BinVec2 { const TYPE: BinType = BinType::Vec2; }
252impl BinValue for BinVec3 { const TYPE: BinType = BinType::Vec3; }
253impl BinValue for BinVec4 { const TYPE: BinType = BinType::Vec4; }
254impl BinValue for BinMatrix { const TYPE: BinType = BinType::Matrix; }
255impl BinValue for BinColor { const TYPE: BinType = BinType::Color; }
256impl BinValue for BinString { const TYPE: BinType = BinType::String; }
257impl BinValue for BinHash { const TYPE: BinType = BinType::Hash; }
258impl BinValue for BinPath { const TYPE: BinType = BinType::Path; }
259impl BinValue for BinList { const TYPE: BinType = BinType::List; }
260impl BinValue for BinStruct { const TYPE: BinType = BinType::Struct; }
261impl BinValue for BinEmbed { const TYPE: BinType = BinType::Embed; }
262impl BinValue for BinLink { const TYPE: BinType = BinType::Link; }
263impl BinValue for BinOption { const TYPE: BinType = BinType::Option; }
264impl BinValue for BinMap { const TYPE: BinType = BinType::Map; }
265impl BinValue for BinFlag { const TYPE: BinType = BinType::Flag; }
266
267
268#[allow(dead_code, missing_docs)]
272#[repr(u8)]
273#[derive(Copy, Clone, Eq, PartialEq, TryFromPrimitive, Debug)]
274pub enum BinType {
275 None = 0,
276 Bool = 1,
277 S8 = 2,
278 U8 = 3,
279 S16 = 4,
280 U16 = 5,
281 S32 = 6,
282 U32 = 7,
283 S64 = 8,
284 U64 = 9,
285 Float = 10,
286 Vec2 = 11,
287 Vec3 = 12,
288 Vec4 = 13,
289 Matrix = 14,
290 Color = 15,
291 String = 16,
292 Hash = 17,
293 Path = 18, List = 19,
296 List2 = 20, Struct = 21,
298 Embed = 22,
299 Link = 23,
300 Option = 24,
301 Map = 25,
302 Flag = 26,
303}
304
305impl BinType {
306 #[inline]
308 pub const fn is_nested(&self) -> bool {
309 matches!(self,
310 BinType::List |
311 BinType::List2 |
312 BinType::Struct |
313 BinType::Embed |
314 BinType::Option |
315 BinType::Map)
316 }
317}
318