use std::cell::RefCell; use std::io::{self, Read, Write}; use futures::task::TaskRc; /// Abstraction that allows inserting an I/O object into task-local storage, /// returning a handle that can be split. /// /// A `TaskIo` handle implements the `ReadTask` and `WriteTask` and will only /// work with the same task that the associated object was inserted into. The /// handle may then be optionally `split` into the read/write halves so they can /// be worked with independently. /// /// Note that it is important that the future returned from `TaskIo::new`, when /// polled, will pin the yielded `TaskIo` object to that specific task. Any /// attempt to read or write the object on other tasks will result in a panic. pub struct TaskIo { handle: TaskRc>, } /// The readable half of a `TaskIo` instance returned from `TaskIo::split`. /// /// This handle implements the `ReadTask` trait and can be used to split up an /// I/O object into two distinct halves. pub struct TaskIoRead { handle: TaskRc>, } /// The writable half of a `TaskIo` instance returned from `TaskIo::split`. /// /// This handle implements the `WriteTask` trait and can be used to split up an /// I/O object into two distinct halves. pub struct TaskIoWrite { handle: TaskRc>, } impl TaskIo { /// Returns a new future which represents the insertion of the I/O object /// `T` into task local storage, returning a `TaskIo` handle to it. /// /// The returned future will never resolve to an error. pub fn new(t: T) -> TaskIo { TaskIo { handle: TaskRc::new(RefCell::new(t)), } } } impl TaskIo where T: Read + Write, { /// For an I/O object which is both readable and writable, this method can /// be used to split the handle into two independently owned halves. /// /// The returned pair implements the `ReadTask` and `WriteTask` traits, /// respectively, and can be used to pass around the object to different /// combinators if necessary. pub fn split(self) -> (TaskIoRead, TaskIoWrite) { (TaskIoRead { handle: self.handle.clone() }, TaskIoWrite { handle: self.handle }) } } impl Read for TaskIo where T: io::Read, { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.handle.with(|t| t.borrow_mut().read(buf)) } } impl Write for TaskIo where T: io::Write, { fn write(&mut self, buf: &[u8]) -> io::Result { self.handle.with(|t| t.borrow_mut().write(buf)) } fn flush(&mut self) -> io::Result<()> { self.handle.with(|t| t.borrow_mut().flush()) } } impl Read for TaskIoRead where T: io::Read, { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.handle.with(|t| t.borrow_mut().read(buf)) } } impl Write for TaskIoWrite where T: io::Write, { fn write(&mut self, buf: &[u8]) -> io::Result { self.handle.with(|t| t.borrow_mut().write(buf)) } fn flush(&mut self) -> io::Result<()> { self.handle.with(|t| t.borrow_mut().flush()) } }