#![stable(feature = "os_fd", since = "1.66.0")]
#![allow(dead_code)]

mod net {
    use crate::os::yggdrasil::io::OwnedFd;
    use crate::os::yggdrasil::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
    use crate::sys_common::{self, AsInner, FromInner, IntoInner};
    use crate::{net, sys};

    macro_rules! impl_as_raw_fd {
        ($($t:ident)*) => {$(
            #[stable(feature = "rust1", since = "1.0.0")]
            impl AsRawFd for net::$t {
                #[inline]
                fn as_raw_fd(&self) -> RawFd {
                    self.as_inner().socket().as_raw_fd()
                }
            }
        )*};
    }

    macro_rules! impl_from_raw_fd {
        ($($t:ident)*) => {$(
            #[stable(feature = "rust1", since = "1.0.0")]
            impl FromRawFd for net::$t {
                #[inline]
                unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
                    let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
                    net::$t::from_inner(sys_common::net::$t::from_inner(socket))
                }
            }
        )*};
    }

    macro_rules! impl_into_raw_fd {
        ($($t:ident)*) => {$(
            #[stable(feature = "rust1", since = "1.0.0")]
            impl IntoRawFd for net::$t {
                #[inline]
                fn into_raw_fd(self) -> RawFd {
                    self.into_inner().into_socket().into_inner().into_raw_fd()
                }
            }
        )*};
    }

    impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
    impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
    impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
}

pub mod raw {
    #[stable(feature = "rust1", since = "1.0.0")]
    pub type RawFd = yggdrasil_rt::io::RawFd;

    #[stable(feature = "rust1", since = "1.0.0")]
    pub trait AsRawFd {
        #[stable(feature = "rust1", since = "1.0.0")]
        fn as_raw_fd(&self) -> RawFd;
    }

    #[stable(feature = "rust1", since = "1.0.0")]
    pub trait FromRawFd {
        #[stable(feature = "rust1", since = "1.0.0")]
        unsafe fn from_raw_fd(fd: RawFd) -> Self;
    }

    #[stable(feature = "rust1", since = "1.0.0")]
    pub trait IntoRawFd {
        #[stable(feature = "rust1", since = "1.0.0")]
        fn into_raw_fd(self) -> RawFd;
    }

    #[stable(feature = "rust1", since = "1.0.0")]
    impl AsRawFd for RawFd {
        fn as_raw_fd(&self) -> RawFd {
            *self
        }
    }

    #[stable(feature = "rust1", since = "1.0.0")]
    impl FromRawFd for RawFd {
        unsafe fn from_raw_fd(fd: RawFd) -> Self {
            fd
        }
    }

    #[stable(feature = "rust1", since = "1.0.0")]
    impl IntoRawFd for RawFd {
        fn into_raw_fd(self) -> RawFd {
            self
        }
    }
}

pub mod owned {
    #![stable(feature = "io_safety", since = "1.63.0")]

    use super::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
    use crate::marker::PhantomData;
    use crate::mem::forget;

    #[stable(feature = "io_safety", since = "1.63.0")]
    #[repr(transparent)]
    #[derive(Debug)]
    pub struct OwnedFd {
        fd: RawFd,
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    #[derive(Clone, Copy, Debug)]
    #[repr(transparent)]
    pub struct BorrowedFd<'fd> {
        fd: RawFd,
        _pd: PhantomData<&'fd OwnedFd>,
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    pub trait AsFd {
        #[stable(feature = "io_safety", since = "1.63.0")]
        fn as_fd(&self) -> BorrowedFd<'_>;
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    impl<T: AsFd> AsFd for &T {
        fn as_fd(&self) -> BorrowedFd<'_> {
            T::as_fd(self)
        }
    }

    // Borrowed

    impl BorrowedFd<'_> {
        #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
        #[stable(feature = "io_safety", since = "1.63.0")]
        pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
            // assert_ne!(fd, u32::MAX as RawFd);
            Self { fd, _pd: PhantomData }
        }
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    impl AsFd for BorrowedFd<'_> {
        fn as_fd(&self) -> BorrowedFd<'_> {
            *self
        }
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    impl AsRawFd for BorrowedFd<'_> {
        fn as_raw_fd(&self) -> RawFd {
            self.fd
        }
    }

    // Owned

    #[stable(feature = "io_safety", since = "1.63.0")]
    impl AsFd for OwnedFd {
        fn as_fd(&self) -> BorrowedFd<'_> {
            unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
        }
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    impl IntoRawFd for OwnedFd {
        fn into_raw_fd(self) -> RawFd {
            let fd = self.fd;
            forget(self);
            fd
        }
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    impl FromRawFd for OwnedFd {
        unsafe fn from_raw_fd(fd: RawFd) -> Self {
            Self { fd }
        }
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    impl AsRawFd for OwnedFd {
        fn as_raw_fd(&self) -> RawFd {
            self.fd
        }
    }

    #[stable(feature = "io_safety", since = "1.63.0")]
    impl Drop for OwnedFd {
        fn drop(&mut self) {
            unsafe {
                yggdrasil_rt::sys::close(self.fd).ok();
            }
        }
    }

    // TODO: AsFd for File, From<File> for OwnedFd, From<OwnedFd> for File,
}

#[stable(feature = "io_safety", since = "1.63.0")]
pub use owned::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub use raw::*;

use crate::io::StdinLock;

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> AsRawFd for StdinLock<'a> {
    fn as_raw_fd(&self) -> RawFd {
        todo!()
    }
}
