plasma_prp/core/
location.rs1use std::fmt;
6use std::io::{Read, Write};
7
8use anyhow::Result;
9
10use crate::resource::prp::PlasmaRead;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct LocFlags(u16);
15
16impl LocFlags {
17 pub const LOCAL_ONLY: u16 = 0x1;
18 pub const VOLATILE: u16 = 0x2;
19 pub const RESERVED: u16 = 0x4;
20 pub const BUILT_IN: u16 = 0x8;
21 pub const ITINERANT: u16 = 0x10;
22}
23
24const GLOBAL_FIXED_LOC_IDX: u32 = 0;
26const LOCAL_LOC_START_IDX: u32 = 3;
27const LOCAL_LOC_END_IDX: u32 = 32;
28const NORMAL_LOC_START_IDX: u32 = LOCAL_LOC_END_IDX + 1;
29const RESERVED_LOC_START: u32 = 0xFF000000;
30const GLOBAL_SERVER_LOC_IDX: u32 = RESERVED_LOC_START;
31const RESERVED_LOC_AVAILABLE_START: u32 = GLOBAL_SERVER_LOC_IDX + 1;
32const INVALID_LOC_IDX: u32 = 0xFFFFFFFF;
33
34#[derive(Clone, Copy)]
39pub struct Location {
40 pub sequence_number: u32,
41 pub flags: u16,
42}
43
44impl Location {
45 pub fn invalid() -> Self {
47 Self {
48 sequence_number: INVALID_LOC_IDX,
49 flags: 0,
50 }
51 }
52
53 pub fn new(sequence_number: u32, flags: u16) -> Self {
55 Self {
56 sequence_number,
57 flags,
58 }
59 }
60
61 pub fn make_reserved(number: u32) -> Self {
63 Self {
64 sequence_number: RESERVED_LOC_AVAILABLE_START + number,
65 flags: LocFlags::RESERVED,
66 }
67 }
68
69 pub fn make_normal(number: u32) -> Self {
71 Self {
72 sequence_number: NORMAL_LOC_START_IDX + number,
73 flags: 0,
74 }
75 }
76
77 pub fn is_valid(&self) -> bool {
78 self.sequence_number != INVALID_LOC_IDX
79 }
80
81 pub fn is_reserved(&self) -> bool {
82 self.flags & LocFlags::RESERVED != 0
83 }
84
85 pub fn is_itinerant(&self) -> bool {
86 self.flags & LocFlags::ITINERANT != 0
87 }
88
89 pub fn is_virtual(&self) -> bool {
90 self.sequence_number == GLOBAL_FIXED_LOC_IDX
91 }
92
93 pub fn is_local(&self) -> bool {
94 self.sequence_number >= LOCAL_LOC_START_IDX
95 && self.sequence_number <= LOCAL_LOC_END_IDX
96 }
97
98 pub fn read(reader: &mut impl Read) -> Result<Self> {
99 let sequence_number = reader.read_u32()?;
100 let flags = reader.read_u16()?;
101 Ok(Self {
102 sequence_number,
103 flags,
104 })
105 }
106
107 pub fn write(&self, writer: &mut impl Write) -> Result<()> {
108 writer.write_all(&self.sequence_number.to_le_bytes())?;
109 writer.write_all(&self.flags.to_le_bytes())?;
110 Ok(())
111 }
112
113 pub const GLOBAL_FIXED: Location = Location {
115 sequence_number: GLOBAL_FIXED_LOC_IDX,
116 flags: 0,
117 };
118 pub const LOCAL_START: Location = Location {
119 sequence_number: LOCAL_LOC_START_IDX,
120 flags: 0,
121 };
122 pub const LOCAL_END: Location = Location {
123 sequence_number: LOCAL_LOC_END_IDX,
124 flags: 0,
125 };
126 pub const NORMAL_START: Location = Location {
127 sequence_number: NORMAL_LOC_START_IDX,
128 flags: 0,
129 };
130 pub const GLOBAL_SERVER: Location = Location {
131 sequence_number: GLOBAL_SERVER_LOC_IDX,
132 flags: LocFlags::RESERVED,
133 };
134 pub const INVALID: Location = Location {
135 sequence_number: INVALID_LOC_IDX,
136 flags: 0,
137 };
138}
139
140impl PartialEq for Location {
141 fn eq(&self, other: &Self) -> bool {
142 self.sequence_number == other.sequence_number
144 && (self.flags & !LocFlags::ITINERANT) == (other.flags & !LocFlags::ITINERANT)
145 }
146}
147
148impl Eq for Location {}
149
150impl std::hash::Hash for Location {
151 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
152 self.sequence_number.hash(state);
153 (self.flags & !LocFlags::ITINERANT).hash(state);
154 }
155}
156
157impl PartialOrd for Location {
158 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
159 Some(self.cmp(other))
160 }
161}
162
163impl Ord for Location {
164 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
165 self.sequence_number.cmp(&other.sequence_number)
166 }
167}
168
169impl Default for Location {
170 fn default() -> Self {
171 Self::invalid()
172 }
173}
174
175impl fmt::Debug for Location {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 write!(f, "Location(S:{:#x} F:{:#x})", self.sequence_number, self.flags)
178 }
179}
180
181impl fmt::Display for Location {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 write!(f, "S{:#x}F{:#x}", self.sequence_number, self.flags)
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use std::io::Cursor;
191
192 #[test]
193 fn test_invalid_location() {
194 let loc = Location::invalid();
195 assert!(!loc.is_valid());
196 }
197
198 #[test]
199 fn test_valid_location() {
200 let loc = Location::new(100, 0);
201 assert!(loc.is_valid());
202 }
203
204 #[test]
205 fn test_round_trip() {
206 let loc = Location::new(0x12345678, 0x0003);
207 let mut buf = Vec::new();
208 loc.write(&mut buf).unwrap();
209 assert_eq!(buf.len(), 6);
210
211 let mut cursor = Cursor::new(&buf);
212 let loc2 = Location::read(&mut cursor).unwrap();
213 assert_eq!(loc, loc2);
214 }
215
216 #[test]
217 fn test_itinerant_equality() {
218 let loc1 = Location::new(100, 0);
219 let loc2 = Location::new(100, LocFlags::ITINERANT);
220 assert_eq!(loc1, loc2);
221 }
222
223 #[test]
224 fn test_reserved() {
225 let loc = Location::make_reserved(5);
226 assert!(loc.is_reserved());
227 assert!(loc.is_valid());
228 }
229
230 #[test]
231 fn test_well_known() {
232 assert!(Location::GLOBAL_FIXED.is_virtual());
233 assert!(Location::GLOBAL_SERVER.is_reserved());
234 assert!(!Location::INVALID.is_valid());
235 }
236}