diff --git a/CHANGELOG.md b/CHANGELOG.md index f3b4c538e2..cba9ae2ca3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- Added safe support for nearly any buffer type in the `sys::aio` module. + ([#872](https://github.com/nix-rust/nix/pull/872)) - Added `sys::aio::LioCb` as a wrapper for `libc::lio_listio`. ([#872](https://github.com/nix-rust/nix/pull/872)) - Added `getsid` in `::nix::unistd` @@ -31,6 +33,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#837](https://github.com/nix-rust/nix/pull/837)) ### Removed +- Removed explicit support for the `bytes` crate from the `sys::aio` module. + See `sys::aio::AioCb::from_boxed_slice`s examples for alternatives. + ([#872](https://github.com/nix-rust/nix/pull/872)) - Removed `sys::aio::lio_listio`. Use `sys::aio::LioCb::listio` instead. ([#872](https://github.com/nix-rust/nix/pull/872)) diff --git a/Cargo.toml b/Cargo.toml index 651c2184ce..17a1bac94c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,15 +17,13 @@ bitflags = "1.0" cfg-if = "0.1.0" void = "1.0.2" -[dependencies.bytes] -version = "0.4.5" -# Don't include the optional serde feature -default-features = false - [target.'cfg(target_os = "dragonfly")'.build-dependencies] gcc = "0.3" [dev-dependencies] +# The examples use on a new feature of Bytes which should be available in 0.5.0 +# https://github.com/carllerche/bytes/pull/185 +bytes = { git = "https://github.com/carllerche/bytes", rev = "ae1b454" } lazy_static = "1" rand = "0.4" tempdir = "0.3" diff --git a/src/lib.rs b/src/lib.rs index 3873f4a18b..07e84c1272 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,6 @@ #![deny(missing_debug_implementations)] // External crates -extern crate bytes; #[macro_use] extern crate bitflags; #[macro_use] diff --git a/src/sys/aio.rs b/src/sys/aio.rs index 5cb3b81850..8a958c8411 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -21,16 +21,15 @@ //! not support this for all filesystems and devices. use {Error, Result}; -use bytes::{Bytes, BytesMut}; use errno::Errno; use std::os::unix::io::RawFd; use libc::{c_void, off_t, size_t}; use libc; +use std::borrow::{Borrow, BorrowMut}; use std::fmt; use std::fmt::Debug; use std::marker::PhantomData; use std::mem; -use std::ops::Deref; use std::ptr::{null, null_mut}; use std::thread; use sys::signal::*; @@ -93,46 +92,38 @@ pub enum AioCancelStat { /// Owns (uniquely or shared) a memory buffer to keep it from `Drop`ing while /// the kernel has a pointer to it. -#[derive(Clone, Debug)] pub enum Buffer<'a> { /// No buffer to own. /// /// Used for operations like `aio_fsync` that have no data, or for unsafe /// operations that work with raw pointers. None, - /// Immutable shared ownership `Bytes` object - // Must use out-of-line allocation so the address of the data will be - // stable. `Bytes` and `BytesMut` sometimes dynamically allocate a buffer, - // and sometimes inline the data within the struct itself. - Bytes(Bytes), - /// Mutable uniquely owned `BytesMut` object - BytesMut(BytesMut), /// Keeps a reference to a slice - Phantom(PhantomData<&'a mut [u8]>) + Phantom(PhantomData<&'a mut [u8]>), + /// Generic thing that keeps a buffer from dropping + BoxedSlice(Box>), + /// Generic thing that keeps a mutable buffer from dropping + BoxedMutSlice(Box>), } -impl<'a> Buffer<'a> { - /// Return the inner `Bytes`, if any - pub fn bytes(&self) -> Option<&Bytes> { - match *self { - Buffer::Bytes(ref x) => Some(x), - _ => None - } - } - - /// Return the inner `BytesMut`, if any - pub fn bytes_mut(&self) -> Option<&BytesMut> { - match *self { - Buffer::BytesMut(ref x) => Some(x), - _ => None - } - } - - /// Is this `Buffer` `None`? - pub fn is_none(&self) -> bool { - match *self { - Buffer::None => true, - _ => false, +impl<'a> Debug for Buffer<'a> { + // Note: someday it may be possible to Derive Debug for a trait object, but + // not today. + // https://github.com/rust-lang/rust/issues/1563 + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + &Buffer::None => write!(fmt, "None"), + &Buffer::Phantom(p) => p.fmt(fmt), + &Buffer::BoxedSlice(ref bs) => { + let borrowed : &Borrow<[u8]> = bs.borrow(); + write!(fmt, "BoxedSlice({:?})", + borrowed as *const Borrow<[u8]>) + }, + &Buffer::BoxedMutSlice(ref bms) => { + let borrowed : &BorrowMut<[u8]> = bms.borrow(); + write!(fmt, "BoxedMutSlice({:?})", + borrowed as *const BorrowMut<[u8]>) + } } } } @@ -150,7 +141,7 @@ pub struct AioCb<'a> { /// Optionally keeps a reference to the data. /// /// Used to keep buffers from `Drop`'ing, and may be returned once the - /// `AioCb` is completed by `into_buffer`. + /// `AioCb` is completed by [`buffer`](#method.buffer). buffer: Buffer<'a> } @@ -166,6 +157,50 @@ impl<'a> AioCb<'a> { x } + /// Remove the inner boxed slice, if any, and return it. + /// + /// The returned value will be the argument that was passed to + /// `from_boxed_slice` when this `AioCb` was created. + /// + /// It is an error to call this method while the `AioCb` is still in + /// progress. + pub fn boxed_slice(&mut self) -> Option>> { + assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress. Did you forget to call aio_return?"); + if let Buffer::BoxedSlice(_) = self.buffer { + let mut oldbuffer = Buffer::None; + mem::swap(&mut self.buffer, &mut oldbuffer); + if let Buffer::BoxedSlice(inner) = oldbuffer { + Some(inner) + } else { + unreachable!(); + } + } else { + None + } + } + + /// Remove the inner boxed mutable slice, if any, and return it. + /// + /// The returned value will be the argument that was passed to + /// `from_boxed_mut_slice` when this `AioCb` was created. + /// + /// It is an error to call this method while the `AioCb` is still in + /// progress. + pub fn boxed_mut_slice(&mut self) -> Option>> { + assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress. Did you forget to call aio_return?"); + if let Buffer::BoxedMutSlice(_) = self.buffer { + let mut oldbuffer = Buffer::None; + mem::swap(&mut self.buffer, &mut oldbuffer); + if let Buffer::BoxedMutSlice(inner) = oldbuffer { + Some(inner) + } else { + unreachable!(); + } + } else { + None + } + } + /// Returns the underlying file descriptor associated with the `AioCb` pub fn fd(&self) -> RawFd { self.aiocb.aio_fildes @@ -187,7 +222,7 @@ impl<'a> AioCb<'a> { /// # Examples /// /// Create an `AioCb` from a raw file descriptor and use it for an - /// [`fsync`](#method.from_bytes_mut) operation. + /// [`fsync`](#method.fsync) operation. /// /// ``` /// # extern crate tempfile; @@ -300,17 +335,19 @@ impl<'a> AioCb<'a> { } } - /// Constructs a new `AioCb` from a `Bytes` object. + /// The safest and most flexible way to create an `AioCb`. /// - /// Unlike `from_slice`, this method returns a structure suitable for + /// Unlike [`from_slice`], this method returns a structure suitable for /// placement on the heap. It may be used for write operations, but not - /// read operations. + /// read operations. Unlike `from_ptr`, this method will ensure that the + /// buffer doesn't `drop` while the kernel is still processing it. Any + /// object that can be borrowed as a boxed slice will work. /// /// # Parameters /// /// * `fd`: File descriptor. Required for all aio functions. /// * `offs`: File offset - /// * `buf`: A shared memory buffer + /// * `buf`: A boxed slice-like object /// * `prio`: If POSIX Prioritized IO is supported, then the /// operation will be prioritized at the process's /// priority level minus `prio` @@ -322,15 +359,13 @@ impl<'a> AioCb<'a> { /// /// # Examples /// - /// Create an `AioCb` from a `Bytes` object and use it for writing. + /// Create an `AioCb` from a Vector and use it for writing /// /// ``` - /// # extern crate bytes; /// # extern crate tempfile; /// # extern crate nix; /// # use nix::errno::Errno; /// # use nix::Error; - /// # use bytes::Bytes; /// # use nix::sys::aio::*; /// # use nix::sys::signal::SigevNotify; /// # use std::{thread, time}; @@ -338,11 +373,12 @@ impl<'a> AioCb<'a> { /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; /// # fn main() { - /// let wbuf = Bytes::from(&b"CDEF"[..]); + /// let wbuf = Box::new(Vec::from("CDEF")); + /// let expected_len = wbuf.len(); /// let mut f = tempfile().unwrap(); - /// let mut aiocb = AioCb::from_bytes( f.as_raw_fd(), + /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), /// 2, //offset - /// wbuf.clone(), + /// wbuf, /// 0, //priority /// SigevNotify::SigevNone, /// LioOpcode::LIO_NOP); @@ -350,72 +386,103 @@ impl<'a> AioCb<'a> { /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) { /// thread::sleep(time::Duration::from_millis(10)); /// } - /// assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len()); + /// assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len); + /// # } + /// ``` + /// + /// Create an `AioCb` from a `Bytes` object + /// + /// ``` + /// # extern crate bytes; + /// # extern crate tempfile; + /// # extern crate nix; + /// # use bytes::Bytes; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// # fn main() { + /// let wbuf = Box::new(Bytes::from(&b"CDEF"[..])); + /// let mut f = tempfile().unwrap(); + /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), + /// 2, //offset + /// wbuf, + /// 0, //priority + /// SigevNotify::SigevNone, + /// LioOpcode::LIO_NOP); /// # } /// ``` - pub fn from_bytes(fd: RawFd, offs: off_t, buf: Bytes, + /// + /// If a library needs to work with buffers that aren't `Box`ed, it can + /// create a `Box`ed container for use with this method. Here's an example + /// using an un`Box`ed `Bytes` object. + /// + /// ``` + /// # extern crate bytes; + /// # extern crate tempfile; + /// # extern crate nix; + /// # use bytes::Bytes; + /// # use nix::sys::aio::*; + /// # use nix::sys::signal::SigevNotify; + /// # use std::borrow::Borrow; + /// # use std::os::unix::io::AsRawFd; + /// # use tempfile::tempfile; + /// struct BytesContainer(Bytes); + /// impl Borrow<[u8]> for BytesContainer { + /// fn borrow(&self) -> &[u8] { + /// self.0.as_ref() + /// } + /// } + /// fn main() { + /// let wbuf = Bytes::from(&b"CDEF"[..]); + /// let boxed_wbuf = Box::new(BytesContainer(wbuf)); + /// let mut f = tempfile().unwrap(); + /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), + /// 2, //offset + /// boxed_wbuf, + /// 0, //priority + /// SigevNotify::SigevNone, + /// LioOpcode::LIO_NOP); + /// } + /// ``` + /// + /// [`from_slice`]: #method.from_slice + pub fn from_boxed_slice(fd: RawFd, offs: off_t, buf: Box>, prio: libc::c_int, sigev_notify: SigevNotify, opcode: LioOpcode) -> AioCb<'a> { - // Small BytesMuts are stored inline. Inline storage is a no-no, - // because we store a pointer to the buffer in the AioCb before - // returning the Buffer by move. If the buffer is too small, reallocate - // it to force out-of-line storage - // TODO: Add an is_inline() method to BytesMut, and a way to explicitly - // force out-of-line allocation. - let buf2 = if buf.len() < 64 { - // Reallocate to force out-of-line allocation - let mut ool = Bytes::with_capacity(64); - ool.extend_from_slice(buf.deref()); - ool - } else { - buf - }; let mut a = AioCb::common_init(fd, prio, sigev_notify); + { + let borrowed : &Borrow<[u8]> = buf.borrow(); + let slice : &[u8] = borrowed.borrow(); + a.aio_nbytes = slice.len() as size_t; + a.aio_buf = slice.as_ptr() as *mut c_void; + } a.aio_offset = offs; - a.aio_nbytes = buf2.len() as size_t; - a.aio_buf = buf2.as_ptr() as *mut c_void; a.aio_lio_opcode = opcode as libc::c_int; AioCb { aiocb: a, mutable: false, in_progress: false, - buffer: Buffer::Bytes(buf2), + buffer: Buffer::BoxedSlice(buf), } } - /// Constructs a new `AioCb` from a `BytesMut` object. - /// - /// Unlike `from_mut_slice`, this method returns a structure suitable for - /// placement on the heap. It may be used for both reads and writes. - /// - /// # Parameters + /// The safest and most flexible way to create an `AioCb` for reading. /// - /// * `fd`: File descriptor. Required for all aio functions. - /// * `offs`: File offset - /// * `buf`: An owned memory buffer - /// * `prio`: If POSIX Prioritized IO is supported, then the - /// operation will be prioritized at the process's - /// priority level minus `prio` - /// * `sigev_notify`: Determines how you will be notified of event - /// completion. - /// * `opcode`: This field is only used for `lio_listio`. It - /// determines which operation to use for this individual - /// aiocb + /// Like [`from_boxed_slice`], but the slice is a mutable one. More + /// flexible than [`from_mut_slice`], because a wide range of objects can be + /// used. /// /// # Examples /// - /// Create an `AioCb` from a `BytesMut` and use it for reading. In this - /// example the `AioCb` is stack-allocated, so we could've used - /// `from_mut_slice` instead. + /// Create an `AioCb` from a Vector and use it for reading /// /// ``` - /// # extern crate bytes; /// # extern crate tempfile; /// # extern crate nix; /// # use nix::errno::Errno; /// # use nix::Error; - /// # use bytes::BytesMut; /// # use nix::sys::aio::*; /// # use nix::sys::signal::SigevNotify; /// # use std::{thread, time}; @@ -425,10 +492,10 @@ impl<'a> AioCb<'a> { /// # fn main() { /// const INITIAL: &[u8] = b"abcdef123456"; /// const LEN: usize = 4; - /// let rbuf = BytesMut::from(vec![0; LEN]); + /// let rbuf = Box::new(vec![0; LEN]); /// let mut f = tempfile().unwrap(); /// f.write_all(INITIAL).unwrap(); - /// let mut aiocb = AioCb::from_bytes_mut( f.as_raw_fd(), + /// let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(), /// 2, //offset /// rbuf, /// 0, //priority @@ -439,33 +506,33 @@ impl<'a> AioCb<'a> { /// thread::sleep(time::Duration::from_millis(10)); /// } /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN); - /// let buffer = aiocb.into_buffer(); + /// let mut buffer = aiocb.boxed_mut_slice().unwrap(); /// const EXPECT: &[u8] = b"cdef"; - /// assert_eq!(buffer.bytes_mut().unwrap(), EXPECT); + /// assert_eq!(buffer.borrow_mut(), EXPECT); /// # } /// ``` - pub fn from_bytes_mut(fd: RawFd, offs: off_t, buf: BytesMut, - prio: libc::c_int, sigev_notify: SigevNotify, - opcode: LioOpcode) -> AioCb<'a> { - let mut buf2 = if buf.len() < 64 { - // Reallocate to force out-of-line allocation - let mut ool = BytesMut::with_capacity(64); - ool.extend_from_slice(buf.deref()); - ool - } else { - buf - }; + /// + /// [`from_boxed_slice`]: #method.from_boxed_slice + /// [`from_mut_slice`]: #method.from_mut_slice + pub fn from_boxed_mut_slice(fd: RawFd, offs: off_t, + mut buf: Box>, + prio: libc::c_int, sigev_notify: SigevNotify, + opcode: LioOpcode) -> AioCb<'a> { let mut a = AioCb::common_init(fd, prio, sigev_notify); + { + let borrowed : &mut BorrowMut<[u8]> = buf.borrow_mut(); + let slice : &mut [u8] = borrowed.borrow_mut(); + a.aio_nbytes = slice.len() as size_t; + a.aio_buf = slice.as_mut_ptr() as *mut c_void; + } a.aio_offset = offs; - a.aio_nbytes = buf2.len() as size_t; - a.aio_buf = buf2.as_mut_ptr() as *mut c_void; a.aio_lio_opcode = opcode as libc::c_int; AioCb { aiocb: a, mutable: true, in_progress: false, - buffer: Buffer::BytesMut(buf2), + buffer: Buffer::BoxedMutSlice(buf), } } @@ -475,7 +542,7 @@ impl<'a> AioCb<'a> { /// placement on the heap. It may be used for both reads and writes. Due /// to its unsafety, this method is not recommended. It is most useful when /// heap allocation is required but for some reason the data cannot be - /// converted to a `BytesMut`. + /// wrapped in a `struct` that implements `BorrowMut<[u8]>` /// /// # Parameters /// @@ -519,7 +586,8 @@ impl<'a> AioCb<'a> { /// Unlike `from_slice`, this method returns a structure suitable for /// placement on the heap. Due to its unsafety, this method is not /// recommended. It is most useful when heap allocation is required but for - /// some reason the data cannot be converted to a `Bytes`. + /// some reason the data cannot be wrapped in a `struct` that implements + /// `Borrow<[u8]>` /// /// # Parameters /// @@ -624,19 +692,6 @@ impl<'a> AioCb<'a> { } } - /// Consumes the `aiocb` and returns its inner `Buffer`, if any. - /// - /// This method is especially useful when reading into a `BytesMut`, because - /// that type does not support shared ownership. - pub fn into_buffer(mut self) -> Buffer<'static> { - let buf = self.buffer(); - match buf { - Buffer::BytesMut(x) => Buffer::BytesMut(x), - Buffer::Bytes(x) => Buffer::Bytes(x), - _ => Buffer::None - } - } - fn common_init(fd: RawFd, prio: libc::c_int, sigev_notify: SigevNotify) -> libc::aiocb { // Use mem::zeroed instead of explicitly zeroing each field, because the @@ -670,12 +725,10 @@ impl<'a> AioCb<'a> { /// result. /// /// ``` - /// # extern crate bytes; /// # extern crate tempfile; /// # extern crate nix; /// # use nix::errno::Errno; /// # use nix::Error; - /// # use bytes::Bytes; /// # use nix::sys::aio::*; /// # use nix::sys::signal::SigevNotify; /// # use std::{thread, time}; @@ -683,11 +736,11 @@ impl<'a> AioCb<'a> { /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; /// # fn main() { - /// let wbuf = Bytes::from(&b"CDEF"[..]); + /// let wbuf = b"CDEF"; /// let mut f = tempfile().unwrap(); - /// let mut aiocb = AioCb::from_bytes( f.as_raw_fd(), + /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), /// 2, //offset - /// wbuf.clone(), + /// &wbuf[..], /// 0, //priority /// SigevNotify::SigevNone, /// LioOpcode::LIO_NOP); @@ -871,12 +924,10 @@ impl<'a> AioCb<'a> { /// descriptor. /// /// ``` -/// # extern crate bytes; /// # extern crate tempfile; /// # extern crate nix; /// # use nix::errno::Errno; /// # use nix::Error; -/// # use bytes::Bytes; /// # use nix::sys::aio::*; /// # use nix::sys::signal::SigevNotify; /// # use std::{thread, time}; @@ -884,11 +935,11 @@ impl<'a> AioCb<'a> { /// # use std::os::unix::io::AsRawFd; /// # use tempfile::tempfile; /// # fn main() { -/// let wbuf = Bytes::from(&b"CDEF"[..]); +/// let wbuf = b"CDEF"; /// let mut f = tempfile().unwrap(); -/// let mut aiocb = AioCb::from_bytes( f.as_raw_fd(), +/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(), /// 2, //offset -/// wbuf.clone(), +/// &wbuf[..], /// 0, //priority /// SigevNotify::SigevNone, /// LioOpcode::LIO_NOP); diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index f11c7ef939..0f7d71e5c1 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -323,20 +323,21 @@ fn test_write() { assert!(rbuf == EXPECT); } -// Tests `AioCb::from_bytes` +// Tests `AioCb::from_boxed_slice` with `Bytes` #[test] #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] fn test_write_bytes() { const INITIAL: &[u8] = b"abcdef123456"; - let wbuf = Bytes::from(&b"CDEF"[..]); + let wbuf = Box::new(Bytes::from(&b"CDEF"[..])); let mut rbuf = Vec::new(); const EXPECT: &[u8] = b"abCDEF123456"; + let expected_len = wbuf.len(); let mut f = tempfile().unwrap(); f.write_all(INITIAL).unwrap(); - let mut aiocb = AioCb::from_bytes( f.as_raw_fd(), + let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(), 2, //offset - wbuf.clone(), + wbuf, 0, //priority SigevNotify::SigevNone, LioOpcode::LIO_NOP); @@ -344,7 +345,7 @@ fn test_write_bytes() { let err = poll_aio(&mut aiocb); assert!(err == Ok(())); - assert!(aiocb.aio_return().unwrap() as usize == wbuf.len()); + assert!(aiocb.aio_return().unwrap() as usize == expected_len); f.seek(SeekFrom::Start(0)).unwrap(); let len = f.read_to_end(&mut rbuf).unwrap(); @@ -352,46 +353,17 @@ fn test_write_bytes() { assert!(rbuf == EXPECT); } -// Tests `AioCb::from_bytes_mut` -#[test] -#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] -fn test_read_bytes_mut_big() { - const INITIAL: &[u8] = b"abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678"; - // rbuf needs to be larger than 32 bytes (64 on 32-bit systems) so - // BytesMut::clone is implemented by reference. - let rbuf = BytesMut::from(vec![0; 70]); - const EXPECT: &[u8] = b"cdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh"; - let mut f = tempfile().unwrap(); - f.write_all(INITIAL).unwrap(); - - let mut aiocb = AioCb::from_bytes_mut( f.as_raw_fd(), - 2, //offset - rbuf, - 0, //priority - SigevNotify::SigevNone, - LioOpcode::LIO_NOP); - aiocb.read().unwrap(); - - let err = poll_aio(&mut aiocb); - assert_eq!(err, Ok(())); - assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); - let buffer = aiocb.into_buffer(); - assert_eq!(buffer.bytes_mut().unwrap(), EXPECT); -} - -// Tests reallocation in `AioCb::from_bytes_mut` +// Tests `AioCb::from_boxed_mut_slice` with `BytesMut` #[test] #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] fn test_read_bytes_mut_small() { const INITIAL: &[u8] = b"abcdef"; - // rbuf needs to be no more than 32 bytes (64 on 32-bit systems) so - // BytesMut::clone is implemented inline. - let rbuf = BytesMut::from(vec![0; 4]); + let rbuf = Box::new(BytesMut::from(vec![0; 4])); const EXPECT: &[u8] = b"cdef"; let mut f = tempfile().unwrap(); f.write_all(INITIAL).unwrap(); - let mut aiocb = AioCb::from_bytes_mut( f.as_raw_fd(), + let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(), 2, //offset rbuf, 0, //priority @@ -402,8 +374,8 @@ fn test_read_bytes_mut_small() { let err = poll_aio(&mut aiocb); assert_eq!(err, Ok(())); assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); - let buffer = aiocb.into_buffer(); - assert_eq!(buffer.bytes_mut().unwrap(), EXPECT); + let buffer = aiocb.boxed_mut_slice().unwrap(); + assert_eq!(buffer.borrow(), EXPECT); } // Tests `AioCb::from_ptr`