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}