destiny_pkg/
tag.rs

1use std::{
2    fmt::{Debug, Display, Formatter},
3    hash::Hash,
4};
5
6use binrw::{BinRead, BinWrite};
7
8#[derive(
9    BinRead,
10    BinWrite,
11    Copy,
12    Clone,
13    PartialEq,
14    PartialOrd,
15    Eq,
16    Ord,
17    serde::Serialize,
18    serde::Deserialize,
19    bincode::Decode,
20    bincode::Encode,
21)]
22#[repr(transparent)]
23pub struct TagHash(pub u32);
24
25impl From<TagHash> for u32 {
26    fn from(value: TagHash) -> Self {
27        value.0
28    }
29}
30
31impl From<u32> for TagHash {
32    fn from(value: u32) -> Self {
33        Self(value)
34    }
35}
36
37impl From<(u16, u16)> for TagHash {
38    fn from((pkg_id, index): (u16, u16)) -> Self {
39        Self::new(pkg_id, index)
40    }
41}
42
43impl Default for TagHash {
44    fn default() -> Self {
45        Self::NONE
46    }
47}
48
49impl TagHash {
50    pub const NONE: TagHash = TagHash(u32::MAX);
51
52    pub fn new(pkg_id: u16, entry: u16) -> TagHash {
53        TagHash(
54            0x80800000u32
55                .wrapping_add((pkg_id as u32) << 13)
56                .wrapping_add(entry as u32 % 8192),
57        )
58    }
59
60    pub fn is_valid(&self) -> bool {
61        self.0 > 0x80800000 && self.0 <= 0x81ffffff
62    }
63
64    pub fn is_none(&self) -> bool {
65        self.0 == u32::MAX
66    }
67
68    pub fn is_some(&self) -> bool {
69        !self.is_none() && self.is_valid()
70    }
71
72    /// Does this hash look like a pkg hash?
73    pub fn is_pkg_file(&self) -> bool {
74        self.is_some() && (0x9..0xa00).contains(&self.pkg_id())
75    }
76
77    pub fn pkg_id(&self) -> u16 {
78        (self.0.wrapping_sub(0x80800000) >> 13) as u16
79    }
80
81    pub fn entry_index(&self) -> u16 {
82        ((self.0 & 0x1fff) % 8192) as u16
83    }
84}
85
86impl Debug for TagHash {
87    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
88        if self.is_none() {
89            f.write_str("TagHash(NONE)")
90        } else if !self.is_valid() {
91            f.write_fmt(format_args!("TagHash(INVALID(0x{:x}))", self.0))
92        } else {
93            f.write_fmt(format_args!(
94                "TagHash(pkg={:04x}, entry={})",
95                self.pkg_id(),
96                self.entry_index()
97            ))
98        }
99    }
100}
101
102impl Display for TagHash {
103    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
104        f.write_fmt(format_args!("{:08X}", self.0.to_be()))
105    }
106}
107
108impl Hash for TagHash {
109    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
110        state.write_u32(self.0)
111    }
112}
113
114#[derive(
115    BinRead,
116    BinWrite,
117    Copy,
118    Clone,
119    PartialEq,
120    PartialOrd,
121    Eq,
122    Ord,
123    serde::Serialize,
124    serde::Deserialize,
125    bincode::Decode,
126    bincode::Encode,
127)]
128#[repr(transparent)]
129pub struct TagHash64(pub u64);
130
131impl TagHash64 {
132    pub const NONE: TagHash64 = TagHash64(0);
133}
134
135impl Default for TagHash64 {
136    fn default() -> Self {
137        Self::NONE
138    }
139}
140
141impl From<TagHash64> for u64 {
142    fn from(value: TagHash64) -> Self {
143        value.0
144    }
145}
146
147impl From<u64> for TagHash64 {
148    fn from(value: u64) -> Self {
149        Self(value)
150    }
151}
152
153impl Debug for TagHash64 {
154    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
155        f.write_fmt(format_args!("TagHash(0x{:016X})", self.0))
156    }
157}
158
159impl Display for TagHash64 {
160    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
161        f.write_fmt(format_args!("{:016X}", self.0.to_be()))
162    }
163}
164
165impl Hash for TagHash64 {
166    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
167        state.write_u64(self.0)
168    }
169}