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