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), '/');
}
}