#[derive(Clone, Copy, Debug)]
pub struct SockAddr {
    storage: libc::sockaddr_storage,
    len: libc::socklen_t,
}

impl SockAddr {
    pub fn empty() -> Self {
        let storage =
            unsafe { std::mem::MaybeUninit::<libc::sockaddr_storage>::zeroed().assume_init() };
        Self {
            storage,
            len: std::mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t,
        }
    }

    /// # Safety
    /// `T` must be a valid `sockaddr_*` family struct and `len` its byte length.
    pub unsafe fn from_storage<T>(addr: T, len: libc::socklen_t) -> Self {
        let mut storage = std::mem::MaybeUninit::<libc::sockaddr_storage>::zeroed();
        unsafe {
            std::ptr::write(storage.as_mut_ptr() as *mut T, addr);
        }
        Self {
            storage: unsafe { storage.assume_init() },
            len,
        }
    }

    pub fn storage_ptr(&self) -> *const libc::sockaddr_storage {
        std::ptr::addr_of!(self.storage)
    }

    pub fn storage_mut_ptr(&mut self) -> *mut libc::sockaddr_storage {
        std::ptr::addr_of_mut!(self.storage)
    }

    pub fn set_len(&mut self, len: libc::socklen_t) {
        self.len = len;
    }

    pub fn addr_ptr(&self) -> *const libc::sockaddr {
        std::ptr::addr_of!(self.storage) as *const libc::sockaddr
    }

    pub fn addr_mut_ptr(&mut self) -> *mut libc::sockaddr {
        std::ptr::addr_of_mut!(self.storage) as *mut libc::sockaddr
    }

    pub fn addr_len(&self) -> libc::socklen_t {
        self.len
    }

    pub fn addr_len_ptr(&mut self) -> *mut libc::socklen_t {
        &mut self.len as *mut libc::socklen_t
    }
}
