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 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}