use crate::driver::request::RequestId;
use crate::sys::token::Token;

#[repr(C, u8)]
#[derive(Clone, Copy)]
pub(in crate::driver) enum Wire {
    Ignore = 0,
    Accept(Token) = 1,
    Recv(Token) = 2,
    Write(Token) = 4,
    Request(RequestId) = 5,
}

const WIRE_MAX_TAG: u8 = 5;

const _: () = assert!(std::mem::size_of::<Wire>() == 8);
const _: () = assert!(std::mem::align_of::<Wire>() == 1);
const _: () = assert!(std::mem::size_of::<Token>() == 7);
const _: () = assert!(std::mem::size_of::<RequestId>() == 7);

#[inline(always)]
fn encode(w: Wire) -> u64 {
    unsafe { std::mem::transmute(w) }
}

#[inline(always)]
pub(in crate::driver) fn decode_wire(raw: u64) -> Wire {
    let tag = raw.to_ne_bytes()[0];
    if tag == 3 || tag > WIRE_MAX_TAG {
        return Wire::Ignore;
    }

    unsafe { std::mem::transmute(raw) }
}

pub(in crate::driver) fn request(id: RequestId) -> u64 {
    encode(Wire::Request(id))
}

pub(in crate::driver) fn write(token: Token) -> u64 {
    encode(Wire::Write(token))
}

pub(in crate::driver) fn accept(token: Token) -> u64 {
    encode(Wire::Accept(token))
}

pub(in crate::driver) fn recv(token: Token) -> u64 {
    encode(Wire::Recv(token))
}

pub(in crate::driver) fn ignore() -> u64 {
    encode(Wire::Ignore)
}
