-
Notifications
You must be signed in to change notification settings - Fork 308
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement creating SliceArg from arbitrary Dimension #909
Conversation
I don't really know the design of the existing code enough to review. Why is there a new type parameter on SliceInfo? 🙂 |
I can review this when I have time. I am also curious about the new type parameter. [Edit: Oh, I think I understand why this is necessary. I'm not sure that providing more ways to manually construct Fwiw, I wrote up some of the reasoning behind the current design here: Implementing Improved Slicing in |
@jturner314 Thank you very much for reviewing my code! I have to say that I found a much better way. And it will not make any changes to the existing code @bluss —— Why don't we directly create the |
src/dimension/dimension_trait.rs
Outdated
/// | ||
/// Panics if conversion failed. | ||
#[doc(hidden)] | ||
fn slice_arg_from(index: &[SliceOrIndex]) -> &Self::SliceArg ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm unsure if this should be a method on Dimension. It could be, it's a bit wonky? This is a hidden method so it is then not intended to be public user-facing API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method should not be listed as the first method in the Dimension trait. It is not the most important method in the trait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do something like this:
use std::convert::{TryFrom, TryInto};
pub trait TryFromRef<T: ?Sized> {
type Error;
fn try_from_ref(orig: &T) -> Result<&Self, Self::Error>;
}
impl<T: ?Sized, U: ?Sized> TryFromRef<T> for U
where
for<'a> &'a U: TryFrom<&'a T>,
{
// Once Rust has const generics, we can implement `TryFromRef` separately
// for `[SliceOrIndex]` and `[SliceOrIndex; N]`, and use
// `TryFromSliceError` for the `[SliceOrIndex; N]` case.
// Actually, we only really need to implement this trait for `N <= 6`, so we until
// Rust has const generics, we could have separate impls for each size.
type Error = ();
fn try_from_ref(orig: &T) -> Result<&Self, Self::Error> {
orig.try_into().map_err(|_| ())
}
}
pub trait Dimension {
...
type SliceArg: ?Sized + AsRef<[SliceOrIndex]> + TryFromRef<[SliceOrIndex]>;
...
}
although this is pretty awkward too.
I took some time to think about this, and came to the following conclusions:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a couple of comments for how I think the conversion should be implemented, if we decide to add a conversion like this.
src/dimension/dimension_trait.rs
Outdated
/// | ||
/// Panics if conversion failed. | ||
#[doc(hidden)] | ||
fn slice_info_from<T, Do>(indices: &T) -> &SliceInfo<Self::SliceArg, Do> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't correct, because the Do
here is unconstrained and is not checked. Instead, we should add a method to SliceInfo
:
impl<T: ?Sized, D> SliceInfo<T, D>
where
T: AsRef<[SliceOrIndex]>,
D: Dimension,
{
pub fn for_dimensionality<E>(&self) -> Result<&SliceInfo<E::SliceArg, D>, ShapeError>
where
E: Dimension,
{
...
}
}
which makes sure that the D
is correctly preserved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For what it's worth, we could do this instead to avoid the need for Dimension::slice_arg_from
:
impl<T: ?Sized, D> SliceInfo<T, D>
where
T: AsRef<[SliceOrIndex]>,
D: Dimension,
{
pub fn for_dimensionality<'a, E>(&'a self) -> &'a SliceInfo<E::SliceArg, D>
where
E: Dimension,
&'a E::SliceArg: TryFrom<&'a [SliceOrIndex]>,
{
...
}
}
but that would make it awkward to use in generic functions because users would have to add the &'a E::SliceArg: TryFrom<&'a [SliceOrIndex]>
bound to their functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right, function should be put in SliceInfo. But I think it seems difficult to move slice_arg_from out of Dimension. try_into()
needs to ensure that SliceArg implements From<&[SliceOrIndex]>. I think we should avoid adding additional restrictions on SliceArg.
I think it might be difficult. If we implement |
Oh, I meant that it would be possible to create a I've rebased #570 off the latest |
IIUC, #570 takes over this use case |
Fix #892
I added a field named in_dim to SliceInfo to indicate the entire length of the incides, which is the length of the SliceArg to be generated. Then the following implementation is done in slice.rs:
In this way, not only IxDyn, but SliceArg of other dimensions can also be generated from AsRef<[SliceOrIndex]>.
Then
Impl<T, Do> AsRef<SliceInfo<[SliceOrIndex], Do, IxDyn>> for SliceInfo<T, Do, $dim>
is to achieve the conversion of other dimensions to IxDyn