mid_net/utils.rs
1use std::io;
2
3use crate::proto::PacketType;
4
5pub trait FancyUtilExt {
6 fn unitize_io(self) -> io::Result<()>;
7}
8
9impl<T> FancyUtilExt for io::Result<T> {
10 fn unitize_io(self) -> io::Result<()> {
11 self.map(|_| ())
12 }
13}
14
15#[rustfmt::skip]
16pub mod flags {
17 pub const SHORT: u8 = 1 << 0;
18 pub const SHORT_CLIENT: u8 = 1 << 1;
19 pub const COMPRESSED: u8 = 1 << 2;
20
21 /// Checks whether packet is short or not (size of length = 1 or 2).
22 ///
23 /// Example:
24 /// ```
25 /// use mid_net::utils::{flags, encode_type};
26 ///
27 /// assert!(
28 /// flags::is_short(encode_type(13, flags::COMPRESSED | flags::SHORT))
29 /// );
30 /// ```
31 pub const fn is_short(f: u8) -> bool {
32 (f & SHORT) != 0
33 }
34
35 /// Checks whether client id field is short or not
36 /// (size of client id = 1 or 2).
37 ///
38 /// Example:
39 /// ```
40 /// use mid_net::utils::{flags, encode_type};
41 ///
42 /// assert!(
43 /// flags::is_short_client(encode_type(31, flags::SHORT_CLIENT))
44 /// );
45 /// ```
46 pub const fn is_short_client(f: u8) -> bool {
47 (f & SHORT_CLIENT) != 0
48 }
49
50 /// Checks whether packet payload is compressed or not.
51 ///
52 /// Example:
53 /// ```
54 /// use mid_net::utils::{flags, encode_type};
55 ///
56 /// assert!(
57 /// flags::is_compressed(encode_type(12, flags::COMPRESSED))
58 /// );
59 /// ```
60 pub const fn is_compressed(f: u8) -> bool {
61 (f & COMPRESSED) != 0
62 }
63}
64
65pub const fn encode_fwd_header(
66 client_id: u16,
67 length: u16,
68 compressed: bool,
69) -> ([u8; 5], usize) {
70 let mut flags: u8 = 0;
71 let mut offset: usize = 1;
72 let mut buf = [0; 5];
73
74 offset += if client_id <= 0xff {
75 flags |= flags::SHORT_CLIENT;
76 buf[offset] = client_id as u8;
77
78 1
79 } else {
80 buf[offset] = (client_id & 0xff) as u8;
81 buf[offset + 1] = (client_id >> 8) as u8;
82
83 2
84 };
85 offset += if length <= 0xff {
86 flags |= flags::SHORT;
87 buf[offset] = length as u8;
88
89 1
90 } else {
91 buf[offset] = (length & 0xff) as u8;
92 buf[offset + 1] = (length >> 8) as u8;
93
94 2
95 };
96
97 if compressed {
98 flags |= flags::COMPRESSED;
99 }
100
101 buf[0] = encode_type(PacketType::Forward as u8, flags);
102 (buf, offset)
103}
104
105/// Decodes packed type. Returns `packet type` and `flags`.
106///
107/// Example:
108/// ```
109/// use mid_net::utils::{
110/// decode_type,
111/// encode_type,
112/// };
113///
114/// assert_eq!(decode_type(encode_type(10, 0b111)), (10, 0b111));
115/// ```
116pub const fn decode_type(pkt_type: u8) -> (u8, u8) {
117 (pkt_type >> 3, pkt_type & 0b111)
118}
119
120/// Encodes packet type to contain both type & flags.
121///
122/// Example:
123/// ```
124/// use mid_net::utils::encode_type;
125///
126/// assert_eq!(encode_type(0, 0b111), 0b111);
127/// assert_eq!(encode_type(1, 0b111), (1 << 3) | 0b111);
128/// ```
129pub const fn encode_type(pkt_type: u8, pkt_flags: u8) -> u8 {
130 debug_assert!(pkt_flags <= 0b111);
131 debug_assert!(pkt_type <= 0x1f);
132
133 (pkt_type << 3) | pkt_flags
134}
135
136/// Same as [`encode_type`], but pkt_flags = 0
137///
138/// Example:
139/// ```
140/// use mid_net::utils::{
141/// encode_type,
142/// ident_type,
143/// };
144///
145/// assert_eq!(ident_type(10), encode_type(10, 0));
146/// assert_eq!(ident_type(4), encode_type(4, 0));
147/// assert_eq!(ident_type(0), encode_type(0, 0));
148/// ```
149pub const fn ident_type(pkt_type: u8) -> u8 {
150 encode_type(pkt_type, 0)
151}