diff --git a/.travis.yml b/.travis.yml index 9b652c0..f4dff2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,8 @@ env: before_install: . vendor/bindgen/ci/before_install.sh rust: - nightly + - beta + - stable cache: cargo matrix: allow_failures: diff --git a/Cargo.toml b/Cargo.toml index bb592ad..b21978e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ibverbs" -version = "0.2.4" +version = "0.3.0" description = "Bindings for RDMA ibverbs through rdma-core" readme = "README.md" diff --git a/src/lib.rs b/src/lib.rs index f1cea9d..3068327 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,6 @@ //! [1]: http://www.rdmamojo.com/2012/05/18/libibverbs/ #![deny(missing_docs)] -#![feature(slice_get_slice)] use std::marker::PhantomData; use std::ptr; @@ -96,6 +95,10 @@ pub use ffi::IBV_ACCESS_REMOTE_READ; /// Enable Remote Atomic Operation Access (if supported). pub use ffi::IBV_ACCESS_REMOTE_ATOMIC; +/// Because `std::slice::SliceIndex` is still unstable, we follow @alexcrichton's suggestion in +/// https://github.com/rust-lang/rust/issues/35729 and implement it ourselves. +mod sliceindex; + /// Get list of available RDMA devices. /// /// # Errors @@ -1082,9 +1085,9 @@ impl<'res> QueuePair<'res> { range: R, wr_id: u64) -> io::Result<()> - where R: std::slice::SliceIndex<[T], Output = [T]> + where R: sliceindex::SliceIndex<[T], Output = [T]> { - let range = &mr[range]; + let range = range.index(&mr); let mut sge = ffi::ibv_sge { addr: range.as_ptr() as u64, length: (mem::size_of::() * range.len()) as u32, @@ -1165,9 +1168,9 @@ impl<'res> QueuePair<'res> { range: R, wr_id: u64) -> io::Result<()> - where R: std::slice::SliceIndex<[T], Output = [T]> + where R: sliceindex::SliceIndex<[T], Output = [T]> { - let range = &mr[range]; + let range = range.index(&mr); let mut sge = ffi::ibv_sge { addr: range.as_ptr() as u64, length: (mem::size_of::() * range.len()) as u32, diff --git a/src/sliceindex.rs b/src/sliceindex.rs new file mode 100644 index 0000000..0215836 --- /dev/null +++ b/src/sliceindex.rs @@ -0,0 +1,143 @@ +use std::ops; + +pub trait SliceIndex { + /// The output type returned by methods. + type Output: ?Sized; + + /// Returns a shared reference to the output at this location, without + /// performing any bounds checking. + unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; + + /// Returns a shared reference to the output at this location, panicking + /// if out of bounds. + fn index(self, slice: &T) -> &Self::Output; +} + +impl SliceIndex<[T]> for usize { + type Output = T; + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &T { + &*slice.as_ptr().offset(self as isize) + } + + #[inline] + fn index(self, slice: &[T]) -> &T { + // NB: use intrinsic indexing + &(*slice)[self] + } +} + +#[inline(never)] +#[cold] +fn slice_index_len_fail(index: usize, len: usize) -> ! { + panic!("index {} out of range for slice of length {}", index, len); +} + +#[inline(never)] +#[cold] +fn slice_index_order_fail(index: usize, end: usize) -> ! { + panic!("slice index starts at {} but ends at {}", index, end); +} + +impl SliceIndex<[T]> for ops::Range { + type Output = [T]; + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + use std::slice::from_raw_parts; + from_raw_parts(slice.as_ptr().offset(self.start as isize), + self.end - self.start) + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_index_len_fail(self.end, slice.len()); + } + unsafe { self.get_unchecked(slice) } + } +} + +impl SliceIndex<[T]> for ops::RangeTo { + type Output = [T]; + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + (0..self.end).get_unchecked(slice) + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..self.end).index(slice) + } +} + +impl SliceIndex<[T]> for ops::RangeFrom { + type Output = [T]; + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + (self.start..slice.len()).get_unchecked(slice) + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (self.start..slice.len()).index(slice) + } +} + +impl SliceIndex<[T]> for ops::RangeFull { + type Output = [T]; + + #[inline] + unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + slice + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + slice + } +} + +// nightly only: +// +// impl SliceIndex<[T]> for ops::RangeInclusive { +// type Output = [T]; +// +// #[inline] +// unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { +// match self { +// ops::RangeInclusive::Empty { .. } => &[], +// ops::RangeInclusive::NonEmpty { start, end } => (start..end + 1).get_unchecked(slice), +// } +// } +// +// #[inline] +// fn index(self, slice: &[T]) -> &[T] { +// match self { +// ops::RangeInclusive::Empty { .. } => &[], +// ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => { +// panic!("attempted to index slice up to maximum usize"); +// } +// ops::RangeInclusive::NonEmpty { start, end } => (start..end + 1).index(slice), +// } +// } +// } +// +// impl SliceIndex<[T]> for ops::RangeToInclusive { +// type Output = [T]; +// +// #[inline] +// unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { +// (0...self.end).get_unchecked(slice) +// } +// +// #[inline] +// fn index(self, slice: &[T]) -> &[T] { +// (0...self.end).index(slice) +// } +// }