1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
use bitflags::bitflags;
use bytes::{Buf, BufMut, BytesMut};
use rand::Rng;

/// MessageID, unique ID per Message.
pub type Mid = u64;
/// ChannelID, unique ID per Channel (Protocol)
pub type Cid = u64;
/// Every Stream has a `Prio` and guaranteed [`Bandwidth`].
/// Every send, the guarantees part is used first.
/// If there is still bandwidth left, it will be shared by all Streams with the
/// same priority. Prio 0 will be send first, then 1, ... till the last prio 7
/// is send. Prio must be < 8!
///
/// [`Bandwidth`]: crate::Bandwidth
pub type Prio = u8;
/// guaranteed `Bandwidth`. See [`Prio`]
///
/// [`Prio`]: crate::Prio
pub type Bandwidth = u64;

bitflags! {
    /// use promises to modify the behavior of [`Streams`].
    /// see the consts in this `struct` for
    ///
    /// [`Streams`]: crate::api::Stream
    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
    pub struct Promises: u8 {
        /// this will guarantee that the order of messages which are send on one side,
        /// is the same when received on the other.
        const ORDERED = 0b00000001;
        /// this will guarantee that messages received haven't been altered by errors,
        /// like bit flips, this is done with a checksum.
        const CONSISTENCY = 0b00000010;
        /// this will guarantee that the other side will receive every message exactly
        /// once no messages are dropped
        const GUARANTEED_DELIVERY = 0b00000100;
        /// this will enable the internal compression on this, only useable with #[cfg(feature = "compression")]
        /// [`Stream`](crate::api::Stream)
        const COMPRESSED = 0b00001000;
        /// this will enable the internal encryption on this
        /// [`Stream`](crate::api::Stream)
        const ENCRYPTED = 0b00010000;
    }
}

impl Promises {
    pub const fn to_le_bytes(self) -> [u8; 1] { self.bits().to_le_bytes() }
}

pub(crate) const VELOREN_MAGIC_NUMBER: [u8; 7] = *b"VELOREN";
/// When this semver differs, 2 Networks can't communicate.
pub const VELOREN_NETWORK_VERSION: [u32; 3] = [0, 6, 0];
pub(crate) const STREAM_ID_OFFSET1: Sid = Sid::new(0);
pub(crate) const STREAM_ID_OFFSET2: Sid = Sid::new(u64::MAX / 2);
/// Maximal possible Prio to choose (for performance reasons)
pub const HIGHEST_PRIO: u8 = 7;

/// Support struct used for uniquely identifying `Participant` over the
/// `Network`.
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub struct Pid {
    internal: u128,
}

/// Unique ID per Stream, in one Channel.
/// one side will always start with 0, while the other start with u64::MAX / 2.
/// number increases for each created Stream.
#[derive(PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
pub struct Sid {
    internal: u64,
}

impl Pid {
    /// create a new Pid with a random interior value
    ///
    /// # Example
    /// ```rust
    /// use veloren_network_protocol::Pid;
    ///
    /// let pid = Pid::new();
    /// ```
    pub fn new() -> Self {
        Self {
            internal: rand::thread_rng().gen(),
        }
    }

    /// don't use fake! just for testing!
    /// This will panic if pid i greater than 7, as I do not want you to use
    /// this in production!
    #[doc(hidden)]
    pub fn fake(pid_offset: u8) -> Self {
        assert!(pid_offset < 8);
        let o = pid_offset as u128;
        const OFF: [u128; 5] = [
            0x40,
            0x40 * 0x40,
            0x40 * 0x40 * 0x40,
            0x40 * 0x40 * 0x40 * 0x40,
            0x40 * 0x40 * 0x40 * 0x40 * 0x40,
        ];
        Self {
            internal: o + o * OFF[0] + o * OFF[1] + o * OFF[2] + o * OFF[3] + o * OFF[4],
        }
    }

    #[inline]
    pub(crate) fn from_bytes(bytes: &mut BytesMut) -> Self {
        Self {
            internal: bytes.get_u128_le(),
        }
    }

    #[inline]
    pub(crate) fn to_bytes(self, bytes: &mut BytesMut) { bytes.put_u128_le(self.internal) }
}

impl Sid {
    pub const fn new(internal: u64) -> Self { Self { internal } }

    pub fn get_u64(&self) -> u64 { self.internal }

    #[inline]
    pub(crate) fn from_bytes(bytes: &mut BytesMut) -> Self {
        Self {
            internal: bytes.get_u64_le(),
        }
    }

    #[inline]
    pub(crate) fn to_bytes(self, bytes: &mut BytesMut) { bytes.put_u64_le(self.internal) }
}

impl std::fmt::Debug for Pid {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        const BITS_PER_SIXLET: usize = 6;
        //only print last 6 chars of number as full u128 logs are unreadable
        const CHAR_COUNT: usize = 6;
        for i in 0..CHAR_COUNT {
            write!(
                f,
                "{}",
                sixlet_to_str((self.internal >> (i * BITS_PER_SIXLET)) & 0x3F)
            )?;
        }
        Ok(())
    }
}

impl Default for Pid {
    fn default() -> Self { Pid::new() }
}

impl std::fmt::Display for Pid {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) }
}

impl std::ops::AddAssign for Sid {
    fn add_assign(&mut self, other: Self) {
        *self = Self {
            internal: self.internal + other.internal,
        };
    }
}

impl std::fmt::Debug for Sid {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        //only print last 6 chars of number as full u128 logs are unreadable
        write!(f, "{}", self.internal.rem_euclid(1000000))
    }
}

impl From<u64> for Sid {
    fn from(internal: u64) -> Self { Sid { internal } }
}

impl std::fmt::Display for Sid {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.internal)
    }
}

fn sixlet_to_str(sixlet: u128) -> char {
    b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[sixlet as usize] as char
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn frame_creation() {
        Pid::new();
        assert_eq!(format!("{}", Pid::fake(0)), "AAAAAA");
        assert_eq!(format!("{}", Pid::fake(1)), "BBBBBB");
        assert_eq!(format!("{}", Pid::fake(2)), "CCCCCC");
    }

    #[test]
    fn test_sixlet_to_str() {
        assert_eq!(sixlet_to_str(0), 'A');
        assert_eq!(sixlet_to_str(29), 'd');
        assert_eq!(sixlet_to_str(63), '/');
    }
}