[
  {
    "path": ".gitignore",
    "content": "/target\nCargo.lock\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"ringbahn\"\nversion = \"0.0.0-experimental.3\"\nauthors = [\"Without Boats <woboats@gmail.com>\"]\ndescription = \"an experimental safe API for io-uring\"\nrepository = \"https://github.com/withoutboats/ringbahn\"\nlicense = \"MIT OR Apache-2.0\"\nedition = \"2018\"\n\n[dependencies]\nfutures-io = \"0.3.5\"\nfutures-core = \"0.3.5\"\nparking_lot = \"0.10.2\"\nonce_cell = \"1.3.1\"\nlibc = \"0.2.71\"\nuring-sys = \"0.7.4\"\nnix = \"0.18.0\"\niou = \"0.3.3\"\neither = \"1.6.1\"\nevent-listener = \"2.5.1\"\n\n[dev-dependencies]\ntempfile = \"3.1.0\"\nfutures = { version = \"0.3.5\", features = [\"thread-pool\"] }\n"
  },
  {
    "path": "README.md",
    "content": "# ringbahn - a safe interface to io-uring\n\nThe Berlin Ringbahn is a double-tracked commuter rail line which forms a complete ring around the\ncenter of the city of Berlin. Similarly, io-uring is a new interface for asynchronous IO with the\nLinux kernel built on a double ring buffer data structure.\n\nringbahn is an attempt to define a good interface to perform IO on io-uring with these properties:\n- 100% memory safe\n- Completely non-blocking\n- Ergonomic with async/await syntax\n- A zero-cost abstraction with minimal overhead\n- Abstracted over different patterns for driving the io-uring instance\n- Misuse-resistant with a well implemented driver\n\n**The current version of ringbahn is highly experimental and insufficiently hardened for production\nuse.** You are strongly recommended not to deploy the code under the current version. But tests, bug\nreports, user feedback, and other experiments are all welcome at this stage.\n\nThough ringbahn is a prototype, it demonstrates that a safe, ergonomic, efficient, and flexible\ninterface to io-uring is possible in Rust. It should be a goal for the Rust community not only to\nhave an adequate interface for io-uring, but to have the *best* interface for io-uring.\n\n## License\n\nringbahn is licensed under your choice of MIT or Apache-2.0.\n"
  },
  {
    "path": "examples/copy-file.rs",
    "content": "use futures::io::AsyncReadExt;\nuse futures::io::AsyncWriteExt;\n\nuse ringbahn::fs::File;\n\nfn main() {\n    futures::executor::block_on(async move {\n        let mut input:  File = File::open(\"props.txt\").await.unwrap();\n        let mut output: File = File::create(\"test.txt\").await.unwrap();\n        let mut buf = vec![0; 1024];\n        let len = input.read(&mut buf).await.unwrap();\n        output.write(&mut buf[0..len]).await.unwrap();\n        output.flush().await.unwrap();\n    });\n}\n"
  },
  {
    "path": "examples/echo-client.rs",
    "content": "use ringbahn::net::TcpStream;\n\nuse std::io::{self, BufRead, Write};\n\nuse futures::io::{AsyncBufReadExt, AsyncWriteExt};\nuse futures::executor::block_on;\n\nfn main() {\n    block_on(async move {\n        let mut stream = TcpStream::connect((\"127.0.0.1\", 7878)).await.unwrap();\n        let stdin = io::stdin();\n        let stdout = io::stdout();\n        let mut stdout = stdout;\n        let mut buf = String::new();\n\n        for line in stdin.lock().lines() {\n            let line = line.unwrap();\n            stream.write_all(line.as_bytes()).await.unwrap();\n            stream.read_line(&mut buf).await.unwrap();\n            stdout.write_all(buf.as_bytes()).unwrap();\n            buf.clear();\n        }\n    })\n}\n"
  },
  {
    "path": "examples/echo-server.rs",
    "content": "use ringbahn::net::TcpListener;\n\nuse futures::StreamExt;\nuse futures::io::{AsyncReadExt, AsyncWriteExt};\nuse futures::executor::{ThreadPool, block_on};\n\nfn main() {\n    let mut listener = TcpListener::bind((\"127.0.0.1\", 7878)).unwrap();\n    println!(\"listening on port 7878\");\n    let mut incoming = listener.incoming();\n    let pool = ThreadPool::new().unwrap();\n    block_on(async move {\n        while let Some(stream) = incoming.next().await {\n            println!(\"recieved connection\");\n            let (mut stream, _) = stream.unwrap();\n            pool.spawn_ok(async move {\n                loop {\n                    let mut buf = [0; 8096];\n                    let n = stream.read(&mut buf[..]).await.unwrap();\n                    println!(\"read {} bytes\", n);\n                    buf[n] = b'\\n';\n                    stream.write_all(&buf[0..n + 1]).await.unwrap();\n                    println!(\"write {} bytes\", n + 1);\n                }\n            });\n        }\n    });\n}\n"
  },
  {
    "path": "examples/read-event.rs",
    "content": "use ringbahn::*;\nuse std::fs::{metadata, File};\nuse std::io;\nuse std::os::unix::io::AsRawFd;\n\nfn main() -> io::Result<()> {\n    let driver = drive::demo::driver();\n    let meta = metadata(\"props.txt\")?;\n    let file = File::open(\"props.txt\")?;\n    let event = event::Read {\n        fd: file.as_raw_fd(),\n        buf: vec![0; meta.len() as usize].into(),\n        offset: 0\n    };\n    let submission = Submission::new(event, driver.clone());\n    futures::executor::block_on(async move {\n        let (event, result) = submission.await;\n        let bytes_read = result? as usize;\n        let content = String::from_utf8_lossy(&event.buf[0..bytes_read]).to_string();\n        ringbahn::print!(driver, \"{}\", content).await;\n        Ok(())\n    })\n}\n"
  },
  {
    "path": "props.txt",
    "content": "But this formidable power of death - and this is perhaps what accounts for part of its force and\nthe cynicism with which it has so greatly expanded its limits - now presents itself as the\ncounterpart of a power that exerts a positive influence on life, that endeavors to administer,\noptimize, and multiply it, subjecting it to precise controls and comprehensive regulations. Wars\nare no longer waged in the name of a sovereign who must be defended; they are waged on behalf of\nthe existence of everyone; entire populations are mobilized for the purpose of wholesale slaughter\nin the name of life necessity: massacres have become vital. It is as managers of life and survival,\nof bodies and the race, that so many regimes have been able to wage so many wars, causing so many\nmen to be killed.\n"
  },
  {
    "path": "src/buf.rs",
    "content": "use std::cmp;\nuse std::io;\nuse std::task::Poll;\n\nuse futures_core::ready;\n\nuse crate::ring::Cancellation;\n\n#[derive(Default, Debug)]\npub struct Buffer {\n    data: Option<Box<[u8]>>,\n    pos: u32,\n    cap: u32,\n}\n\nimpl Buffer {\n    pub fn buffered_from_read(&self) -> &[u8] {\n        self.data.as_deref().map_or(&[], |data| &data[self.pos as usize..self.cap as usize])\n    }\n\n    pub fn fill_buf(&mut self, fill: impl FnOnce(&mut [u8]) -> Poll<io::Result<u32>>)\n        -> Poll<io::Result<&[u8]>>\n    {\n        const CAPACITY: usize = 4096 * 2;\n\n        if self.pos >= self.cap {\n            if self.data.is_none() {\n                self.data = Some(vec![0; CAPACITY].into_boxed_slice());\n            }\n\n            self.cap = ready!(fill(self.data.as_deref_mut().unwrap()))?;\n            self.pos = 0;\n        }\n        Poll::Ready(Ok(self.buffered_from_read()))\n    }\n\n    pub fn consume(&mut self, amt: usize) {\n        self.pos = cmp::min(self.pos + amt as u32, self.cap);\n    }\n\n    pub fn clear(&mut self) {\n        self.pos = 0;\n        self.cap = 0;\n    }\n\n    pub fn into_boxed_slice(self) -> Option<Box<[u8]>> {\n        self.data\n    }\n\n    pub fn cancellation(&mut self) -> Cancellation {\n        Cancellation::from(self.data.take())\n    }\n}\n"
  },
  {
    "path": "src/drive/demo.rs",
    "content": "//! A demo driver for experimentation purposes\n\nuse std::future::Future;\nuse std::io;\nuse std::pin::Pin;\nuse std::sync::Once;\nuse std::task::{Poll, Context};\nuse std::thread;\n\nuse event_listener::*;\nuse futures_core::ready;\nuse once_cell::sync::Lazy;\nuse parking_lot::Mutex;\n\nconst ENTRIES: u32   = 32;\n\nuse super::{Drive, Completion};\n\nuse iou::*;\n\ntype Queues = (\n    Mutex<SubmissionQueue<'static>>,\n    Mutex<CompletionQueue<'static>>,\n    Registrar<'static>,\n    Event,\n);\n\nstatic QUEUES: Lazy<Queues> = Lazy::new(init);\n\n/// The driver handle\npub struct DemoDriver {\n    listener: Option<EventListener>,\n}\n\nimpl DemoDriver {\n    fn poll_submit_inner(&mut self, ctx: &mut Context<'_>, sq: &mut SubmissionQueue<'_>)\n        -> Poll<io::Result<u32>>\n    {\n        start_completion_thread();\n\n        if let Some(listener) = &mut self.listener {\n            ready!(Pin::new(listener).poll(ctx));\n        }\n\n        match sq.submit() {\n            Ok(n)       => Poll::Ready(Ok(n)),\n            Err(err)    => {\n                if err.raw_os_error().map_or(false, |code| code == libc::EBUSY) {\n                    self.listener = Some(QUEUES.3.listen());\n                    Poll::Pending\n                } else {\n                    Poll::Ready(Err(err))\n                }\n            }\n        }\n    }\n}\n\nimpl Default for DemoDriver {\n    fn default() -> Self {\n        driver()\n    }\n}\n\nimpl Clone for DemoDriver {\n    fn clone(&self) -> DemoDriver {\n        driver()\n    }\n}\n\nimpl Drive for DemoDriver {\n    fn poll_prepare<'cx>(\n        mut self: Pin<&mut Self>,\n        ctx: &mut Context<'cx>,\n        count: u32,\n        prepare: impl FnOnce(SQEs<'_>, &mut Context<'cx>) -> Completion<'cx>,\n    ) -> Poll<Completion<'cx>> {\n        let mut sq = QUEUES.0.lock();\n        loop {\n            match sq.prepare_sqes(count) {\n                Some(sqs)   => return Poll::Ready(prepare(sqs, ctx)),\n                None        => {\n                    let _ = ready!(self.poll_submit_inner(ctx, &mut *sq));\n                }\n            }\n        }\n    }\n\n    fn poll_submit(\n        mut self: Pin<&mut Self>,\n        ctx: &mut Context<'_>,\n    ) -> Poll<io::Result<u32>> {\n        self.poll_submit_inner(ctx, &mut *QUEUES.0.lock())\n    }\n}\n\n/// Construct a demo driver handle\npub fn driver() -> DemoDriver {\n    DemoDriver {\n        listener: None,\n    }\n}\n\n/// Access the registrar\n///\n/// This will return `None` if events have already been submitted to the driver. The Demo Driver\n/// currently only allows registering IO objects prior to submitting IO.\npub fn registrar() -> Option<&'static Registrar<'static>> {\n    if !STARTED_COMPLETION_THREAD.is_completed() {\n        Some(&QUEUES.2)\n    } else {\n        None\n    }\n\n}\n\nfn init() -> Queues {\n    let flags = SetupFlags::empty();\n    let features = SetupFeatures::NODROP;\n    let ring = Box::new(IoUring::new_with_flags(ENTRIES, flags, features).unwrap());\n    let ring = Box::leak(ring);\n    let (sq, cq, reg) = ring.queues();\n    (Mutex::new(sq), Mutex::new(cq), reg, Event::new())\n}\n\nstatic STARTED_COMPLETION_THREAD: Once = Once::new();\n\nfn start_completion_thread() {\n    STARTED_COMPLETION_THREAD.call_once(|| { thread::spawn(move || {\n        let mut cq = QUEUES.1.lock();\n        while let Ok(cqe) = cq.wait_for_cqe() {\n            let mut ready = cq.ready() as usize + 1;\n            QUEUES.3.notify_additional(ready);\n\n            super::complete(cqe);\n            ready -= 1;\n\n            while let Some(cqe) = cq.peek_for_cqe() {\n                if ready == 0 {\n                    ready = cq.ready() as usize + 1;\n                    QUEUES.3.notify_additional(ready);\n                }\n\n                super::complete(cqe);\n                ready -= 1;\n            }\n\n            debug_assert!(ready == 0);\n        }\n    }); });\n}\n"
  },
  {
    "path": "src/drive/mod.rs",
    "content": "//! Drive IO on io-uring\n\npub mod demo;\n\nuse std::io;\nuse std::marker::PhantomData;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse crate::ring;\nuse crate::{Submission, Event};\nuse iou::{SQE, SQEs};\n\npub use crate::ring::completion::complete;\n\n/// A completion which will be used to wake the task waiting on this event.\n///\n/// This type is opaque to users of ringbahn. It is constructed by the callback passed to\n/// [Drive::poll_prepare].\npub struct Completion<'cx> {\n    pub(crate) real: ring::Completion,\n    marker: PhantomData<fn(&'cx ()) -> &'cx ()>,\n}\n\nimpl<'cx> Completion<'cx> {\n    pub(crate) fn new(mut sqe: SQE<'_>, _sqes: SQEs<'_>, cx: &mut Context<'cx>) -> Completion<'cx> {\n        let real = ring::Completion::new(cx.waker().clone());\n        unsafe {\n            sqe.set_user_data(real.addr());\n        }\n\n        Completion { real, marker: PhantomData }\n    }\n}\n\n/// Implemented by drivers for io-uring.\n///\n/// The type that implements `Drive` is used to prepare and submit IO events to an io-uring\n/// instance. Paired with a piece of code which processes completions, it can run IO on top of\n/// io-uring.\npub trait Drive {\n    /// Prepare an event on the submission queue.\n    ///\n    /// The implementer is responsible for provisioning an [`iou::SQE`] from the\n    /// submission queue. Once an SQE is available, the implementer should pass it to the\n    /// `prepare` callback, which constructs a [`Completion`], and return that `Completion` to the\n    /// caller.\n    ///\n    /// If the driver is not ready to receive more events, it can return `Poll::Pending`. If it\n    /// does, it must register a waker to wake the task when more events can be prepared, otherwise\n    /// this method will not be called again. This allows the driver to implement backpressure.\n    ///\n    /// Drivers which call `prepare` but do not return the completion it gives are incorrectly\n    /// implemented. This will lead ringbahn to panic.\n    fn poll_prepare<'cx>(\n        self: Pin<&mut Self>,\n        ctx: &mut Context<'cx>,\n        count: u32,\n        prepare: impl FnOnce(SQEs<'_>, &mut Context<'cx>) -> Completion<'cx>,\n    ) -> Poll<Completion<'cx>>;\n\n    /// Suggest to submit all of the events on the submission queue.\n    ///\n    /// The implementer is responsible for determining how and when events are submitted to the\n    /// kernel to complete. It is valid for this function to do nothing at all; this function just\n    /// informs the driver that the user program is waiting for its prepared events to be\n    /// submitted and completed.\n    ///\n    /// If the implementation is not ready to submit, but wants to be called again to try later, it\n    /// can return `Poll::Pending`. If it does, it must register a waker to wake the task when it\n    /// would be appropriate to try submitting again.\n    ///\n    /// It is also valid not to submit an event but not to register a waker to try again, in which\n    /// case the appropriate response would be to return `Ok(0)`. This indicates to the caller that\n    /// the submission step is complete, whether or not actual IO was performed by the driver.\n    fn poll_submit(\n        self: Pin<&mut Self>,\n        ctx: &mut Context<'_>,\n    ) -> Poll<io::Result<u32>>;\n\n    fn submit<E: Event>(self, event: E) -> Submission<E, Self> where Self: Sized {\n        Submission::new(event, self)\n    }\n}\n"
  },
  {
    "path": "src/event/accept.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::sqe::{SockFlag, SockAddrStorage};\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct Accept<FD = RawFd> {\n    pub addr: Option<Box<SockAddrStorage>>,\n    pub fd: FD,\n    pub flags: SockFlag,\n}\n\nimpl<FD: UringFd + Copy> Event for Accept<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_accept(self.fd, self.addr.as_deref_mut(), self.flags);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).addr)\n    }\n}\n"
  },
  {
    "path": "src/event/close.rs",
    "content": "use std::os::unix::io::RawFd;\n\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs};\n\npub struct Close<FD = RawFd> {\n    pub fd: FD,\n}\n\nimpl<FD: UringFd + Copy> Event for Close<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_close(self.fd);\n        sqe\n    }\n}\n"
  },
  {
    "path": "src/event/connect.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::sqe::SockAddr;\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct Connect<FD = RawFd> {\n    pub fd: FD,\n    pub addr: Box<SockAddr>,\n}\n\nimpl<FD: UringFd + Copy> Event for Connect<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_connect(self.fd, &mut *self.addr);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).addr)\n    }\n}\n"
  },
  {
    "path": "src/event/epoll_ctl.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::sqe::{EpollOp, EpollEvent};\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct EpollCtl {\n    pub epoll_fd: RawFd,\n    pub op: EpollOp,\n    pub fd: RawFd,\n    pub event: Option<Box<EpollEvent>>,\n}\n\nimpl Event for EpollCtl {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_epoll_ctl(self.epoll_fd, self.op, self.fd, self.event.as_deref_mut());\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).event)\n    }\n}\n"
  },
  {
    "path": "src/event/fadvise.rs",
    "content": "use std::os::unix::io::RawFd;\n\nuse iou::sqe::PosixFadviseAdvice;\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs};\n\npub struct Fadvise<FD = RawFd> {\n    pub fd: FD,\n    pub offset: u64,\n    pub size: u64,\n    pub flags: PosixFadviseAdvice,\n}\n\nimpl<FD: UringFd + Copy> Event for Fadvise<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_fadvise(self.fd, self.offset, self.size, self.flags);\n        sqe\n    }\n}\n"
  },
  {
    "path": "src/event/fallocate.rs",
    "content": "use std::os::unix::io::RawFd;\n\nuse iou::registrar::UringFd;\nuse iou::sqe::FallocateFlags;\n\nuse super::{Event, SQE, SQEs};\n\npub struct Fallocate<FD = RawFd> {\n    pub fd: FD,\n    pub offset: u64,\n    pub size: u64,\n    pub flags: FallocateFlags,\n}\n\nimpl<FD: UringFd + Copy> Event for Fallocate<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_fallocate(self.fd, self.offset, self.size, self.flags);\n        sqe\n    }\n}\n"
  },
  {
    "path": "src/event/files_update.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct FilesUpdate {\n    pub files: Box<[RawFd]>,\n    pub offset: u32,\n}\n\nimpl Event for FilesUpdate {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_files_update(&self.files[..], self.offset);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).files)\n    }\n}\n"
  },
  {
    "path": "src/event/fsync.rs",
    "content": "use std::os::unix::io::RawFd;\n\nuse iou::registrar::UringFd;\nuse iou::sqe::FsyncFlags;\n\nuse super::{Event, SQE, SQEs};\n\npub struct Fsync<FD = RawFd> {\n    pub fd: FD,\n    pub flags: FsyncFlags,\n}\n\nimpl<FD: UringFd + Copy> Event for Fsync<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_fsync(self.fd, self.flags);\n        sqe\n    }\n}\n"
  },
  {
    "path": "src/event/mod.rs",
    "content": "//! Events that can be scheduled on io-uring with a [`Submission`](crate::Submission)\n\nmod accept;\nmod close;\nmod connect;\nmod epoll_ctl;\nmod fadvise;\nmod fallocate;\nmod files_update;\nmod fsync;\nmod openat;\nmod provide_buffers;\nmod read;\nmod readv;\nmod recv;\nmod send;\nmod splice;\nmod statx;\nmod timeout;\nmod write;\nmod writev;\n\nuse std::mem::ManuallyDrop;\n\nuse iou::{SQE, SQEs};\n\nuse crate::ring::Cancellation;\n\npub use accept::Accept;\npub use close::Close;\npub use connect::Connect;\npub use epoll_ctl::EpollCtl;\npub use fadvise::Fadvise;\npub use fallocate::Fallocate;\npub use files_update::FilesUpdate;\npub use fsync::Fsync;\npub use openat::OpenAt;\npub use provide_buffers::{ProvideBuffers, RemoveBuffers};\npub use read::{Read, ReadFixed};\npub use readv::ReadVectored;\npub use recv::Recv;\npub use send::Send;\npub use splice::Splice;\npub use statx::Statx;\npub use timeout::{Timeout, StaticTimeout};\npub use write::{Write, WriteFixed};\npub use writev::WriteVectored;\n\n/// An IO event that can be scheduled on an io-uring driver.\n///\n/// ## Safety\n///\n/// Event is a safe trait with two unsafe methods. It's important to understand that when\n/// implementing an unsafe method, the code author implementing that method is allowed to assume\n/// certain additional invariants will be upheld by all callers. It is the caller's responsibility\n/// to ensure those invariants are upheld, not the implementer. However, any unsafe operations\n/// performed inside of the method must be safe under those invariants and any other invariants the\n/// implementer has upheld. The implementer is not allowed to add any additional invariants that\n/// the caller must uphold that are not required by the trait.\npub trait Event {\n    fn sqes_needed(&self) -> u32;\n\n    /// Prepare an event to be submitted using the SQE argument.\n    ///\n    /// ## Safety\n    ///\n    /// When this method is called, these guarantees will be maintained by the caller:\n    ///\n    /// The data contained by this event will not be accessed again by this program until one of\n    /// two things happen:\n    /// - The event being prepared has been completed by the kernel, in which case ownership of\n    ///   this event will be passed back to users of this library.\n    /// - Interest in the event is cancelled, in which case `Event::cancel` will be called and the\n    ///   event's destructor will not run.\n    ///\n    /// In essence implementing prepare, users can write code ass if any heap addresses passed to\n    /// the  kernel have passed ownership of that data to the kernel for the time that the event is\n    /// completed.\n    unsafe fn prepare<'a>(&mut self, sqs: &mut SQEs<'a>) -> SQE<'a>;\n\n    /// Return the cancellation callback for this event.\n    ///\n    /// If this event is cancelled, this callback will be stored with the completion to be dropped\n    /// when the IO event completes. This way, any managed resources passed to the kernel (like\n    /// buffers) can be cleaned up once the kernel no longer needs them.\n    fn cancel(_: ManuallyDrop<Self>) -> Cancellation where Self: Sized {\n        Cancellation::from(())\n    }\n}\n"
  },
  {
    "path": "src/event/openat.rs",
    "content": "use std::ffi::CString;\nuse std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\nuse std::os::unix::ffi::OsStrExt;\nuse std::path::Path;\n\nuse iou::sqe::{Mode, OFlag};\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct OpenAt {\n    pub path: CString,\n    pub dir_fd: RawFd,\n    pub flags: OFlag,\n    pub mode: Mode,\n}\n\nimpl OpenAt {\n    pub fn without_dir(path: impl AsRef<Path>, flags: OFlag, mode: Mode) -> OpenAt {\n        let path = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();\n        OpenAt { path, dir_fd: libc::AT_FDCWD, flags, mode }\n    }\n}\n\nimpl Event for OpenAt {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_openat(self.dir_fd, &*self.path, self.flags, self.mode);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).path)\n    }\n}\n"
  },
  {
    "path": "src/event/provide_buffers.rs",
    "content": "use std::mem::ManuallyDrop;\nuse iou::sqe::BufferGroupId;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct ProvideBuffers {\n    pub bufs: Box<[u8]>,\n    pub count: u32,\n    pub group: BufferGroupId,\n    pub index: u32,\n}\n\nimpl Event for ProvideBuffers {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_provide_buffers(&mut self.bufs[..], self.count, self.group, self.index);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).bufs)\n    }\n}\n\npub struct RemoveBuffers {\n    pub count: u32,\n    pub group: BufferGroupId,\n}\n\nimpl Event for RemoveBuffers {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_remove_buffers(self.count, self.group);\n        sqe\n    }\n}\n"
  },
  {
    "path": "src/event/read.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::registrar::{UringFd, RegisteredBuf};\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\n/// A basic read event.\npub struct Read<FD = RawFd> {\n    pub fd: FD,\n    pub buf: Box<[u8]>,\n    pub offset: u64,\n}\n\nimpl<FD: UringFd + Copy> Event for Read<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_read(self.fd, &mut self.buf[..], self.offset);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).buf)\n    }\n}\n\npub struct ReadFixed<FD = RawFd> {\n    pub fd: FD,\n    pub buf: RegisteredBuf,\n    pub offset: u64,\n}\n\nimpl<FD: UringFd + Copy> Event for ReadFixed<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_read(self.fd, self.buf.as_mut(), self.offset);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).buf)\n    }\n}\n"
  },
  {
    "path": "src/event/readv.rs",
    "content": "use std::io::IoSliceMut; \nuse std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\n/// A `readv` event.\npub struct ReadVectored<FD = RawFd> {\n    pub fd: FD,\n    pub bufs: Box<[Box<[u8]>]>,\n    pub offset: u64,\n}\n\nimpl<FD> ReadVectored<FD> {\n    fn as_iovecs(buffers: &mut [Box<[u8]>]) -> &mut [IoSliceMut] {\n        // Unsafe contract:\n        // This pointer cast is defined behaviour because Box<[u8]> (wide pointer)\n        // is currently ABI compatible with libc::iovec.\n        //\n        // Then, libc::iovec is guaranteed ABI compatible with IoSliceMut on Unix:\n        // https://doc.rust-lang.org/beta/std/io/struct.IoSliceMut.html\n        //\n        // We are relying on the internals of Box<[u8]>, but this is such a\n        // foundational part of Rust it's unlikely the data layout would change\n        // without warning.\n        //\n        // Pointer cast expression adapted from the \"Turning a &mut T into an &mut U\"\n        // example of: https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives\n        unsafe { &mut *(buffers as *mut [Box<[u8]>] as *mut [IoSliceMut]) }\n    }\n}\n\n\nimpl<FD: UringFd + Copy> Event for ReadVectored<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_read_vectored(self.fd, Self::as_iovecs(&mut self.bufs[..]), self.offset);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).bufs)\n    }\n}\n"
  },
  {
    "path": "src/event/recv.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::sqe::MsgFlags;\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct Recv<FD = RawFd> {\n    pub fd: FD,\n    pub buf: Box<[u8]>,\n    pub flags: MsgFlags,\n}\n\nimpl<FD: UringFd + Copy> Event for Recv<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_recv(self.fd, &mut self.buf[..], self.flags);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).buf)\n    }\n}\n"
  },
  {
    "path": "src/event/send.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::sqe::MsgFlags;\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct Send<FD = RawFd> {\n    pub fd: FD,\n    pub buf: Box<[u8]>,\n    pub flags: MsgFlags,\n}\n\nimpl<FD: UringFd + Copy> Event for Send<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_send(self.fd, &self.buf[..], self.flags);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).buf)\n    }\n}\n"
  },
  {
    "path": "src/event/splice.rs",
    "content": "use std::os::unix::io::RawFd;\n\nuse iou::sqe::SpliceFlags;\n\nuse super::{Event, SQE, SQEs};\n\npub struct Splice {\n    pub fd_in: RawFd,\n    pub off_in: i64,\n    pub fd_out: RawFd,\n    pub off_out: i64,\n    pub bytes: u32,\n    pub flags: SpliceFlags,\n}\n\nimpl Event for Splice {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_splice(self.fd_in, self.off_in, self.fd_out, self.off_out, self.bytes, self.flags);\n        sqe\n    }\n}\n"
  },
  {
    "path": "src/event/statx.rs",
    "content": "use std::ffi::CString;\nuse std::mem::{self, ManuallyDrop};\nuse std::os::unix::io::RawFd;\nuse std::os::unix::ffi::OsStrExt;\nuse std::path::Path;\n\nuse iou::sqe::{StatxFlags, StatxMode};\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\npub struct Statx<FD = RawFd> {\n    pub dir_fd: FD,\n    pub path: CString,\n    pub flags: StatxFlags,\n    pub mask: StatxMode,\n    pub statx: Box<libc::statx>,\n}\n\nimpl Statx {\n    pub fn without_dir(path: impl AsRef<Path>, flags: StatxFlags, mask: StatxMode) -> Statx {\n        let path = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();\n        let statx = unsafe { Box::new(mem::zeroed()) };\n        Statx { path, dir_fd: libc::AT_FDCWD, flags, mask, statx }\n    }\n}\n\nimpl<FD: UringFd> Statx<FD> {\n    pub fn without_path(fd: FD, mut flags: StatxFlags, mask: StatxMode) -> Statx<FD> {\n        unsafe {\n            // TODO don't allocate? Use Cow? Use NULL?\n            let path = CString::new(\"\").unwrap();\n            let statx = Box::new(mem::zeroed());\n            flags.insert(StatxFlags::AT_EMPTY_PATH);\n            Statx { dir_fd: fd, path, flags, mask, statx }\n        }\n    }\n}\n\nimpl<FD: UringFd + Copy> Event for Statx<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_statx(self.dir_fd, self.path.as_c_str(), self.flags, self.mask, &mut *self.statx);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        let this = ManuallyDrop::into_inner(this);\n        Cancellation::from((this.statx, this.path))\n    }\n}\n"
  },
  {
    "path": "src/event/timeout.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::time::Duration;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\nuse iou::sqe::TimeoutFlags;\n\npub struct StaticTimeout {\n    ts: uring_sys::__kernel_timespec,\n    events: u32,\n    flags: TimeoutFlags,\n}\n\nimpl StaticTimeout {\n    pub const fn new(duration: Duration, events: u32, flags: TimeoutFlags) -> StaticTimeout {\n        StaticTimeout {\n            ts: timespec(duration),\n            events, flags,\n        }\n    }\n}\n\nimpl Event for &'static StaticTimeout {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_timeout(&self.ts, self.events, self.flags);\n        sqe\n    }\n}\n\npub struct Timeout {\n    ts: Box<uring_sys::__kernel_timespec>,\n    events: u32,\n    flags: TimeoutFlags,\n}\n\nimpl Timeout {\n    pub fn new(duration: Duration, events: u32, flags: TimeoutFlags) -> Timeout {\n        Timeout {\n            ts: Box::new(timespec(duration)),\n            events, flags,\n        }\n    }\n}\n\nimpl Event for Timeout {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_timeout(&*self.ts, self.events, self.flags);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).ts)\n    }\n}\n\nconst fn timespec(duration: Duration) -> uring_sys::__kernel_timespec {\n    uring_sys::__kernel_timespec {\n        tv_sec: duration.as_secs() as i64,\n        tv_nsec: duration.subsec_nanos() as _,\n    }\n}\n"
  },
  {
    "path": "src/event/write.rs",
    "content": "use std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::registrar::{UringFd, RegisteredBuf};\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\n/// A basic write event.\npub struct Write<FD = RawFd> {\n    pub fd: FD,\n    pub buf: Box<[u8]>,\n    pub offset: u64,\n}\n\nimpl<FD: UringFd + Copy> Event for Write<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_write(self.fd, &self.buf[..], self.offset);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).buf)\n    }\n}\n\npub struct WriteFixed<FD = RawFd> {\n    pub fd: FD,\n    pub buf: RegisteredBuf,\n    pub offset: u64,\n}\n\nimpl<FD: UringFd + Copy> Event for WriteFixed<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_write(self.fd, self.buf.as_ref(), self.offset);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).buf)\n    }\n}\n"
  },
  {
    "path": "src/event/writev.rs",
    "content": "use std::io::IoSlice; \nuse std::mem::ManuallyDrop;\nuse std::os::unix::io::RawFd;\n\nuse iou::registrar::UringFd;\n\nuse super::{Event, SQE, SQEs, Cancellation};\n\n/// A `writev` event.\npub struct WriteVectored<FD = RawFd> {\n    pub fd: FD,\n    pub bufs: Box<[Box<[u8]>]>,\n    pub offset: u64,\n}\n\nimpl<FD> WriteVectored<FD> {\n    fn iovecs(&self) -> &[IoSlice] {\n        unsafe { & *(&self.bufs[..] as *const [Box<[u8]>] as *const [IoSlice]) }\n    }\n}\n\nimpl<FD: UringFd + Copy> Event for WriteVectored<FD> {\n    fn sqes_needed(&self) -> u32 { 1 }\n\n    unsafe fn prepare<'sq>(&mut self, sqs: &mut SQEs<'sq>) -> SQE<'sq> {\n        let mut sqe = sqs.single().unwrap();\n        sqe.prep_write_vectored(self.fd, self.iovecs(), self.offset);\n        sqe\n    }\n\n    fn cancel(this: ManuallyDrop<Self>) -> Cancellation {\n        Cancellation::from(ManuallyDrop::into_inner(this).bufs)\n    }\n}\n"
  },
  {
    "path": "src/fs.rs",
    "content": "//! Interact with the file system using io-uring\n\nuse std::fs;\nuse std::future::Future;\nuse std::io;\nuse std::mem::{self, ManuallyDrop};\nuse std::os::unix::io::{AsRawFd, FromRawFd, RawFd};\nuse std::path::Path;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse either::Either;\nuse futures_core::ready;\nuse futures_io::{AsyncRead, AsyncBufRead, AsyncWrite, AsyncSeek};\nuse iou::sqe::{OFlag, Mode};\n\nuse crate::buf::Buffer;\nuse crate::drive::Drive;\nuse crate::drive::demo::DemoDriver;\nuse crate::ring::{Ring, Cancellation};\nuse crate::event::OpenAt;\nuse crate::Submission;\n\ntype FileBuf = Either<Buffer, Box<libc::statx>>;\n\n/// A file handle that runs on io-uring\npub struct File<D: Drive = DemoDriver> {\n    ring: Ring<D>,\n    fd: RawFd,\n    active: Op,\n    buf: FileBuf,\n    pos: u64,\n}\n\n#[derive(Copy, Clone, Debug, Eq, PartialEq)]\nenum Op {\n    Read,\n    Write,\n    Close,\n    Nothing,\n    Statx,\n    Closed,\n}\n\nimpl File {\n    /// Open a file using the default driver\n    pub fn open(path: impl AsRef<Path>) -> Open {\n        File::open_on_driver(path, DemoDriver::default())\n    }\n\n    /// Create a new file using the default driver\n    pub fn create(path: impl AsRef<Path>) -> Create {\n        File::create_on_driver(path, DemoDriver::default())\n    }\n}\n\nimpl<D: Drive + Clone> File<D> {\n    /// Open a file\n    pub fn open_on_driver(path: impl AsRef<Path>, driver: D) -> Open<D> {\n        let flags = OFlag::O_CLOEXEC | OFlag::O_RDONLY;\n        Open(driver.submit(OpenAt::without_dir(path, flags, Mode::from_bits(0o666).unwrap())))\n    }\n\n    /// Create a file\n    pub fn create_on_driver(path: impl AsRef<Path>, driver: D) -> Create<D> {\n        let flags = OFlag::O_CLOEXEC | OFlag::O_WRONLY | OFlag::O_CREAT | OFlag::O_TRUNC;\n        Create(driver.submit(OpenAt::without_dir(path, flags, Mode::from_bits(0o666).unwrap())))\n    }\n}\n\nimpl<D: Drive> File<D> {\n    /// Take an existing file and run its IO on an io-uring driver\n    pub fn run_on_driver(file: fs::File, driver: D) -> File<D> {\n        let file = ManuallyDrop::new(file);\n        File::from_fd(file.as_raw_fd(), driver)\n    }\n\n    fn from_fd(fd: RawFd, driver: D) -> File<D> {\n        File {\n            ring: Ring::new(driver),\n            active: Op::Nothing,\n            buf: Either::Left(Buffer::default()),\n            pos: 0,\n            fd,\n        }\n    }\n\n    /// Access any data that has been read into the buffer, but not consumed\n    ///\n    /// This is similar to the fill_buf method from AsyncBufRead, but instead of performing IO if\n    /// the buffer is empty, it will just return an empty slice. This method can be used to copy\n    /// out any left over buffered data before closing or performing a write.\n    pub fn read_buffered(&self) -> &[u8] {\n        if self.active == Op::Read {\n            self.buf.as_ref().unwrap_left().buffered_from_read()\n        } else { &[] }\n    }\n\n    fn guard_op(self: Pin<&mut Self>, op: Op) {\n        let (ring, buf, .., active) = self.split();\n        if *active == Op::Closed {\n            panic!(\"Attempted to perform IO on a closed File\");\n        } else if *active != Op::Nothing && *active != op {\n            let new_buf = Either::Left(Buffer::default());\n            ring.cancel_pinned(Cancellation::from(mem::replace(buf, new_buf)));\n        }\n        *active = op;\n    }\n\n    fn cancel(&mut self) {\n        self.active = Op::Nothing;\n        let new_buf = Either::Left(Buffer::default());\n        self.ring.cancel(Cancellation::from(mem::replace(&mut self.buf, new_buf)));\n    }\n\n    fn poll_file_size(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<u64>> {\n        static EMPTY: libc::c_char = 0;\n        use std::ffi::CStr;\n\n        self.as_mut().guard_op(Op::Statx);\n        let fd = self.fd;\n        let (ring, statx, ..) = self.split_with_statx();\n        let flags = iou::sqe::StatxFlags::AT_EMPTY_PATH;\n        let mask = iou::sqe::StatxMode::STATX_SIZE;\n        ready!(ring.poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_statx(fd, CStr::from_ptr(&EMPTY), flags, mask, statx);\n            }\n            sqe\n        }))?;\n        Poll::Ready(Ok((*statx).stx_size))\n    }\n\n    #[inline(always)]\n    fn split(self: Pin<&mut Self>) -> (Pin<&mut Ring<D>>, &mut FileBuf, &mut u64, &mut Op) {\n        unsafe {\n            let this = Pin::get_unchecked_mut(self);\n            (Pin::new_unchecked(&mut this.ring), &mut this.buf, &mut this.pos, &mut this.active)\n        }\n    }\n\n    #[inline(always)]\n    fn split_with_buf(self: Pin<&mut Self>)\n        -> (Pin<&mut Ring<D>>, &mut Buffer, &mut u64, &mut Op)\n    {\n        let (ring, buf, pos, active) = self.split();\n        let buf = buf.as_mut().unwrap_left();\n        (ring, buf, pos, active)\n    }\n\n    #[inline(always)]\n    fn split_with_statx(self: Pin<&mut Self>)\n        -> (Pin<&mut Ring<D>>, &mut libc::statx, &mut u64, &mut Op)\n    {\n        let (ring, buf, pos, active) = self.split();\n        if buf.is_left() {\n            *buf = Either::Right(Box::new(unsafe { mem::zeroed() }));\n        }\n        let statx = buf.as_mut().unwrap_right();\n        (ring, statx, pos, active)\n    }\n\n    #[inline(always)]\n    fn ring(self: Pin<&mut Self>) -> Pin<&mut Ring<D>> {\n        self.split().0\n    }\n\n    #[inline(always)]\n    fn buf(self: Pin<&mut Self>) -> &mut Buffer {\n        self.split_with_buf().1\n    }\n\n    #[inline(always)]\n    fn pos(self: Pin<&mut Self>) -> &mut u64 {\n        self.split().2\n    }\n\n    fn confirm_close(self: Pin<&mut Self>) {\n        *self.split().3 = Op::Closed;\n    }\n}\n\nimpl<D: Drive> AsyncRead for File<D> {\n    fn poll_read(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8])\n        -> Poll<io::Result<usize>>\n    {\n        let mut inner = ready!(self.as_mut().poll_fill_buf(ctx))?;\n        let len = io::Read::read(&mut inner, buf)?;\n        self.consume(len);\n        Poll::Ready(Ok(len))\n    }\n}\n\nimpl<D: Drive> AsyncBufRead for File<D> {\n    fn poll_fill_buf(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {\n        self.as_mut().guard_op(Op::Read);\n        let fd = self.fd;\n        let (ring, buf, pos, ..) = self.split_with_buf();\n        buf.fill_buf(|buf| {\n            let n = ready!(ring.poll(ctx, 1, |sqs| {\n                let mut sqe = sqs.single().unwrap();\n                unsafe {\n                    sqe.prep_read(fd, buf, *pos);\n                }\n                sqe\n            }))?;\n            *pos += n as u64;\n            Poll::Ready(Ok(n as u32))\n        })\n    }\n\n    fn consume(self: Pin<&mut Self>, amt: usize) {\n        self.buf().consume(amt);\n    }\n}\n\nimpl<D: Drive> AsyncWrite for File<D> {\n    fn poll_write(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, slice: &[u8]) -> Poll<io::Result<usize>> {\n        self.as_mut().guard_op(Op::Write);\n        let fd = self.fd;\n        let (ring, buf, pos, ..) = self.split_with_buf();\n        let data = ready!(buf.fill_buf(|mut buf| {\n            Poll::Ready(Ok(io::Write::write(&mut buf, slice)? as u32))\n        }))?;\n        let n = ready!(ring.poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_write(fd, data, *pos);\n            }\n            sqe\n        }))?;\n        *pos += n as u64;\n        buf.clear();\n        Poll::Ready(Ok(n as usize))\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        ready!(self.poll_write(ctx, &[]))?;\n        Poll::Ready(Ok(()))\n    }\n\n    fn poll_close(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.as_mut().guard_op(Op::Close);\n        let fd = self.fd;\n        ready!(self.as_mut().ring().poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_close(fd);\n            }\n            sqe\n        }))?;\n        self.confirm_close();\n        Poll::Ready(Ok(()))\n    }\n}\n\nimpl<D: Drive> AsyncSeek for File<D> {\n    fn poll_seek(mut self: Pin<&mut Self>, ctx: &mut Context, pos: io::SeekFrom)\n        -> Poll<io::Result<u64>>\n    {\n        let (whence, offset) = match pos {\n            io::SeekFrom::Start(n) => {\n                *self.as_mut().pos() = n;\n                return Poll::Ready(Ok(self.pos));\n            }\n            io::SeekFrom::Current(n) => (self.pos, n),\n            io::SeekFrom::End(n)     => {\n                (ready!(self.as_mut().poll_file_size(ctx))?, n)\n            }\n        };\n        let valid_seek = if offset.is_negative() {\n            match whence.checked_sub(offset.abs() as u64) {\n                Some(valid_seek) => valid_seek,\n                None => {\n                    let invalid = io::Error::from(io::ErrorKind::InvalidInput);\n                    return Poll::Ready(Err(invalid));\n                }\n            }\n        } else {\n            match whence.checked_add(offset as u64) {\n                Some(valid_seek) => valid_seek,\n                None => {\n                    let overflow = io::Error::from_raw_os_error(libc::EOVERFLOW);\n                    return Poll::Ready(Err(overflow));\n                }\n            }\n        };\n        *self.as_mut().pos() = valid_seek;\n        Poll::Ready(Ok(self.pos))\n    }\n}\n\nimpl From<fs::File> for File {\n    fn from(file: fs::File) -> File {\n        File::run_on_driver(file, DemoDriver::default())\n    }\n}\n\nimpl<D: Drive> From<File<D>> for fs::File {\n    fn from(mut file: File<D>) -> fs::File {\n        file.cancel();\n        let file = ManuallyDrop::new(file);\n        unsafe {\n            fs::File::from_raw_fd(file.fd)\n        }\n    }\n}\n\nimpl<D: Drive> Drop for File<D> {\n    fn drop(&mut self) {\n        match self.active {\n            Op::Closed  => { }\n            Op::Nothing => unsafe { libc::close(self.fd); },\n            _           => self.cancel(),\n        }\n    }\n}\n\n/// A future representing an opening file.\npub struct Open<D: Drive = DemoDriver>(Submission<OpenAt, D>);\n\nimpl<D: Drive> Open<D> {\n    fn inner(self: Pin<&mut Self>) -> Pin<&mut Submission<OpenAt, D>> {\n        unsafe { Pin::map_unchecked_mut(self, |this| &mut this.0) }\n    }\n}\n\nimpl<D: Drive + Clone> Future for Open<D> {\n    type Output = io::Result<File<D>>;\n\n    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<File<D>>> {\n        let mut inner = self.inner();\n        let (_, result) = ready!(inner.as_mut().poll(ctx));\n        let fd = result? as i32;\n        let driver = inner.driver().clone();\n        Poll::Ready(Ok(File::from_fd(fd, driver)))\n    }\n}\n\n/// A future representing a file being created.\npub struct Create<D: Drive = DemoDriver>(Submission<OpenAt, D>);\n\nimpl<D: Drive> Create<D> {\n    fn inner(self: Pin<&mut Self>) -> Pin<&mut Submission<OpenAt, D>> {\n        unsafe { Pin::map_unchecked_mut(self, |this| &mut this.0) }\n    }\n}\n\nimpl<D: Drive + Clone> Future for Create<D> {\n    type Output = io::Result<File<D>>;\n\n    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<File<D>>> {\n        let mut inner = self.inner();\n        let (_, result) = ready!(inner.as_mut().poll(ctx));\n        let fd = result? as i32;\n        let driver = inner.driver().clone();\n        Poll::Ready(Ok(File::from_fd(fd, driver)))\n    }\n}\n"
  },
  {
    "path": "src/io.rs",
    "content": "use std::borrow::Cow;\nuse std::future::Future;\nuse std::io;\nuse std::os::unix::io::{AsRawFd, RawFd};\nuse std::pin::Pin;\nuse std::task::{Poll, Context};\n\nuse futures_core::ready;\nuse futures_io::AsyncWrite;\n\nuse crate::buf::Buffer;\nuse crate::{Drive, ring::Ring};\nuse crate::drive::demo::DemoDriver;\n\n#[macro_export]\nmacro_rules! print {\n    ($driver:expr, $($arg:tt)*) => {{\n        let mut s = format!($($arg)*);\n        $crate::io::__print($driver, s.into_bytes())\n    }};\n}\n\n#[macro_export]\nmacro_rules! println {\n    ($driver:expr) => {$crate::io::__print($driver, b\"\\n\")};\n    ($driver:expr, $($arg:tt)*) => {{\n        let mut s = format!($($arg)*);\n        s.push('\\n');\n        $crate::io::__print($driver, s.into_bytes())\n    }};\n}\n\n#[macro_export]\nmacro_rules! eprint {\n    ($driver:expr, $($arg:tt)*) => {{\n        let mut s = format!($($arg)*);\n        $crate::io::__eprint($driver, s.into_bytes())\n    }};\n}\n\n#[macro_export]\nmacro_rules! eprintln {\n    ($driver:expr) => {$crate::io::__eprint($driver, b\"\\n\")};\n    ($driver:expr, $($arg:tt)*) => {{\n        let mut s = format!($($arg)*);\n        s.push('\\n');\n        $crate::io::__eprint($driver, s.into_bytes())\n    }};\n}\n\n#[doc(hidden)]\npub async fn __print<D: Drive>(driver: D, bytes: impl Into<Cow<'static, [u8]>>) {\n    Print {\n        ring: Ring::new(driver),\n        fd: 1,\n        bytes: bytes.into(),\n        idx: 0,\n    }.await.expect(\"printing to stdout failed\")\n}\n\n#[doc(hidden)]\npub async fn __eprint<D: Drive>(driver: D, bytes: impl Into<Cow<'static, [u8]>>) {\n    Print {\n        ring: Ring::new(driver),\n        fd: 2,\n        bytes: bytes.into(),\n        idx: 0,\n    }.await.expect(\"printing to stderr failed\")\n}\n\nstruct Print<D: Drive> {\n    ring: Ring<D>,\n    fd: RawFd,\n    bytes: Cow<'static, [u8]>,\n    idx: usize,\n}\n\nimpl<D: Drive> Print<D> {\n    fn split(self: Pin<&mut Self>) -> (Pin<&mut Ring<D>>, RawFd, &[u8], &mut usize) {\n        unsafe {\n            let this = Pin::get_unchecked_mut(self);\n            let bytes = &this.bytes.as_ref()[this.idx..];\n            (Pin::new_unchecked(&mut this.ring), this.fd, bytes, &mut this.idx)\n        }\n    }\n}\n\nimpl<D: Drive> Future for Print<D> {\n    type Output = io::Result<()>;\n\n    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {\n        let (mut ring, fd, mut bytes, idx) = self.split();\n        if !bytes.is_empty() {\n            loop {\n                let written = ready!(ring.as_mut().poll(ctx, 1, |sqs| unsafe {\n                    let mut sqe = sqs.single().unwrap();\n                    sqe.prep_write(fd, bytes, 0);\n                    sqe\n                }))? as usize;\n                *idx += written;\n                if written == bytes.len() {\n                    return Poll::Ready(Ok(()));\n                } else {\n                    bytes = &bytes[written..];\n                }\n            }\n        } else {\n            return Poll::Ready(Ok(()));\n        }\n    }\n}\n\n/// A handle to the standard output of the current process.\npub struct Stdout<D: Drive> {\n    ring: Ring<D>,\n    buf: Buffer,\n}\n\n/// Constructs a new `stdout` handle run on the demo driver.\n/// ```no_run\n/// use ringbahn::io;\n///\n/// # use futures::AsyncWriteExt;\n/// # fn main() -> std::io::Result<()> { futures::executor::block_on(async {\n/// io::stdout().write(b\"hello, world\").await?;\n/// # Ok(())\n/// # })\n/// # }\n/// ```\n// TODO synchronization note?\npub fn stdout() -> Stdout<DemoDriver> {\n    stdout_on_driver(DemoDriver::default())\n}\n\n/// Constructs a new `stdout` handle run on the provided driver.\npub fn stdout_on_driver<D: Drive>(driver: D) -> Stdout<D> {\n    Stdout {\n        ring: Ring::new(driver),\n        buf: Buffer::default(),\n    }\n}\n\nimpl<D: Drive> Stdout<D> {\n    #[inline(always)]\n    fn split(self: Pin<&mut Self>) -> (Pin<&mut Ring<D>>, &mut Buffer) {\n        unsafe {\n            let this = Pin::get_unchecked_mut(self);\n            (Pin::new_unchecked(&mut this.ring), &mut this.buf)\n        }\n    }\n}\n\nimpl<D: Drive> AsyncWrite for Stdout<D> {\n    fn poll_write(self: Pin<&mut Self>, ctx: &mut Context<'_>, slice: &[u8])\n        -> Poll<io::Result<usize>>\n    {\n        let fd = self.as_raw_fd();\n        let (ring, buf, ..) = self.split();\n        let data = ready!(buf.fill_buf(|mut buf| {\n            Poll::Ready(Ok(io::Write::write(&mut buf, slice)? as u32))\n        }))?;\n        let n = ready!(ring.poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_write(fd, data, 0);\n            }\n            sqe\n        }))?;\n        buf.clear();\n        Poll::Ready(Ok(n as usize))\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        ready!(self.poll_write(ctx, &[]))?;\n        Poll::Ready(Ok(()))\n    }\n\n    fn poll_close(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.poll_flush(ctx)\n    }\n}\n\nimpl<D: Drive> AsRawFd for Stdout<D> {\n    fn as_raw_fd(&self) -> RawFd {\n        libc::STDOUT_FILENO\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "pub mod fs;\npub mod net;\npub mod unix;\n\npub mod drive;\npub mod event;\npub mod ring;\n\npub mod io;\n\nmod buf;\nmod submission;\n\npub use submission::Submission;\n\n#[doc(inline)]\npub use drive::Drive;\n#[doc(inline)]\npub use event::Event;\n"
  },
  {
    "path": "src/net/listener.rs",
    "content": "use std::io;\nuse std::future::Future;\nuse std::net::{ToSocketAddrs, SocketAddr};\nuse std::os::unix::io::{RawFd};\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_core::{ready, Stream};\nuse iou::sqe::SockAddrStorage;\nuse nix::sys::socket::{self as nix_socket, SockProtocol, SockFlag};\n\nuse crate::drive::{Drive, demo::DemoDriver};\nuse crate::ring::{Cancellation, Ring};\n\nuse super::TcpStream;\n\npub struct TcpListener<D: Drive = DemoDriver> {\n    ring: Ring<D>,\n    fd: RawFd,\n    active: Op,\n    addr: Option<Box<iou::sqe::SockAddrStorage>>,\n}\n\n#[derive(Eq, PartialEq, Copy, Clone, Debug)]\nenum Op {\n    Nothing = 0,\n    Accept,\n    Close,\n    Closed,\n}\n\nimpl TcpListener {\n    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {\n        TcpListener::bind_on_driver(addr, DemoDriver::default())\n    }\n}\n\nimpl<D: Drive> TcpListener<D> {\n    pub fn bind_on_driver<A: ToSocketAddrs>(addr: A, driver: D) -> io::Result<TcpListener<D>> {\n        let (fd, addr) = super::socket(addr, SockProtocol::Tcp)?;\n        let addr = iou::sqe::SockAddr::Inet(nix_socket::InetAddr::from_std(&addr));\n        nix_socket::setsockopt(fd, nix_socket::sockopt::ReuseAddr, &true)\n            .map_err(|e| e.as_errno().unwrap_or(nix::errno::Errno::EIO))?;\n        nix_socket::bind(fd, &addr).map_err(|e| e.as_errno().unwrap_or(nix::errno::Errno::EIO))?;\n        nix_socket::listen(fd, 128).map_err(|e| e.as_errno().unwrap_or(nix::errno::Errno::EIO))?;\n        let ring = Ring::new(driver);\n        Ok(TcpListener {\n            active: Op::Nothing,\n            addr: None,\n            fd, ring,\n        })\n    }\n\n    pub fn close(&mut self) -> Close<D> where D: Unpin {\n        Pin::new(self).close_pinned()\n    }\n\n    pub fn close_pinned(self: Pin<&mut Self>) -> Close<D> {\n        Close { socket: self }\n    }\n\n    fn guard_op(self: Pin<&mut Self>, op: Op) {\n        let (ring, addr, active) = self.split();\n        if *active == Op::Closed {\n            panic!(\"Attempted to perform IO on a closed TcpListener\");\n        } else if *active != Op::Nothing && *active != op {\n            ring.cancel_pinned(Cancellation::from(addr.take()));\n        }\n        *active = op;\n    }\n\n    fn cancel(&mut self) {\n        let cancellation = match self.active {\n            Op::Accept  => Cancellation::from(self.addr.take()),\n            Op::Close   => Cancellation::from(()),\n            Op::Closed  => return,\n            Op::Nothing => return,\n        };\n        self.active = Op::Nothing;\n        self.ring.cancel(cancellation);\n    }\n\n    fn drop_addr(self: Pin<&mut Self>) {\n        self.split().1.take();\n    }\n\n    fn ring(self: Pin<&mut Self>) -> Pin<&mut Ring<D>> {\n        self.split().0\n    }\n\n    fn split(self: Pin<&mut Self>) \n        -> (Pin<&mut Ring<D>>, &mut Option<Box<SockAddrStorage>>, &mut Op)\n    {\n        unsafe {\n            let this = Pin::get_unchecked_mut(self);\n            (Pin::new_unchecked(&mut this.ring), &mut this.addr, &mut this.active)\n        }\n    }\n\n    fn split_with_addr(self: Pin<&mut Self>)\n        -> (Pin<&mut Ring<D>>, &mut SockAddrStorage, &mut Op)\n    {\n        let (ring, addr, active) = self.split();\n        if addr.is_none() {\n            *addr = Some(Box::new(SockAddrStorage::uninit()));\n        }\n        (ring, &mut **addr.as_mut().unwrap(), active)\n    }\n\n    fn confirm_close(self: Pin<&mut Self>) {\n        *self.split().2 = Op::Closed;\n    }\n}\n\nimpl<D: Drive + Clone> TcpListener<D> {\n    pub fn accept(&mut self) -> Accept<'_, D> where D: Unpin {\n        Pin::new(self).accept_pinned()\n    }\n\n    pub fn accept_pinned(self: Pin<&mut Self>) -> Accept<'_, D> {\n        Accept { socket: self }\n    }\n\n    pub fn incoming(&mut self) -> Incoming<'_, D> where D: Unpin {\n        Pin::new(self).incoming_pinned()\n    }\n\n    pub fn incoming_pinned(self: Pin<&mut Self>) -> Incoming<'_, D> {\n        Incoming { accept: self.accept_pinned() }\n    }\n\n    pub fn accept_no_addr(&mut self) -> AcceptNoAddr<'_, D> where D: Unpin {\n        Pin::new(self).accept_no_addr_pinned()\n    }\n\n    pub fn accept_no_addr_pinned(self: Pin<&mut Self>) -> AcceptNoAddr<'_, D> {\n        AcceptNoAddr { socket: self }\n    }\n\n    pub fn incoming_no_addr(&mut self) -> IncomingNoAddr<'_, D> where D: Unpin {\n        Pin::new(self).incoming_no_addr_pinned()\n    }\n\n    pub fn incoming_no_addr_pinned(self: Pin<&mut Self>) -> IncomingNoAddr<'_, D> {\n        IncomingNoAddr { accept: self.accept_no_addr_pinned() }\n    }\n\n    pub fn poll_accept(mut self: Pin<&mut Self>, ctx: &mut Context<'_>)\n        -> Poll<io::Result<(TcpStream<D>, SocketAddr)>>\n    {\n        self.as_mut().guard_op(Op::Accept);\n        let fd = self.fd;\n        let (ring, addr, ..) = self.as_mut().split_with_addr();\n        let fd = ready!(ring.poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_accept(fd, Some(addr), SockFlag::empty());\n            }\n            sqe\n        }))? as RawFd;\n        let addr = {\n            let result = unsafe { addr.as_socket_addr() };\n            self.as_mut().drop_addr();\n            match result? {\n                iou::sqe::SockAddr::Inet(addr) => addr.to_std(),\n                addr => panic!(\"TcpListener addr cannot be {:?}\", addr.family()),\n            }\n        };\n\n        Poll::Ready(Ok((TcpStream::from_fd(fd, self.ring().clone()), addr)))\n    }\n\n    pub fn poll_accept_no_addr(mut self: Pin<&mut Self>, ctx: &mut Context<'_>)\n        -> Poll<io::Result<TcpStream<D>>>\n    {\n        self.as_mut().guard_op(Op::Accept);\n        let fd = self.fd;\n        let fd = ready!(self.as_mut().ring().poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_accept(fd, None, SockFlag::empty());\n            }\n            sqe\n        }))? as RawFd;\n        Poll::Ready(Ok(TcpStream::from_fd(fd, self.ring().clone())))\n    }\n}\n\nimpl<D: Drive> Drop for TcpListener<D> {\n    fn drop(&mut self) {\n        match self.active {\n            Op::Closed  => { }\n            Op::Nothing => unsafe { libc::close(self.fd); }\n            _           => self.cancel(),\n        }\n    }\n}\n\npub struct Accept<'a, D: Drive> {\n    socket: Pin<&'a mut TcpListener<D>>,\n}\n\nimpl<'a, D: Drive + Clone> Future for Accept<'a, D> {\n    type Output = io::Result<(TcpStream<D>, SocketAddr)>;\n\n    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.socket.as_mut().poll_accept(ctx)\n    }\n}\n\npub struct AcceptNoAddr<'a, D: Drive> {\n    socket: Pin<&'a mut TcpListener<D>>,\n}\n\nimpl<'a, D: Drive + Clone> Future for AcceptNoAddr<'a, D> {\n    type Output = io::Result<TcpStream<D>>;\n\n    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.socket.as_mut().poll_accept_no_addr(ctx)\n    }\n}\n\npub struct Incoming<'a, D: Drive> {\n    accept: Accept<'a, D>,\n}\n\nimpl<'a, D: Drive> Incoming<'a, D> {\n    fn inner(self: Pin<&mut Self>) -> Pin<&mut Accept<'a, D>> {\n        unsafe { Pin::map_unchecked_mut(self, |this| &mut this.accept) }\n    }\n}\n\nimpl<'a, D: Drive + Clone> Stream for Incoming<'a, D> {\n    type Item = io::Result<(TcpStream<D>, SocketAddr)>;\n\n    fn poll_next(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let next = ready!(self.inner().poll(ctx));\n        Poll::Ready(Some(next))\n    }\n}\n\npub struct IncomingNoAddr<'a, D: Drive> {\n    accept: AcceptNoAddr<'a, D>,\n}\n\nimpl<'a, D: Drive> IncomingNoAddr<'a, D> {\n    fn inner(self: Pin<&mut Self>) -> Pin<&mut AcceptNoAddr<'a, D>> {\n        unsafe { Pin::map_unchecked_mut(self, |this| &mut this.accept) }\n    }\n}\n\nimpl<'a, D: Drive + Clone> Stream for IncomingNoAddr<'a, D> {\n    type Item = io::Result<TcpStream<D>>;\n\n    fn poll_next(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let next = ready!(self.inner().poll(ctx));\n        Poll::Ready(Some(next))\n    }\n}\n\npub struct Close<'a, D: Drive> {\n    socket: Pin<&'a mut TcpListener<D>>,\n}\n\nimpl<'a, D: Drive> Future for Close<'a, D> {\n    type Output = io::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.socket.as_mut().guard_op(Op::Close);\n        let fd = self.socket.fd;\n        ready!(self.socket.as_mut().ring().poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_close(fd);\n            }\n            sqe\n        }))?;\n        self.socket.as_mut().confirm_close();\n        Poll::Ready(Ok(()))\n    }\n}\n"
  },
  {
    "path": "src/net/mod.rs",
    "content": "mod listener;\nmod stream;\n\nuse std::io;\nuse std::net::{SocketAddr, ToSocketAddrs};\nuse std::os::unix::io::RawFd;\n\npub use listener::{TcpListener, Accept, AcceptNoAddr, Close, Incoming, IncomingNoAddr};\npub use stream::{TcpStream, Connect};\n\nuse nix::sys::socket as nix;\n\nfn socket<A: ToSocketAddrs>(addr: A, protocol: nix::SockProtocol) -> io::Result<(RawFd, SocketAddr)> {\n    use io::{Error, ErrorKind};\n\n    let mut error = Error::new(ErrorKind::InvalidInput, \"could not resolve to any addresses\");\n\n    for addr in addr.to_socket_addrs()? {\n        let domain = match addr.is_ipv6() {\n            true    => nix::AddressFamily::Inet6,\n            false   => nix::AddressFamily::Inet,\n        };\n\n        let flags = nix::SockFlag::SOCK_CLOEXEC;\n\n        match nix::socket(domain, nix::SockType::Stream, flags, Some(protocol)) {\n            Ok(fd)          => return Ok((fd, addr)),\n            _               => error = io::Error::last_os_error(),\n        }\n    }\n\n    Err(error)\n}\n"
  },
  {
    "path": "src/net/stream.rs",
    "content": "use std::io;\nuse std::future::Future;\nuse std::net::ToSocketAddrs;\nuse std::os::unix::io::RawFd;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_core::ready;\nuse futures_io::{AsyncRead, AsyncBufRead, AsyncWrite};\nuse iou::sqe::SockAddr;\nuse nix::sys::socket::SockProtocol;\n\nuse crate::buf::Buffer;\nuse crate::drive::{Drive, demo::DemoDriver};\nuse crate::ring::Ring;\nuse crate::event;\nuse crate::Submission;\n\nuse super::socket;\n\npub struct TcpStream<D: Drive = DemoDriver> {\n    ring: Ring<D>,\n    buf: Buffer,\n    active: Op,\n    fd: RawFd,\n}\n\n#[derive(Copy, Clone, Debug, Eq, PartialEq)]\nenum Op {\n    Read,\n    Write,\n    Close,\n    Nothing,\n    Closed,\n}\n\nimpl TcpStream {\n    pub fn connect<A: ToSocketAddrs>(addr: A) -> Connect {\n        TcpStream::connect_on_driver(addr, DemoDriver::default())\n    }\n}\n\nimpl<D: Drive + Clone> TcpStream<D> {\n    pub fn connect_on_driver<A: ToSocketAddrs>(addr: A, driver: D) -> Connect<D> {\n        let (fd, addr) = match socket(addr, SockProtocol::Tcp) {\n            Ok(fd)  => fd,\n            Err(e)  => return Connect(Err(Some(e))),\n        };\n        let addr = Box::new(SockAddr::Inet(nix::sys::socket::InetAddr::from_std(&addr)));\n        Connect(Ok(driver.submit(event::Connect { fd, addr })))\n    }\n}\n\nimpl<D: Drive> TcpStream<D> {\n    pub(crate) fn from_fd(fd: RawFd, ring: Ring<D>) -> TcpStream<D> {\n        TcpStream {\n            buf: Buffer::default(),\n            active: Op::Nothing,\n            fd, ring,\n        }\n    }\n\n    fn guard_op(self: Pin<&mut Self>, op: Op) {\n        let (ring, buf, active) = self.split();\n        if *active == Op::Closed {\n            panic!(\"Attempted to perform IO on a closed stream\");\n        } else if *active != Op::Nothing && *active != op {\n            ring.cancel_pinned(buf.cancellation());\n        }\n        *active = op;\n    }\n\n    fn cancel(&mut self) {\n        self.active = Op::Nothing;\n        self.ring.cancel(self.buf.cancellation());\n    }\n\n    #[inline(always)]\n    fn ring(self: Pin<&mut Self>) -> Pin<&mut Ring<D>> {\n        self.split().0\n    }\n\n    #[inline(always)]\n    fn buf(self: Pin<&mut Self>) -> &mut Buffer {\n        self.split().1\n    }\n\n    #[inline(always)]\n    fn split(self: Pin<&mut Self>) -> (Pin<&mut Ring<D>>, &mut Buffer, &mut Op) {\n        unsafe {\n            let this = Pin::get_unchecked_mut(self);\n            (Pin::new_unchecked(&mut this.ring), &mut this.buf, &mut this.active)\n        }\n    }\n\n    fn confirm_close(self: Pin<&mut Self>) {\n        *self.split().2 = Op::Closed;\n    }\n}\n\npub struct Connect<D: Drive = DemoDriver>(\n    Result<Submission<event::Connect, D>, Option<io::Error>>\n);\n\nimpl<D: Drive + Clone> Future for Connect<D> {\n    type Output = io::Result<TcpStream<D>>;\n\n    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {\n        match self.project() {\n            Ok(mut submission)  => {\n                let (connect, result) = ready!(submission.as_mut().poll(ctx));\n                result?;\n                let driver = submission.driver().clone();\n                Poll::Ready(Ok(TcpStream::from_fd(connect.fd, Ring::new(driver))))\n            }\n            Err(err)        => {\n                let err = err.take().expect(\"polled Connect future after completion\");\n                Poll::Ready(Err(err))\n            }\n        }\n    }\n}\n\nimpl<D: Drive> Connect<D> {\n    fn project(self: Pin<&mut Self>)\n        -> Result<Pin<&mut Submission<event::Connect, D>>, &mut Option<io::Error>>\n    {\n        unsafe {\n            match &mut Pin::get_unchecked_mut(self).0 {\n                Ok(submission)  => Ok(Pin::new_unchecked(submission)),\n                Err(err)        => Err(err)\n            }\n        }\n    }\n}\n\nimpl<D: Drive> AsyncRead for TcpStream<D> {\n    fn poll_read(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8])\n        -> Poll<io::Result<usize>>\n    {\n        let mut inner = ready!(self.as_mut().poll_fill_buf(ctx))?;\n        let len = io::Read::read(&mut inner, buf)?;\n        self.consume(len);\n        Poll::Ready(Ok(len))\n    }\n}\n\nimpl<D: Drive> AsyncBufRead for TcpStream<D> {\n    fn poll_fill_buf(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {\n        self.as_mut().guard_op(Op::Read);\n        let fd = self.fd;\n        let (ring, buf, ..) = self.split();\n        buf.fill_buf(|buf| {\n            let n = ready!(ring.poll(ctx, 1, |sqs| { \n                let mut sqe = sqs.single().unwrap();\n                unsafe {\n                    sqe.prep_read(fd, buf, 0);\n                }\n                sqe\n            }))?;\n            Poll::Ready(Ok(n as u32))\n        })\n    }\n\n    fn consume(self: Pin<&mut Self>, amt: usize) {\n        self.buf().consume(amt);\n    }\n}\n\nimpl<D: Drive> AsyncWrite for TcpStream<D> {\n    fn poll_write(mut self: Pin<&mut Self>, ctx: &mut Context<'_>, slice: &[u8]) -> Poll<io::Result<usize>> {\n        self.as_mut().guard_op(Op::Write);\n        let fd = self.fd;\n        let (ring, buf, ..) = self.split();\n        let data = ready!(buf.fill_buf(|mut buf| {\n            Poll::Ready(Ok(io::Write::write(&mut buf, slice)? as u32))\n        }))?;\n        let n = ready!(ring.poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_write(fd, data, 0);\n            }\n            sqe\n        }))?;\n        buf.clear();\n        Poll::Ready(Ok(n as usize))\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        ready!(self.poll_write(ctx, &[]))?;\n        Poll::Ready(Ok(()))\n    }\n\n    fn poll_close(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.as_mut().guard_op(Op::Close);\n        let fd = self.fd;\n        ready!(self.as_mut().ring().poll(ctx, 1, |sqs| {\n            let mut sqe = sqs.single().unwrap();\n            unsafe {\n                sqe.prep_close(fd);\n            }\n            sqe\n        }))?;\n        self.confirm_close();\n        Poll::Ready(Ok(()))\n    }\n}\n\nimpl<D: Drive> Drop for TcpStream<D> {\n    fn drop(&mut self) {\n        match self.active {\n            Op::Closed  => { }\n            Op::Nothing => unsafe { libc::close(self.fd); },\n            _           => self.cancel(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/ring/cancellation.rs",
    "content": "use std::any::Any;\nuse std::ffi::CString;\nuse std::mem;\nuse std::ptr;\n\nuse either::Either;\n\nuse crate::buf::Buffer;\n\n/// A cancellation callback to clean up resources when IO gets cancelled.\n///\n/// When a user cancels interest in an event, the future representing that event needs to be\n/// dropped. However, that future may share ownership of some data structures (like buffers)\n/// with the kernel, which is completing the event. The cancellation callback will take\n/// ownership of those resources, and clean them up when it is dropped.\npub struct Cancellation {\n    data: *mut (),\n    metadata: usize,\n    drop: unsafe fn(*mut (), usize),\n}\n\npub unsafe trait Cancel {\n    fn into_raw(self) -> (*mut (), usize);\n    unsafe fn drop_raw(data: *mut (), metadata: usize);\n}\n\nunsafe impl<T> Cancel for Box<T> {\n    fn into_raw(self) -> (*mut (), usize) {\n        (Box::into_raw(self) as *mut (), 0)\n    }\n\n    unsafe fn drop_raw(data: *mut (), _: usize) {\n        drop(Box::from_raw(data as *mut T));\n    }\n}\n\nunsafe impl<T> Cancel for Box<[T]> {\n    fn into_raw(self) -> (*mut (), usize) {\n        let len = self.len();\n        (Box::into_raw(self) as *mut (), len)\n    }\n\n    unsafe fn drop_raw(data: *mut (), len: usize) {\n        drop(Vec::from_raw_parts(data as *mut T, len, len).into_boxed_slice());\n    }\n}\n\n#[repr(C)]\nstruct TraitObject {\n    data: *mut (),\n    vtable: *mut (),\n}\n\nunsafe impl Cancel for Box<dyn Any + Send + Sync> {\n    fn into_raw(self) -> (*mut (), usize) {\n        let obj = unsafe { mem::transmute::<Self, TraitObject>(self) };\n        (obj.data, obj.vtable as usize)\n    }\n\n    unsafe fn drop_raw(data: *mut (), metadata: usize) {\n        let obj = TraitObject { data, vtable: metadata as *mut () };\n        drop(mem::transmute::<TraitObject, Self>(obj));\n    }\n}\n\nunsafe impl Cancel for iou::registrar::RegisteredBuf {\n    fn into_raw(self) -> (*mut (), usize) {\n        self.into_inner().into_raw()\n    }\n\n    unsafe fn drop_raw(data: *mut (), metadata: usize) {\n        Box::<[u8]>::drop_raw(data, metadata)\n    }\n}\n\nunsafe impl Cancel for CString {\n    fn into_raw(self) -> (*mut (), usize) {\n        (self.into_raw() as *mut (), 0)\n    }\n\n    unsafe fn drop_raw(data: *mut (), _: usize) {\n        drop(CString::from_raw(data as *mut libc::c_char));\n    }\n}\n\nunsafe impl Cancel for () {\n    fn into_raw(self) -> (*mut (), usize) {\n        (ptr::null_mut(), 0)\n    }\n\n    unsafe fn drop_raw(_: *mut (), _: usize) { }\n}\n\npub unsafe trait CancelNarrow: Cancel { }\n\nunsafe impl<T> CancelNarrow for Box<T> { }\nunsafe impl CancelNarrow for CString { }\n\nunsafe impl<T: CancelNarrow, U: CancelNarrow> Cancel for (T, U) {\n    fn into_raw(self) -> (*mut (), usize) {\n        let left = self.0.into_raw().0;\n        let right = self.1.into_raw().0;\n        (left, right as usize)\n    }\n\n    unsafe fn drop_raw(data: *mut (), metadata: usize) {\n        T::drop_raw(data, 0);\n        U::drop_raw(metadata as *mut (), 0);\n    }\n}\n\n\nimpl Cancellation {\n    fn new<T: Cancel>(object: T) -> Cancellation {\n        let (data, metadata) = object.into_raw();\n        Cancellation { data, metadata, drop: T::drop_raw }\n    }\n}\n\nimpl<T: Cancel> From<T> for Cancellation {\n    fn from(object: T) -> Cancellation {\n        Cancellation::new(object)\n    }\n}\n\nimpl<T> From<Option<T>> for Cancellation where Cancellation: From<T> {\n    fn from(object: Option<T>) -> Cancellation {\n        object.map_or(Cancellation::new(()), Cancellation::from)\n    }\n}\n\nimpl From<Buffer> for Cancellation {\n    fn from(buffer: Buffer) -> Cancellation {\n        Cancellation::from(buffer.into_boxed_slice())\n    }\n}\n\nimpl<T, U> From<Either<T, U>> for Cancellation where Cancellation: From<T> + From<U> {\n    fn from(object: Either<T, U>) -> Cancellation {\n        object.either(Cancellation::from, Cancellation::from)\n    }\n}\n\nunsafe impl Send for Cancellation { }\nunsafe impl Sync for Cancellation { }\n\nimpl Drop for Cancellation {\n    fn drop(&mut self) {\n        unsafe {\n            (self.drop)(self.data, self.metadata)\n        }\n    }\n}\n"
  },
  {
    "path": "src/ring/completion.rs",
    "content": "use std::io;\nuse std::mem::{self, ManuallyDrop};\nuse std::task::Waker;\n\nuse parking_lot::Mutex;\n\nuse crate::ring::Cancellation;\nuse iou::CQE;\n\nuse State::*;\n\n/// A completion tracks an event that has been submitted to io-uring. It is a pointer to a heap\n/// allocated object which represents the state of the event's completion. Ownership of this object\n/// is shared between the Completion type and the io-uring instance (the address of the object is\n/// passed as a user_data field with the event's SQE).\n///\n/// Therefore, it requires a fair amout of unsafe code and synchronization to properly manage the\n/// lifecycle of this object. That code is encapsulated here inside a safe API for the rest of\n/// ringbahn to use.\n///\n/// This API is not publicly visible outside of this crate. (The Completion type in the public API\n/// is an opaque wrapper aroud this type). End users do not need to understand the completion API.\npub struct Completion {\n    state: ManuallyDrop<Box<Mutex<State>>>,\n}\n\nenum State {\n    Submitted(Waker),\n    Completed(io::Result<u32>),\n    Cancelled(Cancellation),\n    Empty,\n}\n\nimpl Completion {\n    /// Create a new completion for an event being prepared. When the event is completed by\n    /// io-uring, the waker this completion holds will be awoken.\n    pub fn new(waker: Waker) -> Completion {\n        Completion {\n            state: ManuallyDrop::new(Box::new(Mutex::new(Submitted(waker)))),\n        }\n    }\n\n    /// Get the address of this completion, so that it can set as the user_data field of the SQE\n    /// being prepared.\n    pub fn addr(&self) -> u64 {\n        &**self.state as *const Mutex<State> as usize as u64\n    }\n\n    /// Check if the completion has completed. If it has, the result of the completion will be\n    /// returned and the completion will be deallocated. If it has not been completed, the waker\n    /// field will be updated to the new waker if the old waker would not wake the same task.\n    pub fn check(self, waker: &Waker) -> Result<io::Result<u32>, Completion> {\n        let mut state = self.state.lock();\n        match mem::replace(&mut *state, State::Empty) {\n            Submitted(old_waker)    => {\n                let waker = if old_waker.will_wake(waker) { old_waker } else { waker.clone() };\n                *state = Submitted(waker);\n                drop(state);\n                Err(self)\n            }\n            Completed(result)       => {\n                drop(state);\n                drop(ManuallyDrop::into_inner(self.state));\n                Ok(result)\n            }\n            _                       => unreachable!()\n        }\n    }\n\n    /// Cancel interest in this completion. The Cancellation callback will be stored to clean up\n    /// resources shared with the kernel when the event completes.\n    pub fn cancel(self, callback: Cancellation) {\n        let mut state = self.state.lock();\n        match &*state {\n            Submitted(_)    => {\n                *state = Cancelled(callback);\n                drop(state);\n            }\n            Completed(_)    => {\n                drop(callback);\n                drop(state);\n                drop(ManuallyDrop::into_inner(self.state));\n            }\n            _               => unreachable!()\n        }\n    }\n\n    fn complete(self, result: io::Result<u32>) {\n        let mut state = self.state.lock();\n        match mem::replace(&mut *state, State::Empty) {\n            Submitted(waker)    => {\n                *state = Completed(result);\n                waker.wake();\n            }\n            Cancelled(callback) => {\n                drop(callback);\n                drop(state);\n                drop(ManuallyDrop::into_inner(self.state));\n            }\n            _                   => unreachable!()\n        }\n    }\n}\n\npub fn complete(cqe: CQE) {\n    unsafe {\n        let result = cqe.result();\n        let user_data = cqe.user_data();\n        // iou should never raise LIBURING_UDATA_TIMEOUTs, this is just to catch bugs in iou\n        debug_assert!(user_data != uring_sys::LIBURING_UDATA_TIMEOUT);\n        let state = user_data as *mut Mutex<State>;\n\n        if !state.is_null() {\n            let completion = Completion {\n                state: ManuallyDrop::new(Box::from_raw(state))\n            };\n            completion.complete(result);\n        }\n    };\n}\n"
  },
  {
    "path": "src/ring/mod.rs",
    "content": "mod cancellation;\npub(crate) mod completion;\n\nuse std::io;\nuse std::mem;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_core::ready;\nuse iou::{SQE, SQEs};\n\nuse crate::drive::{self, Drive};\n\npub use cancellation::{Cancellation, Cancel, CancelNarrow};\npub(crate) use completion::Completion;\n\nuse State::*;\n\n/// A low-level primitive for building an IO object on io-uring\n/// \n/// Ring is a state machine similar to `Submission`, but it is designed to cycle through multiple\n/// IO events submitted to io-uring, rather than representing a single submission. Because of this,\n/// it is more low level, but it is suitable for building an IO object like a `File` on top of\n/// io-uring.\n///\n/// Users writing code on top of `Ring` are responsible for making sure that it is correct. For\n/// example, when calling `poll`, users must ensure that they are in the proper state to submit\n/// whatever type of IO they would be attempting to submit. Additionally, users should note that\n/// `Ring` does not implement `Drop`. In order to cancel any ongoing IO, users are responsible for\n/// implementing drop to call cancel properly.\npub struct Ring<D: Drive> {\n    state: State,\n    driver: D,\n}\n\nenum State {\n    Inert,\n    Prepared(Completion),\n    Submitted(Completion),\n    Cancelled(u64),\n    Lost,\n}\n\n\nimpl<D: Default + Drive> Default for Ring<D> {\n    fn default() -> Ring<D> {\n        Ring::new(D::default())\n    }\n}\n\nimpl<D: Drive + Clone> Clone for Ring<D> {\n    fn clone(&self) -> Ring<D> {\n        Ring::new(self.driver.clone())\n    }\n}\n\nimpl<D: Drive> Ring<D> {\n    /// Construct a new Ring on top of a driver.\n    #[inline(always)]\n    pub fn new(driver: D) -> Ring<D> {\n        Ring {\n            state: Inert,\n            driver\n        }\n    }\n\n    pub fn driver(&self) -> &D {\n        &self.driver\n    }\n\n    /// Poll the ring state machine.\n    ///\n    /// This accepts a callback, `prepare`, which prepares an event to be submitted to io-uring.\n    /// This callback will only be called once during an iteration of ring's state machine: once an\n    /// event has been prepared, until it is completed or cancelled, a single ring instance will\n    /// not prepare any additional events.\n    #[inline]\n    pub fn poll(\n        mut self: Pin<&mut Self>,\n        ctx: &mut Context<'_>,\n        count: u32,\n        prepare: impl for<'sq> FnOnce(&mut SQEs<'sq>) -> SQE<'sq>,\n    ) -> Poll<io::Result<u32>> {\n        match self.state {\n            Inert | Cancelled(_) => {\n                ready!(self.as_mut().poll_prepare(ctx, count, prepare));\n                ready!(self.as_mut().poll_submit(ctx));\n                Poll::Pending\n            }\n            Prepared(_)             => {\n                match self.as_mut().poll_complete(ctx) {\n                    ready @ Poll::Ready(..) => ready,\n                    Poll::Pending           => {\n                        ready!(self.poll_submit(ctx));\n                        Poll::Pending\n                    }\n                }\n            }\n            Submitted(_)            => self.poll_complete(ctx),\n            Lost                    => panic!(\"Ring in a bad state; driver is faulty\"),\n        }\n    }\n\n    #[inline(always)]\n    fn poll_prepare(\n        self: Pin<&mut Self>,\n        ctx: &mut Context<'_>,\n        count: u32,\n        prepare: impl for<'sq> FnOnce(&mut SQEs<'sq>) -> SQE<'sq>,\n    ) -> Poll<()> {\n        let (driver, state) = self.split();\n        let completion = match *state {\n            Cancelled(prev) => {\n                ready!(driver.poll_prepare(ctx, count + 1, |mut sqs, ctx| {\n                    *state = Lost;\n                    unsafe { sqs.hard_linked().next().unwrap().prep_cancel(prev, 0); }\n                    let sqe = prepare(&mut sqs);\n                    drive::Completion::new(sqe, sqs, ctx)\n                }))\n            }\n            Inert           => {\n                ready!(driver.poll_prepare(ctx, count, |mut sqs, ctx| {\n                    *state = Lost;\n                    let sqe = prepare(&mut sqs);\n                    drive::Completion::new(sqe, sqs, ctx)\n                }))\n            }\n            _               => unreachable!(),\n        };\n        *state = Prepared(completion.real);\n        Poll::Ready(())\n    }\n\n    #[inline(always)]\n    fn poll_submit(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<()> {\n        let (driver, state) = self.split();\n        // TODO figure out how to handle this result\n        let _ = ready!(driver.poll_submit(ctx));\n        if let Prepared(completion) | Submitted(completion) = mem::replace(state, Lost) {\n            *state = Submitted(completion);\n            Poll::Ready(())\n        } else {\n            unreachable!()\n        }\n    }\n\n    #[inline(always)]\n    fn poll_complete(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<u32>> {\n        let (_, state) = self.split();\n        match mem::replace(state, Lost) {\n            Prepared(completion)    => {\n                match completion.check(ctx.waker()) {\n                    Ok(result)      => {\n                        *state = Inert;\n                        Poll::Ready(result)\n                    }\n                    Err(completion) => {\n                        *state = Prepared(completion);\n                        Poll::Pending\n                    }\n                }\n            }\n            Submitted(completion)   => {\n                match completion.check(ctx.waker()) {\n                    Ok(result)      => {\n                        *state = Inert;\n                        Poll::Ready(result)\n                    }\n                    Err(completion) => {\n                        *state = Submitted(completion);\n                        Poll::Pending\n                    }\n                }\n            }\n            _                       => unreachable!(),\n        }\n    }\n\n    /// Cancel any ongoing IO with this cancellation.\n    ///\n    /// Users are responsible for ensuring that the cancellation passed would be appropriate to\n    /// clean up the resources of the running event.\n    #[inline]\n    pub fn cancel(&mut self, cancellation: Cancellation) {\n        self.state.cancel(cancellation);\n    }\n\n    /// Cancel any ongoing IO, but from a pinned reference.\n    ///\n    /// This has the same behavior of as Ring::cancel.\n    pub fn cancel_pinned(self: Pin<&mut Self>, cancellation: Cancellation) {\n        self.split().1.cancel(cancellation);\n    }\n\n    fn split(self: Pin<&mut Self>) -> (Pin<&mut D>, &mut State) {\n        unsafe {\n            let this = Pin::get_unchecked_mut(self);\n            (Pin::new_unchecked(&mut this.driver), &mut this.state)\n        }\n    }\n}\n\nimpl State {\n    fn cancel(&mut self, cancellation: Cancellation) {\n        match mem::replace(self, Lost) {\n            Prepared(completion) | Submitted(completion) => {\n                *self = Cancelled(completion.addr());\n                completion.cancel(cancellation);\n            }\n            state                                       => {\n                *self = state;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/submission.rs",
    "content": "use std::future::Future;\nuse std::io;\nuse std::mem::ManuallyDrop;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_core::ready;\n\nuse crate::{Event, Drive, ring::Ring};\n\n/// A [`Future`] representing an event submitted to io-uring\npub struct Submission<E: Event, D: Drive> {\n    ring: Ring<D>,\n    event: Option<E>,\n}\n\nimpl<E: Event, D: Drive> Submission<E, D> {\n    /// Construct a new submission from an event and a driver.\n    pub fn new(event: E, driver: D) -> Submission<E, D> {\n        Submission {\n            ring: Ring::new(driver),\n            event: Some(event),\n        }\n    }\n\n    /// Access the driver this submission is using\n    pub fn driver(&self) -> &D {\n        self.ring.driver()\n    }\n\n    pub fn replace_event(self: Pin<&mut Self>, event: E) {\n        let (ring, event_slot) = self.split();\n        if let Some(event) = event_slot.take() {\n            ring.cancel_pinned(E::cancel(ManuallyDrop::new(event)))\n        }\n        *event_slot = Some(event);\n    }\n\n    fn split(self: Pin<&mut Self>) -> (Pin<&mut Ring<D>>, &mut Option<E>) {\n        unsafe {\n            let this = Pin::get_unchecked_mut(self);\n            (Pin::new_unchecked(&mut this.ring), &mut this.event)\n        }\n    }\n}\n\nimpl<E, D> Future for Submission<E, D> where\n    E: Event,\n    D: Drive,\n{\n    type Output = (E, io::Result<u32>);\n\n    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {\n        let (ring, event) = self.split();\n\n        let result = if let Some(event) = event {\n            let count = event.sqes_needed();\n            ready!(ring.poll(ctx, count, |sqs| unsafe { event.prepare(sqs) }))\n        } else {\n            panic!(\"polled Submission after completion\")\n        };\n\n        Poll::Ready((event.take().unwrap(), result))\n    }\n}\n\n\nimpl<E: Event, D: Drive> Drop for Submission<E, D> {\n    fn drop(&mut self) {\n        if let Some(event) = self.event.take() {\n            self.ring.cancel(E::cancel(ManuallyDrop::new(event)))\n        }\n    }\n}\n"
  },
  {
    "path": "src/unix/listener.rs",
    "content": "use std::io;\nuse std::future::Future;\nuse std::os::unix::io::{RawFd};\nuse std::path::Path;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_core::{ready, Stream};\nuse nix::sys::socket::{self as nix_socket, SockFlag};\n\nuse crate::drive::{Drive, demo::DemoDriver};\nuse crate::ring::{Ring, Cancellation};\n\nuse super::UnixStream;\n\npub struct UnixListener<D: Drive = DemoDriver> {\n    ring: Ring<D>,\n    fd: RawFd,\n    active: Op,\n}\n\n#[derive(Eq, PartialEq, Copy, Clone, Debug)]\nenum Op {\n    Nothing = 0,\n    Accept,\n    Close,\n    Closed,\n}\n\nimpl UnixListener {\n    pub fn bind(path: impl AsRef<Path>) -> io::Result<UnixListener> {\n        UnixListener::bind_on_driver(path, DemoDriver::default())\n    }\n}\n\nimpl<D: Drive> UnixListener<D> {\n    pub fn bind_on_driver(path: impl AsRef<Path>, driver: D) -> io::Result<UnixListener<D>> {\n        let fd = super::socket()?;\n        let addr = iou::sqe::SockAddr::Unix(nix_socket::UnixAddr::new(path.as_ref()).unwrap());\n        nix_socket::bind(fd, &addr).map_err(|e| e.as_errno().unwrap_or(nix::errno::Errno::EIO))?;\n        nix_socket::listen(fd, 128).map_err(|e| e.as_errno().unwrap_or(nix::errno::Errno::EIO))?;\n        let ring = Ring::new(driver);\n        Ok(UnixListener {\n            active: Op::Nothing,\n            fd, ring,\n        })\n    }\n\n    pub fn close(&mut self) -> Close<D> where D: Unpin {\n        Pin::new(self).close_pinned()\n    }\n\n    pub fn close_pinned(self: Pin<&mut Self>) -> Close<D> {\n        Close { socket: self }\n    }\n\n    fn guard_op(self: Pin<&mut Self>, op: Op) {\n        let this = unsafe { Pin::get_unchecked_mut(self) };\n        if this.active == Op::Closed {\n            panic!(\"Attempted to perform IO on a closed UnixListener\");\n        }\n        if this.active != Op::Nothing && this.active != op {\n            this.cancel();\n        }\n        this.active = op;\n    }\n\n    fn cancel(&mut self) {\n        if !matches!(self.active, Op::Nothing | Op::Closed) {\n            self.active = Op::Nothing;\n            self.ring.cancel(Cancellation::from(()));\n        }\n    }\n\n    fn ring(self: Pin<&mut Self>) -> Pin<&mut Ring<D>> {\n        unsafe { Pin::map_unchecked_mut(self, |this| &mut this.ring) }\n    }\n\n    fn confirm_close(self: Pin<&mut Self>) {\n        unsafe { Pin::get_unchecked_mut(self).active = Op::Closed; }\n    }\n}\n\nimpl<D: Drive + Clone> UnixListener<D> {\n    pub fn accept(&mut self) -> Accept<'_, D> where D: Unpin {\n        Pin::new(self).accept_pinned()\n    }\n\n    pub fn accept_pinned(self: Pin<&mut Self>) -> Accept<'_, D> {\n        Accept { socket: self }\n    }\n\n    pub fn incoming(&mut self) -> Incoming<'_, D> where D: Unpin {\n        Pin::new(self).incoming_pinned()\n    }\n\n    pub fn incoming_pinned(self: Pin<&mut Self>) -> Incoming<'_, D> {\n        Incoming { accept: self.accept_pinned() }\n    }\n\n    pub fn poll_accept(mut self: Pin<&mut Self>, ctx: &mut Context<'_>)\n        -> Poll<io::Result<UnixStream<D>>>\n    {\n        self.as_mut().guard_op(Op::Accept);\n        let fd = self.fd;\n        let fd = ready!(self.as_mut().ring().poll(ctx, 1, |sqs| unsafe {\n            let mut sqe = sqs.single().unwrap();\n            sqe.prep_accept(fd, None, SockFlag::empty());\n            sqe\n        }))? as RawFd;\n        Poll::Ready(Ok(UnixStream::from_fd(fd, self.ring().clone())))\n    }\n\n}\n\nimpl<D: Drive> Drop for UnixListener<D> {\n    fn drop(&mut self) {\n        match self.active {\n            Op::Closed  => { }\n            Op::Nothing => unsafe { libc::close(self.fd); }\n            _           => self.cancel(),\n        }\n    }\n}\n\npub struct Accept<'a, D: Drive> {\n    socket: Pin<&'a mut UnixListener<D>>,\n}\n\nimpl<'a, D: Drive + Clone> Future for Accept<'a, D> {\n    type Output = io::Result<UnixStream<D>>;\n\n    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.socket.as_mut().poll_accept(ctx)\n    }\n}\n\npub struct Incoming<'a, D: Drive> {\n    accept: Accept<'a, D>,\n}\n\nimpl<'a, D: Drive> Incoming<'a, D> {\n    fn inner(self: Pin<&mut Self>) -> Pin<&mut Accept<'a, D>> {\n        unsafe { Pin::map_unchecked_mut(self, |this| &mut this.accept) }\n    }\n}\n\nimpl<'a, D: Drive + Clone> Stream for Incoming<'a, D> {\n    type Item = io::Result<UnixStream<D>>;\n\n    fn poll_next(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let next = ready!(self.inner().poll(ctx));\n        Poll::Ready(Some(next))\n    }\n}\n\n\npub struct Close<'a, D: Drive> {\n    socket: Pin<&'a mut UnixListener<D>>,\n}\n\nimpl<'a, D: Drive> Future for Close<'a, D> {\n    type Output = io::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.socket.as_mut().guard_op(Op::Close);\n        let fd = self.socket.fd;\n        ready!(self.socket.as_mut().ring().poll(ctx, 1, |sqs| unsafe {\n            let mut sqe = sqs.single().unwrap();\n            sqe.prep_close(fd);\n            sqe\n        }))?;\n        self.socket.as_mut().confirm_close();\n        Poll::Ready(Ok(()))\n    }\n}\n"
  },
  {
    "path": "src/unix/mod.rs",
    "content": "use std::io;\nuse std::os::unix::io::RawFd;\n\nmod listener;\nmod stream;\n\npub use listener::{UnixListener, Close, Accept, Incoming};\npub use stream::{UnixStream, Connect};\n\nuse nix::sys::socket as nix;\n\nfn socket() -> io::Result<RawFd> {\n    match nix::socket(nix::AddressFamily::Unix, nix::SockType::Stream, nix::SockFlag::SOCK_CLOEXEC, None) {\n        Ok(fd)  => Ok(fd),\n        Err(_)  => Err(io::Error::last_os_error()),\n    }\n}\n\nfn socketpair() -> io::Result<(RawFd, RawFd)> {\n    match nix::socketpair(nix::AddressFamily::Unix, nix::SockType::Stream, None, nix::SockFlag::SOCK_CLOEXEC) {\n        Ok((fd1, fd2))  => Ok((fd1, fd2)),\n        Err(_)          => Err(io::Error::last_os_error()),\n    }\n}\n"
  },
  {
    "path": "src/unix/stream.rs",
    "content": "use std::io;\nuse std::future::Future;\nuse std::os::unix::io::RawFd;\nuse std::path::Path;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_core::ready;\nuse futures_io::{AsyncRead, AsyncBufRead, AsyncWrite};\nuse iou::sqe::SockAddr;\nuse nix::sys::socket::UnixAddr;\n\nuse crate::drive::{Drive, demo::DemoDriver};\nuse crate::event;\nuse crate::ring::Ring;\nuse crate::Submission;\n\nuse super::{socket, socketpair};\n\nuse crate::net::TcpStream;\n\npub struct UnixStream<D: Drive = DemoDriver> {\n    inner: TcpStream<D>,\n}\n\nimpl UnixStream {\n    pub fn connect(path: &impl AsRef<Path>) -> Connect {\n        UnixStream::connect_on_driver(path, DemoDriver::default())\n    }\n\n    pub fn pair() -> io::Result<(UnixStream, UnixStream)> {\n        UnixStream::pair_on_driver(DemoDriver::default())\n    }\n}\n\nimpl<D: Drive + Clone> UnixStream<D> {\n    pub fn connect_on_driver(path: &impl AsRef<Path>, driver: D) -> Connect<D> {\n        let fd = match socket() {\n            Ok(fd)  => fd,\n            Err(e)  => return Connect(Err(Some(e))),\n        };\n        let addr = Box::new(SockAddr::Unix(UnixAddr::new(path.as_ref()).unwrap()));\n        Connect(Ok(driver.submit(event::Connect { fd, addr })))\n    }\n\n    pub fn pair_on_driver(driver: D) -> io::Result<(UnixStream<D>, UnixStream<D>)> {\n        let (fd1, fd2) = socketpair()?;\n        let ring1 = Ring::new(driver.clone());\n        let ring2 = Ring::new(driver);\n        Ok((UnixStream::from_fd(fd1, ring1), UnixStream::from_fd(fd2, ring2)))\n    }\n}\n\nimpl<D: Drive> UnixStream<D> {\n    pub(super) fn from_fd(fd: RawFd, ring: Ring<D>) -> UnixStream<D> {\n        UnixStream {\n            inner: TcpStream::from_fd(fd, ring),\n        }\n    }\n\n    #[inline(always)]\n    fn inner(self: Pin<&mut Self>) -> Pin<&mut TcpStream<D>> {\n        unsafe { Pin::map_unchecked_mut(self, |this| &mut this.inner) }\n    }\n}\n\npub struct Connect<D: Drive = DemoDriver>(\n    Result<Submission<event::Connect, D>, Option<io::Error>>\n);\n\nimpl<D: Drive + Clone> Future for Connect<D> {\n    type Output = io::Result<UnixStream<D>>;\n\n    fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {\n        unsafe {\n            match &mut Pin::get_unchecked_mut(self).0 {\n                Ok(submission)  => {\n                    let mut submission = Pin::new_unchecked(submission);\n                    let (connect, result) = ready!(submission.as_mut().poll(ctx));\n                    result?;\n                    let driver = submission.driver().clone();\n                    Poll::Ready(Ok(UnixStream::from_fd(connect.fd, Ring::new(driver))))\n                }\n                Err(err)        => {\n                    let err = err.take().expect(\"polled Connect future after completion\");\n                    Poll::Ready(Err(err))\n                }\n            }\n        }\n    }\n}\n\nimpl<D: Drive> AsyncRead for UnixStream<D> {\n    fn poll_read(self: Pin<&mut Self>, ctx: &mut Context<'_>, buf: &mut [u8])\n        -> Poll<io::Result<usize>>\n    {\n        self.inner().poll_read(ctx, buf)\n    }\n}\n\nimpl<D: Drive> AsyncBufRead for UnixStream<D> {\n    fn poll_fill_buf(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {\n        self.inner().poll_fill_buf(ctx)\n    }\n\n    fn consume(self: Pin<&mut Self>, amt: usize) {\n        self.inner().consume(amt)\n    }\n}\n\nimpl<D: Drive> AsyncWrite for UnixStream<D> {\n    fn poll_write(self: Pin<&mut Self>, ctx: &mut Context<'_>, slice: &[u8]) -> Poll<io::Result<usize>> {\n        self.inner().poll_write(ctx, slice)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.inner().poll_flush(ctx)\n    }\n\n    fn poll_close(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.inner().poll_close(ctx)\n    }\n}\n"
  },
  {
    "path": "tests/basic-read.rs",
    "content": "use std::fs::File;\nuse std::os::unix::io::AsRawFd;\n\nuse ringbahn::Submission;\nuse ringbahn::event::Read;\nuse ringbahn::drive::demo;\n\nconst ASSERT: &[u8] = b\"But this formidable power of death -\";\n\n#[test]\nfn read_file() {\n    let file = File::open(\"props.txt\").unwrap();\n    let read = Read {\n        fd: file.as_raw_fd(),\n        buf: vec![0; 4096].into(),\n        offset: 0,\n    };\n    let (read, result) = futures::executor::block_on(Submission::new(read, demo::driver()));\n    assert!(result.is_ok());\n    assert_eq!(&read.buf[0..ASSERT.len()], ASSERT);\n}\n"
  },
  {
    "path": "tests/basic-readv.rs",
    "content": "use std::fs::File;\nuse std::os::unix::io::AsRawFd;\n\nuse ringbahn::Submission;\nuse ringbahn::event::ReadVectored;\nuse ringbahn::drive::demo;\n\nconst ASSERT: &[u8] = b\"But this formidable power of death -\";\n\n#[test]\nfn readv_file() {\n    let file = File::open(\"props.txt\").unwrap();\n    let vec1: Box<[u8]> = Box::new([0; 4]);\n    let vec2: Box<[u8]> = Box::new([0; 5]);\n    let vec3: Box<[u8]> = Box::new([0; 10]);\n    let readv = ReadVectored {\n        fd: file.as_raw_fd(),\n        bufs: vec![vec1, vec2, vec3].into_boxed_slice(),\n        offset: 0,\n    };\n    let (readv, result) = futures::executor::block_on(Submission::new(readv, demo::driver()));\n    assert!(result.is_ok());\n    assert_eq!(readv.bufs[0][..], ASSERT[0..4]); \n    assert_eq!(readv.bufs[1][..], ASSERT[4..9]); \n    assert_eq!(readv.bufs[2][..], ASSERT[9..19]); \n}\n"
  },
  {
    "path": "tests/basic-write.rs",
    "content": "use std::io::Read;\nuse std::os::unix::io::AsRawFd;\n\nuse ringbahn::Submission;\nuse ringbahn::event::Write;\nuse ringbahn::drive::demo;\n\nconst ASSERT: &[u8] = b\"But this formidable power of death -\";\n\n#[test]\nfn write_file() {\n    let mut file = tempfile::tempfile().unwrap();\n    let write = Write {\n        fd: file.as_raw_fd(),\n        buf: Box::from(ASSERT),\n        offset: 0,\n    };\n    let (_, result) = futures::executor::block_on(Submission::new(write, demo::driver()));\n    assert_eq!(result.unwrap() as usize, ASSERT.len());\n\n    let mut buf = vec![];\n    assert_eq!(file.read_to_end(&mut buf).unwrap(), ASSERT.len());\n    assert_eq!(&buf[0..ASSERT.len()], ASSERT);\n}\n"
  },
  {
    "path": "tests/basic-writev.rs",
    "content": "use std::io::Read; \nuse std::os::unix::io::AsRawFd;\n\nuse ringbahn::Submission;\nuse ringbahn::event::WriteVectored;\nuse ringbahn::drive::demo;\n\nconst ASSERT: &[u8] = b\"But this formidable power of death -\";\n\n#[test]\nfn writev_file() {\n    let mut file = tempfile::tempfile().unwrap();\n    let vec1 = &ASSERT[0..4];\n    let vec2 = &ASSERT[4..9];\n    let vec3 = &ASSERT[9..];\n    let writev = WriteVectored {\n        fd: file.as_raw_fd(),\n        bufs: vec![vec1.into(), vec2.into(), vec3.into()].into(),\n        offset: 0,\n    };\n    let (_, result) = futures::executor::block_on(Submission::new(writev, demo::driver()));\n    assert_eq!(result.unwrap() as usize, ASSERT.len());\n\n    let mut buf = vec![];\n    assert_eq!(file.read_to_end(&mut buf).unwrap(), ASSERT.len());\n    assert_eq!(&buf[0..ASSERT.len()], ASSERT);\n}\n"
  },
  {
    "path": "tests/file-close.rs",
    "content": "use futures::{AsyncReadExt, AsyncWriteExt};\n\nuse ringbahn::fs::File;\n\nconst ASSERT: &[u8] = b\"But this formidable power of death -\";\n\n#[test]\nfn read_and_close_file() {\n    futures::executor::block_on(async move {\n        let mut file = File::open(\"props.txt\").await.unwrap();\n        let mut buf = vec![0; 4096];\n        assert!(file.read(&mut buf).await.is_ok());\n        assert_eq!(&buf[0..ASSERT.len()], ASSERT);\n        file.close().await.unwrap();\n    });\n}\n"
  },
  {
    "path": "tests/file-read.rs",
    "content": "use futures::AsyncReadExt;\n\nuse ringbahn::fs::File;\n\nconst ASSERT: &[u8] = b\"But this formidable power of death -\";\n\n#[test]\nfn read_file() {\n    futures::executor::block_on(async move {\n        let mut file = File::open(\"props.txt\").await.unwrap();\n        let mut buf = vec![0; 4096];\n        assert!(file.read(&mut buf).await.is_ok());\n        assert_eq!(&buf[0..ASSERT.len()], ASSERT);\n    });\n}\n\n#[test]\nfn read_to_end() {\n    futures::executor::block_on(async move {\n        let mut file = File::open(\"props.txt\").await.unwrap();\n        let mut buf = Vec::new();\n        assert!(file.read_to_end(&mut buf).await.is_ok());\n        assert_eq!(&buf[0..ASSERT.len()], ASSERT);\n    });\n}\n"
  },
  {
    "path": "tests/file-seek.rs",
    "content": "use std::io::SeekFrom;\nuse futures::{AsyncSeekExt, AsyncReadExt, AsyncWriteExt};\n\nuse ringbahn::fs::File;\n\n#[test]\nfn seek_to_end() {\n    futures::executor::block_on(async move {\n        let mut file = File::open(\"props.txt\").await.unwrap();\n        assert_eq!(file.seek(SeekFrom::End(0)).await.unwrap(), 792);\n    });\n}\n\n#[test]\nfn seek_and_then_io() {\n    futures::executor::block_on(async move {\n        let mut file: File = tempfile::tempfile().unwrap().into();\n        assert_eq!(file.seek(SeekFrom::End(0)).await.unwrap(), 0);\n        file.write(b\"abcdef\").await.unwrap();\n        let mut buf = [0; 16];\n        assert_eq!(file.seek(SeekFrom::Start(0)).await.unwrap(), 0);\n        file.read(&mut buf).await.unwrap();\n        assert_eq!(&buf[0..6], b\"abcdef\");\n    });\n}\n"
  },
  {
    "path": "tests/file-write.rs",
    "content": "use std::io::SeekFrom;\n\nuse futures::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};\n\nuse ringbahn::fs::File;\n\nconst ASSERT: &[u8] = b\"But this formidable power of death -\";\n\n#[test]\nfn write_file() {\n    let file = tempfile::tempfile().unwrap();\n    let mut file = File::from(file);\n    futures::executor::block_on(async move {\n        assert_eq!(file.write(ASSERT).await.unwrap(), ASSERT.len());\n\n        let mut buf = vec![];\n        assert!(file.seek(SeekFrom::Start(0)).await.is_ok());\n        assert_eq!(file.read_to_end(&mut buf).await.unwrap(), ASSERT.len());\n        assert_eq!(&buf[0..ASSERT.len()], ASSERT);\n    });\n}\n\n#[test]\nfn select_complete_many_futures() {\n    async fn act() {\n        let file = tempfile::tempfile().unwrap();\n        let mut file = File::from(file);\n        file.write_all(b\"hello, world!\").await.unwrap();\n    }\n\n    futures::executor::block_on(async move {\n        use futures::FutureExt;\n\n        let mut f1 = Box::pin(act().fuse());\n        let mut f2 = Box::pin(act().fuse());\n        let mut f3 = Box::pin(act().fuse());\n        let mut f4 = Box::pin(act().fuse());\n        let mut f5 = Box::pin(act().fuse());\n        let mut f6 = Box::pin(act().fuse());\n        let mut f7 = Box::pin(act().fuse());\n        let mut f8 = Box::pin(act().fuse());\n        loop {\n            futures::select! {\n                _ = f1  => (),\n                _ = f2  => (),\n                _ = f3  => (),\n                _ = f4  => (),\n                _ = f5  => (),\n                _ = f6  => (),\n                _ = f7  => (),\n                _ = f8  => (),\n                complete => break,\n            }\n        }\n    });\n}\n"
  },
  {
    "path": "tests/println.rs",
    "content": "use ringbahn::drive::demo;\n\n#[test]\nfn println() {\n    futures::executor::block_on(async {\n        ringbahn::println!(demo::driver(), \"Hello, world!\").await\n    })\n}\n\n#[test]\nfn print() {\n    futures::executor::block_on(async {\n        ringbahn::print!(demo::driver(), \"Hello, world!\").await\n    })\n}\n\n#[test]\nfn eprintln() {\n    futures::executor::block_on(async {\n        ringbahn::eprintln!(demo::driver(), \"Hello, world!\").await\n    })\n}\n\n#[test]\nfn eprint() {\n    futures::executor::block_on(async {\n        ringbahn::eprint!(demo::driver(), \"Hello, world!\").await\n    })\n}\n"
  },
  {
    "path": "tests/registered-fd.rs",
    "content": "use std::os::unix::io::IntoRawFd;\n\nuse ringbahn::event::*;\nuse ringbahn::drive::{demo, Drive};\n\nuse iou::sqe::*;\n\n#[test]\nfn test_registered_fd_ops() {\n    // open and register file\n    let file = std::fs::File::open(\"props.txt\").unwrap();\n    let fd = demo::registrar().unwrap()\n                  .register_files(&[file.into_raw_fd()]).unwrap().next().unwrap();\n\n    futures::executor::block_on(async move {\n        // read file and print contents to stdout\n        let buf = vec![0; 1024].into_boxed_slice();\n        let (event, result) = demo::driver().submit(Read { fd, buf, offset: 0 }).await;\n        let n = result.unwrap() as _;\n        let data = String::from_utf8_lossy(&event.buf[..n]).to_owned();\n        ringbahn::println!(demo::driver(), \"{}\", data).await;\n\n        // statx file and print statx to stdout\n        let (event, result) = demo::driver().submit(Statx::without_path(\n            fd,\n            StatxFlags::empty(),\n            StatxMode::all(),\n        )).await;\n        result.unwrap();\n        ringbahn::println!(demo::driver(), \"{:?}\", event.statx).await;\n\n        // close file with ringbahn\n        let (_, result) = demo::driver().submit(Close { fd }).await;\n        result.unwrap();\n    });\n}\n"
  },
  {
    "path": "tests/stdio.rs",
    "content": "use futures::AsyncWriteExt;\n\nuse ringbahn::{drive::demo};\n\nconst ASSERT: &[u8] = b\"Hello, world!\\n\";\n\n#[test]\nfn write_stdout() {\n    futures::executor::block_on(async {\n        let n = ringbahn::io::stdout().write(ASSERT).await.unwrap();\n        assert_eq!(n, ASSERT.len());\n        let mut stdout = ringbahn::io::stdout_on_driver(demo::driver());\n        let n = stdout.write(ASSERT).await.unwrap();\n        assert_eq!(n, ASSERT.len());\n    });\n}\n"
  }
]