npsd 0.2.0

Network payload serializer / deserializer framework
Documentation
use core::mem;

use super::{Error, AsyncMiddleware, AsyncPayload, AsyncIntoPayload, AsyncFromPayload};

#[macro_export]
macro_rules! async_payload_be_bytes {
    ($type:ty) => {
        impl<C: Send + Sync> AsyncIntoPayload<C> for $type {
            #[inline]
            async fn poll_into_payload<'m, M: AsyncMiddleware<'m>>(&self, _ctx: &mut C, next: &mut M) -> Result<(), Error> {
                next.poll_write(&self.to_be_bytes()).await
            }
        }
        
        impl<'a, C: Send + Sync> AsyncFromPayload<'a, C> for $type {
            #[inline]
            async fn poll_from_payload<M: AsyncMiddleware<'a>>(_ctx: &mut C, next: &mut M) -> Result<Self, Error> {
                let slice: &[u8] = next.poll_read(mem::size_of::<Self>()).await?;

                Ok(<Self>::from_be_bytes(unsafe {
                    *(slice.as_ptr() as *const [u8; mem::size_of::<Self>()])
                }))
            }
        }

        impl<'a, C: Send + Sync> AsyncPayload<'a, C> for $type {}
    };
}

async_payload_be_bytes!(i8);
async_payload_be_bytes!(u8);
async_payload_be_bytes!(i16);
async_payload_be_bytes!(u16);
async_payload_be_bytes!(i32);
async_payload_be_bytes!(u32);
async_payload_be_bytes!(i64);
async_payload_be_bytes!(u64);
async_payload_be_bytes!(i128);
async_payload_be_bytes!(u128);
async_payload_be_bytes!(f32);
async_payload_be_bytes!(f64);

impl<C: Send + Sync> AsyncIntoPayload<C> for isize {
    #[inline]
    async fn poll_into_payload<'m, M: AsyncMiddleware<'m>>(&self, ctx: &mut C, next: &mut M) -> Result<(), Error> {
        next.poll_into_payload(&(*self as i64), ctx).await
    }
}

impl<'a, C: Send + Sync> AsyncFromPayload<'a, C> for isize {
    async fn poll_from_payload<M: AsyncMiddleware<'a>>(ctx: &mut C, next: &mut M) -> Result<Self, Error> {
        let value: i64 = next.poll_from_payload(ctx).await?;
        Ok(value as Self)
    }
}

impl<'a, C: Send + Sync> AsyncPayload<'a, C> for isize {}

impl<C: Send + Sync> AsyncIntoPayload<C> for usize {
    async fn poll_into_payload<'m, M: AsyncMiddleware<'m>>(&self, ctx: &mut C, next: &mut M) -> Result<(), Error> {
        let mut value = *self;
        const CONTINUATION_BIT: u8 = 0b1000_0000;
        const DATA_BITS: usize = 7;

        loop {
            if value < 0x80 {
                next.poll_into_payload(&(value as u8), ctx).await?;
                break;
            } else {
                next.poll_into_payload(&(((value as u8) & 0x7F) | CONTINUATION_BIT), ctx).await?;

                value >>= DATA_BITS;
            }
        }

        Ok(())
    }
}

impl<'a, C: Send + Sync> AsyncFromPayload<'a, C> for usize {
    async fn poll_from_payload<M: AsyncMiddleware<'a>>(ctx: &mut C, next: &mut M) -> Result<Self, Error> {
        const CONTINUATION_BIT: u8 = 0b1000_0000;
        const DATA_BITS: u8 = 7;

        let mut result = 0usize;
        let mut shift = 0u8;

        loop {
            let byte: u8 = next.poll_from_payload(ctx).await?;

            let value = (byte & !CONTINUATION_BIT) as usize;
            result |= value << usize::from(shift);
            
            if byte & CONTINUATION_BIT == 0 {
                break;
            }

            shift += DATA_BITS;

            if usize::from(shift) >= mem::size_of::<usize>() * 8 {
                return Err(Error::IndexOutOfBounds(usize::from(shift)));
            }
        }

        Ok(result)
    }
}

impl<'a, C: Send + Sync> AsyncPayload<'a, C> for usize {}

impl<C: Send + Sync> AsyncIntoPayload<C> for () {
    async fn poll_into_payload<'b, M: AsyncMiddleware<'b>>(&self, _ctx: &mut C, _next: &mut M) -> Result<(), Error> {
        Ok(())
    }
}

impl<'a, C: Send + Sync> AsyncFromPayload<'a, C> for () {
    async fn poll_from_payload<M: AsyncMiddleware<'a>>(_ctx: &mut C, _next: &mut M) -> Result<Self, Error> {
        Ok(())
    }
}

impl<'a, C: Send + Sync> AsyncPayload<'a, C> for () {}

impl<C: Send + Sync> AsyncIntoPayload<C> for bool {
    async fn poll_into_payload<'m, M: AsyncMiddleware<'m>>(&self, ctx: &mut C, next: &mut M) -> Result<(), Error> {
        if *self {
            next.poll_into_payload(&1u8, ctx).await
        } else {
            next.poll_into_payload(&0u8, ctx).await
        }
    }
}

impl<'a, C: Send + Sync> AsyncFromPayload<'a, C> for bool {
    async fn poll_from_payload<M: AsyncMiddleware<'a>>(ctx: &mut C, next: &mut M) -> Result<Self, Error> {
        let byte: u8 = next.poll_from_payload(ctx).await?;

        if byte != 0 {
            Ok(true)
        } else {
            Ok(false)
        }
    }
}

impl<'a, C: Send + Sync> AsyncPayload<'a, C> for bool {}