use error::{ShapeError, ErrorKind};
use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeTo};
use std::fmt;
use std::marker::PhantomData;
use super::Dimension;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Slice {
pub start: isize,
pub end: Option<isize>,
pub step: isize,
}
impl Slice {
pub fn new(start: isize, end: Option<isize>, step: isize) -> Slice {
debug_assert_ne!(step, 0, "Slice::new: step must be nonzero");
Slice {
start,
end,
step,
}
}
#[inline]
pub fn step_by(self, step: isize) -> Self {
debug_assert_ne!(step, 0, "Slice::step_by: step must be nonzero");
Slice { step: self.step * step, ..self }
}
}
macro_rules! impl_slice_from_index_type {
($index:ty) => {
impl From<Range<$index>> for Slice {
#[inline]
fn from(r: Range<$index>) -> Slice {
Slice {
start: r.start as isize,
end: Some(r.end as isize),
step: 1,
}
}
}
impl From<RangeFrom<$index>> for Slice {
#[inline]
fn from(r: RangeFrom<$index>) -> Slice {
Slice {
start: r.start as isize,
end: None,
step: 1,
}
}
}
impl From<RangeTo<$index>> for Slice {
#[inline]
fn from(r: RangeTo<$index>) -> Slice {
Slice {
start: 0,
end: Some(r.end as isize),
step: 1,
}
}
}
}
}
impl_slice_from_index_type!(isize);
impl_slice_from_index_type!(usize);
impl_slice_from_index_type!(i32);
impl From<RangeFull> for Slice {
#[inline]
fn from(_: RangeFull) -> Slice {
Slice {
start: 0,
end: None,
step: 1,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum SliceOrIndex {
Slice {
start: isize,
end: Option<isize>,
step: isize,
},
Index(isize),
}
copy_and_clone!{SliceOrIndex}
impl SliceOrIndex {
pub fn is_slice(&self) -> bool {
match self {
&SliceOrIndex::Slice { .. } => true,
_ => false,
}
}
pub fn is_index(&self) -> bool {
match self {
&SliceOrIndex::Index(_) => true,
_ => false,
}
}
#[inline]
pub fn step_by(self, step: isize) -> Self {
debug_assert_ne!(step, 0, "SliceOrIndex::step_by: step must be nonzero");
match self {
SliceOrIndex::Slice {
start,
end,
step: orig_step,
} => SliceOrIndex::Slice {
start,
end,
step: orig_step * step,
},
SliceOrIndex::Index(s) => SliceOrIndex::Index(s),
}
}
}
impl fmt::Display for SliceOrIndex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SliceOrIndex::Index(index) => write!(f, "{}", index)?,
SliceOrIndex::Slice { start, end, step } => {
if start != 0 {
write!(f, "{}", start)?;
}
write!(f, "..")?;
if let Some(i) = end {
write!(f, "{}", i)?;
}
if step != 1 {
write!(f, ";{}", step)?;
}
}
}
Ok(())
}
}
impl From<Slice> for SliceOrIndex {
#[inline]
fn from(s: Slice) -> SliceOrIndex {
SliceOrIndex::Slice {
start: s.start,
end: s.end,
step: s.step,
}
}
}
macro_rules! impl_sliceorindex_from_index_type {
($index:ty) => {
impl From<$index> for SliceOrIndex {
#[inline]
fn from(r: $index) -> SliceOrIndex {
SliceOrIndex::Index(r as isize)
}
}
impl From<Range<$index>> for SliceOrIndex {
#[inline]
fn from(r: Range<$index>) -> SliceOrIndex {
SliceOrIndex::Slice {
start: r.start as isize,
end: Some(r.end as isize),
step: 1,
}
}
}
impl From<RangeFrom<$index>> for SliceOrIndex {
#[inline]
fn from(r: RangeFrom<$index>) -> SliceOrIndex {
SliceOrIndex::Slice {
start: r.start as isize,
end: None,
step: 1,
}
}
}
impl From<RangeTo<$index>> for SliceOrIndex {
#[inline]
fn from(r: RangeTo<$index>) -> SliceOrIndex {
SliceOrIndex::Slice {
start: 0,
end: Some(r.end as isize),
step: 1,
}
}
}
}
}
impl_sliceorindex_from_index_type!(isize);
impl_sliceorindex_from_index_type!(usize);
impl_sliceorindex_from_index_type!(i32);
impl From<RangeFull> for SliceOrIndex {
#[inline]
fn from(_: RangeFull) -> SliceOrIndex {
SliceOrIndex::Slice {
start: 0,
end: None,
step: 1,
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct SliceInfo<T: ?Sized, D: Dimension> {
out_dim: PhantomData<D>,
indices: T,
}
impl<T: ?Sized, D> Deref for SliceInfo<T, D>
where
D: Dimension,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.indices
}
}
impl<T, D> SliceInfo<T, D>
where
D: Dimension,
{
#[doc(hidden)]
pub unsafe fn new_unchecked(indices: T, out_dim: PhantomData<D>) -> SliceInfo<T, D> {
SliceInfo {
out_dim: out_dim,
indices: indices,
}
}
}
impl<T, D> SliceInfo<T, D>
where
T: AsRef<[SliceOrIndex]>,
D: Dimension,
{
pub fn new(indices: T) -> Result<SliceInfo<T, D>, ShapeError> {
if let Some(ndim) = D::NDIM {
if ndim != indices.as_ref().iter().filter(|s| s.is_slice()).count() {
return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
}
}
Ok(SliceInfo {
out_dim: PhantomData,
indices: indices,
})
}
}
impl<T: ?Sized, D> SliceInfo<T, D>
where
T: AsRef<[SliceOrIndex]>,
D: Dimension,
{
pub fn out_ndim(&self) -> usize {
D::NDIM.unwrap_or_else(|| {
self.indices
.as_ref()
.iter()
.filter(|s| s.is_slice())
.count()
})
}
}
impl<T, D> AsRef<[SliceOrIndex]> for SliceInfo<T, D>
where
T: AsRef<[SliceOrIndex]>,
D: Dimension,
{
fn as_ref(&self) -> &[SliceOrIndex] {
self.indices.as_ref()
}
}
impl<T, D> AsRef<SliceInfo<[SliceOrIndex], D>> for SliceInfo<T, D>
where
T: AsRef<[SliceOrIndex]>,
D: Dimension,
{
fn as_ref(&self) -> &SliceInfo<[SliceOrIndex], D> {
unsafe {
&*(self.indices.as_ref() as *const [SliceOrIndex]
as *const SliceInfo<[SliceOrIndex], D>)
}
}
}
impl<T, D> Copy for SliceInfo<T, D>
where
T: Copy,
D: Dimension,
{
}
impl<T, D> Clone for SliceInfo<T, D>
where
T: Clone,
D: Dimension,
{
fn clone(&self) -> Self {
SliceInfo {
out_dim: PhantomData,
indices: self.indices.clone(),
}
}
}
#[doc(hidden)]
pub trait SliceNextDim<D1, D2> {
fn next_dim(&self, PhantomData<D1>) -> PhantomData<D2>;
}
impl<D1: Dimension> SliceNextDim<D1, D1::Larger> for Slice {
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
PhantomData
}
}
macro_rules! impl_slicenextdim_for_index_type {
($index:ty) => {
impl<D1: Dimension> SliceNextDim<D1, D1> for $index {
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1> {
PhantomData
}
}
impl<D1: Dimension> SliceNextDim<D1, D1::Larger> for Range<$index> {
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
PhantomData
}
}
impl<D1: Dimension> SliceNextDim<D1, D1::Larger> for RangeFrom<$index> {
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
PhantomData
}
}
impl<D1: Dimension> SliceNextDim<D1, D1::Larger> for RangeTo<$index> {
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
PhantomData
}
}
}
}
impl_slicenextdim_for_index_type!(isize);
impl_slicenextdim_for_index_type!(usize);
impl_slicenextdim_for_index_type!(i32);
impl<D1: Dimension> SliceNextDim<D1, D1::Larger> for RangeFull {
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
PhantomData
}
}
#[macro_export]
macro_rules! s(
(@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr) => {
match $r {
r => {
let out_dim = $crate::SliceNextDim::next_dim(&r, $dim);
unsafe {
$crate::SliceInfo::new_unchecked(
[$($stack)* s!(@convert r, $s)],
out_dim,
)
}
}
}
};
(@parse $dim:expr, [$($stack:tt)*] $r:expr) => {
match $r {
r => {
let out_dim = $crate::SliceNextDim::next_dim(&r, $dim);
unsafe {
$crate::SliceInfo::new_unchecked(
[$($stack)* s!(@convert r)],
out_dim,
)
}
}
}
};
(@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => {
match $r {
r => {
let out_dim = $crate::SliceNextDim::next_dim(&r, $dim);
unsafe {
$crate::SliceInfo::new_unchecked(
[$($stack)* s!(@convert r, $s)],
out_dim,
)
}
}
}
};
(@parse $dim:expr, [$($stack:tt)*] $r:expr ,) => {
match $r {
r => {
let out_dim = $crate::SliceNextDim::next_dim(&r, $dim);
unsafe {
$crate::SliceInfo::new_unchecked(
[$($stack)* s!(@convert r)],
out_dim,
)
}
}
}
};
(@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => {
match $r {
r => {
s![@parse
$crate::SliceNextDim::next_dim(&r, $dim),
[$($stack)* s!(@convert r, $s),]
$($t)*
]
}
}
};
(@parse $dim:expr, [$($stack:tt)*] $r:expr, $($t:tt)*) => {
match $r {
r => {
s![@parse
$crate::SliceNextDim::next_dim(&r, $dim),
[$($stack)* s!(@convert r),]
$($t)*
]
}
}
};
(@convert $r:expr) => {
<$crate::SliceOrIndex as ::std::convert::From<_>>::from($r)
};
(@convert $r:expr, $s:expr) => {
<$crate::SliceOrIndex as ::std::convert::From<_>>::from($r).step_by($s as isize)
};
($($t:tt)*) => {
&*&s![@parse ::std::marker::PhantomData::<$crate::Ix0>, [] $($t)*]
};
);