//! Defines data types for network operations

#[cfg(any(feature = "alloc", feature = "rustc_std_alloc"))]
pub mod dns;
#[cfg(feature = "alloc")]
pub mod netconfig;

pub mod link;
pub mod options;
pub mod protocols;
pub mod types;

pub use crate::generated::{SocketShutdown, SocketType};
use crate::io::RawFd;

pub use types::{
    subnet_addr::{SubnetAddr, SubnetV4Addr},
    MacAddress,
};

/// Message structure describing how data + metadata should be sent to the other side of some
/// socket
#[repr(C)]
pub struct MessageHeader<'a> {
    /// Destination address, depends on the socket type
    pub destination: Option<&'a [u8]>,
    /// Raw payload data
    pub payload: &'a [u8],
    /// Ancillary data, depends on the socket type
    pub ancillary: &'a [u8],
}

/// Message structure describing how data + metadata should be received from a socket
#[repr(C)]
pub struct MessageHeaderMut<'a> {
    /// Optional: storage for the source address, depends on the socket type
    pub source: Option<&'a mut [u8]>,
    /// Buffer to store the payload in
    pub payload: &'a mut [u8],
    /// Optional: storage for the ancillary data, depends on the socket type
    pub ancillary: Option<&'a mut [u8]>,
    /// Optional: if ancillary data is received, the length will be stored in this field
    pub ancillary_len: usize,
}

/// Ancillary message which can be sent over a socket
#[derive(Debug, Clone)]
pub enum AncillaryMessage {
    /// Send a file descriptor to the recepient. (Local sockets only)
    File(RawFd),
}

abi_serde::impl_struct_serde!(MessageHeader<'de>: [
    destination,
    payload,
    ancillary
]);
abi_serde::impl_enum1_serde!(AncillaryMessage: [
    File => 1
]);

/// Describes a method to query an interface
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum SocketInterfaceQuery<'a> {
    /// Query by name
    ByName(&'a str),
    /// Query by id
    ById(u32),
}

impl<'a> From<&'a str> for SocketInterfaceQuery<'a> {
    fn from(value: &'a str) -> Self {
        Self::ByName(value)
    }
}

impl From<u32> for SocketInterfaceQuery<'_> {
    fn from(value: u32) -> Self {
        Self::ById(value)
    }
}

abi_serde::impl_enum1_serde!(SocketInterfaceQuery<'de>: [
    ById => 1,
    ByName => 2
]);

#[cfg(test)]
mod tests {
    use abi_serde::wire;

    use super::SocketInterfaceQuery;

    #[test]
    fn socket_interface_query_serde() {
        let mut buffer = [0; 512];
        let source = SocketInterfaceQuery::ById(123);
        let len = wire::to_slice(&source, &mut buffer).unwrap();
        let result: SocketInterfaceQuery<'_> = wire::from_slice(&buffer[..len]).unwrap();
        assert_eq!(source, result);

        let mut buffer = [0; 512];
        let source = SocketInterfaceQuery::ByName("hello");
        let len = wire::to_slice(&source, &mut buffer).unwrap();
        let result: SocketInterfaceQuery<'_> = wire::from_slice(&buffer[..len]).unwrap();
        assert_eq!(source, result);
    }
}
