use crate::traits::*;
use crate::util::*;
impl TlRead<'_> for bool {
type Repr = Boxed;
fn read_from(packet: &[u8], offset: &mut usize) -> TlResult<Self> {
match u32::read_from(packet, offset) {
Ok(BOOL_TRUE) => Ok(true),
Ok(BOOL_FALSE) => Ok(false),
Ok(_) => Err(TlError::UnknownConstructor),
Err(e) => Err(e),
}
}
}
impl TlWrite for bool {
type Repr = Boxed;
#[inline(always)]
fn max_size_hint(&self) -> usize {
std::mem::size_of::<u32>()
}
#[inline(always)]
fn write_to<T>(&self, packet: &mut T)
where
T: TlPacket,
{
packet.write_u32(if *self { BOOL_TRUE } else { BOOL_FALSE })
}
}
macro_rules! impl_read_from_packet(
($ty:ty) => {
impl TlRead<'_> for $ty {
type Repr = Bare;
#[inline(always)]
fn read_from(packet: &[u8], offset: &mut usize) -> TlResult<Self> {
if unlikely(packet.len() < *offset + std::mem::size_of::<$ty>()) {
Err(TlError::UnexpectedEof)
} else {
let value = <$ty>::from_le_bytes(unsafe {
*(packet.as_ptr().add(*offset) as *const [u8; std::mem::size_of::<$ty>()])
});
*offset += std::mem::size_of::<$ty>();
Ok(value)
}
}
}
}
);
impl_read_from_packet!(u32);
impl TlWrite for u32 {
type Repr = Bare;
#[inline(always)]
fn max_size_hint(&self) -> usize {
std::mem::size_of::<Self>()
}
#[inline(always)]
fn write_to<T>(&self, packet: &mut T)
where
T: TlPacket,
{
packet.write_u32(*self)
}
}
impl_read_from_packet!(i32);
impl TlWrite for i32 {
type Repr = Bare;
#[inline(always)]
fn max_size_hint(&self) -> usize {
std::mem::size_of::<Self>()
}
#[inline(always)]
fn write_to<T>(&self, packet: &mut T)
where
T: TlPacket,
{
packet.write_i32(*self)
}
}
impl_read_from_packet!(u64);
impl TlWrite for u64 {
type Repr = Bare;
#[inline(always)]
fn max_size_hint(&self) -> usize {
std::mem::size_of::<Self>()
}
#[inline(always)]
fn write_to<T>(&self, packet: &mut T)
where
T: TlPacket,
{
packet.write_u64(*self)
}
}
impl_read_from_packet!(i64);
impl TlWrite for i64 {
type Repr = Bare;
#[inline(always)]
fn max_size_hint(&self) -> usize {
std::mem::size_of::<Self>()
}
#[inline(always)]
fn write_to<T>(&self, packet: &mut T)
where
T: TlPacket,
{
packet.write_i64(*self)
}
}
impl_read_from_packet!(f64);
impl TlWrite for f64 {
type Repr = Bare;
#[inline(always)]
fn max_size_hint(&self) -> usize {
std::mem::size_of::<Self>()
}
#[inline(always)]
fn write_to<T>(&self, packet: &mut T)
where
T: TlPacket,
{
packet.write_u64(convert_f64(self))
}
}
#[inline(always)]
fn convert_f64(f: &f64) -> u64 {
const SIGN_MASK: u64 = 0x8000000000000000u64;
const EXP_MASK: u64 = 0x7ff0000000000000u64;
const MAN_MASK: u64 = 0x000fffffffffffffu64;
const CANONICAL_NAN_BITS: u64 = 0x7ff8000000000000u64;
const CANONICAL_ZERO_BITS: u64 = 0x0u64;
if f.is_nan() {
return CANONICAL_NAN_BITS;
}
let bits = f.to_bits();
let sign = if bits >> 63 == 0 { 1i8 } else { -1 };
let mut exp = ((bits >> 52) & 0x7ff) as i16;
let man = if exp == 0 {
(bits & 0xfffffffffffff) << 1
} else {
(bits & 0xfffffffffffff) | 0x10000000000000
};
if man == 0 {
return CANONICAL_ZERO_BITS;
}
exp -= 1023 + 52;
let exp_u64 = exp as u64;
let sign_u64 = u64::from(sign > 0);
(man & MAN_MASK) | ((exp_u64 << 52) & EXP_MASK) | ((sign_u64 << 63) & SIGN_MASK)
}
const BOOL_FALSE: u32 = 0xbc799737;
const BOOL_TRUE: u32 = 0x997275b5;