1use std::fmt::Display;
2use zerocopy::{LE, U16};
3use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
4
5#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
10#[repr(transparent)]
11pub struct Stream(u16);
12
13impl Stream {
14 pub const OLD_STREAM_DIR: Stream = Stream(0);
18
19 pub const PDB: Stream = Stream(1);
22
23 pub const TPI: Stream = Stream(2);
25
26 pub const DBI: Stream = Stream(3);
28
29 pub const IPI: Stream = Stream(4);
31
32 pub fn new(index: u16) -> Option<Stream> {
36 if index == NIL_STREAM_INDEX {
37 None
38 } else {
39 Some(Stream(index))
40 }
41 }
42
43 pub fn value(self) -> u16 {
45 self.0
46 }
47
48 pub fn index(self) -> usize {
50 debug_assert!(self.0 != NIL_STREAM_INDEX);
51 self.0 as usize
52 }
53}
54
55impl From<Stream> for u32 {
56 fn from(value: Stream) -> Self {
57 value.value() as u32
58 }
59}
60
61impl Display for Stream {
62 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
63 Display::fmt(&self.0, f)
64 }
65}
66
67pub const NIL_STREAM_INDEX: u16 = 0xffff;
69
70#[derive(Clone, Debug)]
72pub struct StreamIndexIsNilError;
73
74impl std::error::Error for StreamIndexIsNilError {}
75
76impl Display for StreamIndexIsNilError {
77 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
78 fmt.write_str("The given stream index is NIL.")
79 }
80}
81
82#[derive(Clone, Debug)]
83pub struct StreamIndexOverflow;
84
85impl std::error::Error for StreamIndexOverflow {}
86
87impl Display for StreamIndexOverflow {
88 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
89 fmt.write_str("The value is out of range for 16-bit stream indexes.")
90 }
91}
92
93impl TryFrom<u16> for Stream {
94 type Error = StreamIndexIsNilError;
95
96 fn try_from(i: u16) -> Result<Self, Self::Error> {
97 if i != NIL_STREAM_INDEX {
98 Ok(Self(i))
99 } else {
100 Err(StreamIndexIsNilError)
101 }
102 }
103}
104
105#[derive(
107 Copy, Clone, Eq, PartialEq, Debug, IntoBytes, FromBytes, Immutable, KnownLayout, Unaligned,
108)]
109#[repr(transparent)]
110pub struct StreamIndexU16(pub U16<LE>);
111
112impl StreamIndexU16 {
113 pub const NIL: Self = Self(U16::from_bytes(NIL_STREAM_INDEX.to_le_bytes()));
115
116 pub fn get(self) -> Option<u32> {
119 let s = self.0.get();
120 if s != NIL_STREAM_INDEX {
121 Some(s as u32)
122 } else {
123 None
124 }
125 }
126
127 pub fn get_err(self) -> Result<u32, StreamIndexIsNilError> {
130 let s = self.0.get();
131 if s != NIL_STREAM_INDEX {
132 Ok(s as u32)
133 } else {
134 Err(StreamIndexIsNilError)
135 }
136 }
137}
138
139impl TryFrom<u32> for StreamIndexU16 {
140 type Error = StreamIndexOverflow;
141
142 fn try_from(s: u32) -> Result<Self, Self::Error> {
143 if s < NIL_STREAM_INDEX as u32 {
144 Ok(StreamIndexU16(U16::new(s as u16)))
145 } else {
146 Err(StreamIndexOverflow)
147 }
148 }
149}
150
151impl TryFrom<Option<u32>> for StreamIndexU16 {
152 type Error = StreamIndexOverflow;
153
154 fn try_from(s_opt: Option<u32>) -> Result<Self, Self::Error> {
155 if let Some(s) = s_opt {
156 if s < NIL_STREAM_INDEX as u32 {
157 Ok(StreamIndexU16(U16::new(s as u16)))
158 } else {
159 Err(StreamIndexOverflow)
160 }
161 } else {
162 Ok(Self::NIL)
163 }
164 }
165}