Git Product home page Git Product logo

generic-array's Introduction

Crates.io Build Status

generic-array

This crate implements a structure that can be used as a generic array type.

**Requires minumum Rust version of 1.65.0

Documentation on GH Pages may be required to view certain types on foreign crates.

Usage

Before Rust 1.51, arrays [T; N] were problematic in that they couldn't be generic with respect to the length N, so this wouldn't work:

struct Foo<N> {
    data: [i32; N],
}

Since 1.51, the below syntax is valid:

struct Foo<const N: usize> {
    data: [i32; N],
}

However, the const-generics we have as of writing this are still the minimum-viable product (min_const_generics), so many situations still result in errors, such as this example:

trait Bar {
    const LEN: usize;

    // Error: cannot perform const operation using `Self`
    fn bar(&self) -> Foo<{ Self::LEN }>;
}

generic-array defines a new trait ArrayLength and a struct GenericArray<T, N: ArrayLength>, which lets the above be implemented as:

struct Foo<N: ArrayLength> {
    data: GenericArray<i32, N>
}

trait Bar {
    type LEN: ArrayLength;
    fn bar(&self) -> Foo<Self::LEN>;
}

The ArrayLength trait is implemented for unsigned integer types from typenum crate. For example, GenericArray<T, U5> would work almost like [T; 5]:

use generic_array::typenum::U5;

struct Foo<T, N: ArrayLength> {
    data: GenericArray<T, N>
}

let foo = Foo::<i32, U5> { data: GenericArray::default() };

The arr! macro is provided to allow easier creation of literal arrays, as shown below:

let array = arr![1, 2, 3];
//  array: GenericArray<i32, typenum::U3>
assert_eq!(array[2], 3);

Feature flags

[dependencies.generic-array]
features = [
    "more_lengths",  # Expands From/Into implementation for more array lengths
    "serde",         # Serialize/Deserialize implementation
    "zeroize",       # Zeroize implementation for setting array elements to zero
    "const-default", # Compile-time const default value support via trait
    "alloc",         # Enables From/TryFrom implementations between GenericArray and Vec<T>/Box<[T]>
    "faster-hex"     # Enables internal use of the `faster-hex` crate for faster hex encoding via SIMD
]

generic-array's People

Contributors

bddap avatar cactter avatar cuviper avatar dr-emann avatar eggyal avatar fizyk20 avatar fjarri avatar gereeter avatar ia0 avatar ilyvion avatar japm48 avatar keens avatar kevaundray avatar llogiq avatar lrazovic avatar millardjn avatar narann avatar newpavlov avatar novacrazy avatar paholg avatar pratyush avatar regexident avatar rilysh avatar robbepop avatar rodrimati1992 avatar sebcrozet avatar sergiobenitez avatar tailhook avatar top-webmaster avatar twissel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

generic-array's Issues

Possible to multiply ArrayLength<T>?

Hi, I'm brand new to Rust, so I'm definitely at a the limits of my knowledge in tackling the following. I have a use-case where I would like to modify an existing library (Mat) that makes use of Unsize<[T]> to use GenericArray<T, N> instead. One of the hiccups I'm finding as I do so is that I would like to be able to construct the total size of an array (i.e. a ArrayLength<T>) based on two parameters. Perhaps code is a better way to summarize it.

Here's before:

#[derive(Clone)]
pub struct Mat<T, BUFFER, NROWS, NCOLS>
where
    BUFFER: Unsize<[T]>,
    NCOLS: Unsigned,
    NROWS: Unsigned,
    T: Copy,
{
    buffer: BUFFER,
    ty: PhantomData<[T; 0]>,
    nrows: PhantomData<NROWS>,
    ncols: PhantomData<NCOLS>,
}

impl<T, BUFFER, NROWS, NCOLS> Mat<T, BUFFER, NROWS, NCOLS>
where
    BUFFER: Unsize<[T]>,
    NROWS: Unsigned,
    NCOLS: Unsigned,
    T: Copy,
{
    #[doc(hidden)]
    pub unsafe fn new(buffer: BUFFER) -> Self {
        Mat {
            buffer,
            ty: PhantomData,
            nrows: PhantomData,
            ncols: PhantomData,
        }
    }
}

Here's (ideally) after:

#[derive(Clone)]
pub struct MatGen<T, NROWS, NCOLS>
    where
        NCOLS: ArrayLength<T>,
        NROWS: ArrayLength<T>,
        T: Copy,
{
    buffer: GenericArray<T,Prod<NCOLS,NROWS>>,
    ty: PhantomData<[T; 0]>,
    nrows: PhantomData<NROWS>,
    ncols: PhantomData<NCOLS>,
}

impl<T, NROWS, NCOLS> MatGen<T, NROWS, NCOLS>
    where
        NROWS: ArrayLength<T>,
        NCOLS: ArrayLength<T>,
        T: Copy,
{
    #[doc(hidden)]
    pub unsafe fn new(buffer: GenericArray<T,Prod<NROWS,NCOLS>>) -> Self {
        MatGen {
            buffer,
            ty: PhantomData,
            nrows: PhantomData,
            ncols: PhantomData,
        }
    }
}

I get an error in trying to implement it this way:

error[E0277]: cannot multiply `NROWS` to `NCOLS`
   --> src/lib.rs:111:5
    |
111 |     buffer: GenericArray<T,Prod<NCOLS,NROWS>>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NCOLS * NROWS`
    |
    = help: the trait `core::ops::Mul<NROWS>` is not implemented for `NCOLS`
    = help: consider adding a `where NCOLS: core::ops::Mul<NROWS>` bound

I would like to know if it's possible to do what I am sketching out here with generic-array and I just don't understand it since I'm so new to Rust. (Or maybe there are some additions that I could help make to generic-array).

By the way, I've cross-posted this to the Mat repo, since it could be my misunderstanding of how to use that crate: here.

Add a changelog

Title says all. Intended as a reminder to myself - unless anyone else wants to go through the project history and detail the changes over time?

converting from fixed size arrays?

current GenericArray doesn't support conversion from [T;n]s, but can be implemented by this way, though size of array must be specified by hand, of cause.

impl<T> From<[T; 3]> for GenericArray<T, ::typenum::U3> {
    fn from(arr: [T; 3]) -> Self {
        use core::mem::{forget, transmute_copy};
        let x = unsafe { transmute_copy(&arr) };
        forget(arr);
        x
    }
}
#[test]
fn test_from() {
    let data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)];
    let garray: GenericArray<(usize, usize, usize), ::typenum::U3> = data.into();
    assert_eq!(&data, garray.as_slice());
}
$ cargo test impls::test_from
test impls::test_from ... ok

If this is an acceptable feature, I'll submit a PR.

generic-array v0.12.1 broke builds on pre 1.27 Rust

In RustCrypto we test MSRV and recent generic-array broke our promise to support Rust 1.21 and later dues to the usage of rfold. Since you've already published v0.13.0, maybe it's worth to yank v0.12.1 and v0.12.2?

impl Default

Hi, are you ok with adding a impl Default for GenericArray<T:Default, U> ?
This is essentially the same as the current new() method, but would allow initialising nested generic arrays.

Panic safety issues

I haven't reviewed the whole library, but I noticed a bug and I wanted to mention it.

Using mem::uninitialized is tricky for general values. Is generic-array restricted to only Copy types?

The new and from_slice methods are good examples. An unintialized array is created on line 136, on the next line, _user supplied function_ T::default() is called. The problem is that the array will run its destructor if there is a panic, and we can't rule out panic since the default function is arbitrary user code.

The from_slice method has the same problem (the arbitrary user code is .clone()).

Feel free to ask any questions you may have.

mem::uninitialized is nearly always UB, switch to MaybeUninitialized or something else

mem::uninitialized is deprecated because it's basically impossible to use correctly:

From mem::uninitialized's docs:

The reason for deprecation is that the function basically cannot be used
correctly: the Rust compiler assumes that values are properly initialized.
As a consequence, calling e.g. mem::uninitialized::<bool>() causes immediate
undefined behavior for returning a bool that is not definitely either true
or false. Worse, truly uninitialized memory like what gets returned here
is special in that the compiler knows that it does not have a fixed value.
This makes it undefined behavior to have uninitialized data in a variable even
if that variable has an integer type.
(Notice that the rules around uninitialized integers are not finalized yet, but
until they are, it is advisable to avoid them.)

Obtaining &[T; N] for GenericArray<T, N>

Apologies if there's already a way to do this, but I can't figure it out.

I'd like to pass a generic array as a sized array reference. I'm able to do this using e.g. the arrayref crate but I'd like to avoid that if possible (among other things by virtue of using a macro that expands to unsafe code I'm unable to deny(unsafe_code).

Having different versions of generic-array breaks the build

Lately, there has been some breakages when crates that depend on different versions (0.7 and 0.8) of generic-array are being used in the same build. The breakage is due to cargo update not finding compatible crates. See rust-lang/cargo#4474 It's unclear to me whether the build would actually break, because it fails already when cargo update is being performed.

See also durch/rust-s3#18 and sfackler/rust-postgres#290

An example of the breaking which I'm familiar with is rust-s3 and postgres. However, these crates are fully independent and don't interact. They don't even expose any generic-array types in their API, as far as I know.

Do you know as the author of this crate any reason why different versions of this crate would break the build?

What is missing for 0.14 release?

I am just wondering what is still missing for another 0.14 release on crates.io.
The last release on crates.io for this crate was 9 months ago and since then there have been some improvements which would be nice to incorporate for other crates that are hosted at crates.io.

Issues with Eq

Hi,

I'm trying to use a GenericArray inside a struct wrapping a BtreeSet, but when I instantiate the Array with a numtype (say U1), I get compile-time errors saying that

the trait core::cmp::Eq is not implemented for generic_array::GenericArrayImplOdd<u8, ()>

For reference, here's a simplified version of my code:

struct Block<N> 
      where N: ArrayLength<u8>,
            N::ArrayType: Copy + Eq
{
    content: GenericArray<u8, N>
}

struct Container<N>
      where N: ArrayLength<u8>,
            N::ArrayType: Copy + Eq
{
    set: BTreeSet<Block<N>>
}

Trying to instantiate Container results in the above error. Any tips on how to fix this? Using just a BTreeSet (not wrapped in another struct) doesn't result in these problems (I think).

Copy trait for GenericArray not implemented

use generic_array::{GenericArray, ArrayLength};

#[derive(Clone, Copy)]
pub struct CustomBuffer<N: ArrayLength<u8>> {
    buffer: GenericArray<u8, N>,
    cursor: usize,
}

Produces following error:

error[E0204]: the trait `Copy` may not be implemented for this type
 --> src/lib.rs:7:17
  |
7 | #[derive(Clone, Copy)]
  |                 ^^^^ field `buffer` does not implement `Copy`

It seems problem is in Copy bound for N::ArrayType, but I am not able to perform a more in-depth analysis.

`arr!` with no type loops infinitely in the compiler

I'm sure this wasn't intentional, but:

rustc 1.15.0-nightly (daf8c1dfc 2016-12-05)
error: recursion limit reached while expanding the macro `arr`
 --> <anon>:5:24
  |
5 |     ($($x:expr,)*) => (arr![$($x),*])
  |                        ^^^^^^^^^^^^^
...
9 |     arr![]
  |     ------ in this macro invocation

Building with serde feature does not work with Serde versions >= 8.0

See this commit to the serde project on 11 July:
serde-rs/serde@99038b0
This removed SeqVisitor and replaced it with SeqSerializer. The impl_serde.rs code in generic-array still uses the SeqVisitor, thus does not compile with newer versions of serde.
The commit status show that is has been in effect for all of these versions of serde:
v0.8.8 v0.8.7 v0.8.6 v0.8.5 v0.8.4 v0.8.3 v0.8.2 v0.8.1 v0.8.0 v0.8.0-rc3 v0.8.0-rc2 v0.8.0-rc1,
however in the Cargo.toml file generic-array indicates preference for serde = "~0.8"

.map(_) implementation

I have a .map(_) implementation that can map a function over a slice or GenericArray<_, _> producing another GenericArray. It uses leak amplification to be (hopefully) panic-safe. We should also be able to use it to clone GenericArrays (both from slice or otherwise).

Will try to set up a PR shortly.

GenericArray::cmp() overflows stack

Using generic-array = "0.8.2" the following:

#[macro_use]
extern crate generic_array;

fn main() {
    arr![u8; 0x00].cmp(&arr![u8; 0x00]);
}

Produces output:

thread 'main' has overflowed its stack
fatal runtime error: stack overflow

Relevant portion of the backtrace:

#130855 0x000055555555a953 in core::cmp::impls::{{impl}}::cmp<generic_array::GenericArray<u8, typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>>> (self=0x7fffffffda00, other=0x7fffffffda08) at /checkout/src/libcore/cmp.rs:889
#130856 0x000055555555a913 in generic_array::impls::{{impl}}::cmp<u8,typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>> (self=0x7fffffffdab0, other=0x7fffffffdab8) at /home/cpick/.cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.8.2/src/impls.rs:63
#130857 0x000055555555a953 in core::cmp::impls::{{impl}}::cmp<generic_array::GenericArray<u8, typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>>> (self=0x7fffffffda80, other=0x7fffffffda88) at /checkout/src/libcore/cmp.rs:889
#130858 0x000055555555a913 in generic_array::impls::{{impl}}::cmp<u8,typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>> (self=0x7fffffffdab0, other=0x7fffffffdab8) at /home/cpick/.cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.8.2/src/impls.rs:63
#130859 0x000055555555a989 in delgen::main () at src/main.rs:5

ArrayLength should require typenum::Unsigned

  • All actual array lengths implement this trait
  • If ArrayLength implies it, it makes it easier for generic code to do arithmetic with array length, otherwise it must write lots of Where bounds everywhere

Placement new

Not sure how messy this would turn out, but has anybody experimented with a "GenericArray with borrowed data", where the constructor would inject a pre-allocated &mut [T; N::to_usize()]? Or in other words, exposing the applicable GenericArray methods to "views" of array slices.

Deriving Serialize & Deserialize

I'm having issues with deriving (and then using) Serialize and Deserialize on structs that contain a GenericArray. For example, the code below doesn't compile:

extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate generic_array;
extern crate bincode;

use generic_array::{GenericArray, ArrayLength};
use generic_array::typenum;

#[derive(Serialize, Deserialize)]
struct Block<N>
    where N: ArrayLength<u8>
{
    content: GenericArray<u8, N>,
}

fn main() {
    let block: Block<typenum::U1> = Block { content: arr![u8; 1] };
    bincode::serialize(&block, bincode::SizeLimit::Infinite);
}

I get the following error:

error[E0277]: the trait bound `generic_array::<unnamed>::UInt<generic_array::<unnamed>::UTerm, generic_array::<unnamed>::B1>: serde::Serialize` is not satisfied

Add 0.12.0 release tag

Can you add a release tag to github? If I spot a bug and am unable to upgrade, I'd like the option to fork locally from that release tag. Thanks!

Borrowing .map()

I have array: GenericArray<T, N> and a function f: fn(&T) -> U. I want to be able to obtain a GenericArray<U, N>.

Right now I can't see any way to do this other than array.clone().map(|x| f(&x)). It would be useful for there to be a way to do this without cloning the array. This could be added either in the form of a FunctionalSequence::map_ref method that directly implemented this functionality or through another method to convert a &GenericArray<T, N> to a GenericArray<&T, N>.

If I'm not just missing something and this functionality is judged worthwhile to add, I can give implementing it a shot.

Generic primitive type parameter with std::marker::Sized bound

Hi,
I am trying to implement something that looks like this for some tuple struct Array :

impl<T: std::marker::Sized> Array<T, U3> {
    pub fn new(x: T, y: T, z: T) -> Array<T, U3> {
        let data: GenericArray<T, U3> = arr![T; x, y, z];
        Array { data }
    }
}

Unfortunately this seems to be impossible for now and the compilers complains that arr![T; x, y, z] has no fixed size at compile-time. It even points me to the impl<T: std::marker::Sized> telling me the parameter nneds to be std::marker::Sized even if it is already bounded.
I suppose there must be a way in the macro to add this condition on T without loss of generality but I'm not familiar with procedural macros myself.
Any tip here?

Cheers,
Philippe

How to create GenericArray like [T; N]?

Standard arrays can be created with [expr; N], so long as expr is Copy.

But as far as I can tell, GenericArray can't do this, all the construction methods require exact sizes?

The other method, which I was using until now, was Default::default(), but for reasons my type can't/shouldn't be Default and in the process of changing it discovered.. there was no way to construct the arrays I needed to store it in anymore.. a blocker..

Is there a method i'm missing, or can one be added?

Mathematical operations on ArrayLength<T> possible?

I've been beating around trying to get something like this to work:

struct Foo<N: ArrayLength<i32>> {
    data: GenericArray<i32, N>,
    index: GenericArray<i32, <N as Mul<U2>>::Output>
}

Basically, I want the second array to always have double the length of the first array, using only the single N generic passed in.
Im trying to use the same kind of ops provided by typenum, but I'm getting compiler errors like:
trait N: core::ops::Mul<typenum::UInt<typenum::UInt<typenum::UTerm, typenum::B1>, typenum::B0>> not satisfied
I would have assumed that since the type ArrayLength<T> is based on the Unsigned it should already have Mul implemented inherently.
Or am I doing something really stupid?

Implement Into trait

It would be nice to have the following traits:

impl<T> Into<[T; 1]> for GenericArray<T, U1> { .. }
impl<T> Into<[T; 2]> for GenericArray<T, U2> { .. }
// up to 32, for 48 and 64

One use-case is to easily convert hashes in RustCrypto crates from GenericArray to arrays. And it would be great if you'll publish a backport for v0.12, which is currently used by RustCrypto crates.

`arr!` unsoundness

The arr! macro silently and unsoundly extends arbitrary lifetimes to 'static (playground):

fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A {
  arr![&A; a][0]
}

Design document

Recently on reddit I received a comment asking to describe the design of generic-array, and after seeing some comments asking how it works/safety/performance and about my numeric-array crate, I decided to give it a go.

Working DESIGN.md document

If anyone wants to check it out, proofread it, point out things I got wrong, missed or should expand upon, etc. feel free.

It's not very formal, but I can make it more formal if deemed necessary.

@fizyk20 what do you think?

Possible safety issue in the future

I noticed code like this

    let mut res: GenericArray<T, N> = unsafe { mem::zeroed() };
    for i in 0..N::reify() as usize {
        res[i] = T::default();
    }
    res

To the best of my knowledge, this is problematic. You are relying on an "undocumented" implementation detail that might change in the future. The drop flags might be stored out-of-band in the future in which case you can't set a non-trival T to be in a "dropped state" by zeroing its memory location.

A slightly more correct (as in relying less on undocumented implementation details) would be to use std::ptr::write instead of the assignments:

        ptr::write(&mut res[i], T::default());

But if you don't want to rely on in-band drop flags (being zeroed) you might also have to rethink panic-safety. Perhaps bluss' nodrop create could help.

equality fails when array is part of structure

I am seeing this failure with insertion into a HashMap of a GenericArray key when its part of a larger structure.

solana-labs/solana@43eaf84#diff-7665adc942e63b90927e054380a1318eR1235

I am happy to try to make a standalone test if that helps. I am on OSX,
generic-array = { version = "0.11.1", default-features = false, features = ["serde"] }
rustc 1.27.0 (3eda71b00 2018-06-19)

I am pretty sure I've seen symptoms of this in earlier versions of rust as well.

API style documentation?

(Please be advised, I am a beginner with Rust.)

I am trying to use GenericArray to implement a dynamically sized array. I am having a hard time understanding how to use GenericArray for things like:

  • Creating a new, empty array
  • Inserting new items into the array
  • Getting the length (number of items currently inside) of the array
  • Getting the size/capacity of the array as defined by ArrayLength

The design document has helped a bit but I feel pretty lost when looking at the documentation. Is there a simple way for me to understand what methods I can use with GenericArray?

Thank you for your patience with me in advance!

Is it possible to extract the length from a GenericArray?

I want to implement a Matrix type

struct Matrix<T, N, M>
    where N: ArrayLength<T>,
          M: ArrayLength<GenericArray<T, N>>{
    data: GenericArray<GenericArray<T, N>, M>
}

type Mat3x2f = Matrix<f32, U3, U2>;

I would want to implement a transpose function that would transform a Mat3x2f to a Mat2x3f.

impl<T, N, M> Matrix<T, N, M>
    where N: ArrayLength<T>,
          M: ArrayLength<GenericArray<T, N>>{
    fn tranpose(&self) -> ???
}

The problem that I have is that ArrayLength depends on the type for a GenericArray, which means I can't just write

impl<T, N, M> Matrix<T, N, M>
    where N: ArrayLength<T>,
          M: ArrayLength<GenericArray<T, N>>{
    fn tranpose(&self) -> Matrix<T, M, N>{..}
}

Any idea if that could be achieved with GenericArray?

Genric array is not copy generically

Hi!

While GenericArray<u8, L> is Copy for each length, it's not Copy for all lengths:

fn assert_is_copy<T: Copy>() {}

fn test_concrete_array_is_copy() { // this works
    assert_is_copy::<GenericArray<u8, U32>>()
}

fn test_abstract_array_is_copy<L: ArrayLength<u8>>() { // this fails to compiler
    assert_is_copy::<GenericArray<u8, L>>()
}

I am not sure if it's possible to fix this in a good way though :( What we want is a bound where T: Copy => Self::ArrayType: Copy for ArrayLength, but I think it's not possible to express this in Rust? What we might do is to introduce a second, CopyGenericArray struct with explicit T: Copy bound, but this feels pretty ugly.

Remove no_std feature

no_std feature got deprecated in typenum and this crate does not use it at all, so there is no reason to keep it.

P.S.: Also this issue will be a good reason to bump a minor version. ;)

Add compatibility to work with serde 0.9

Hi,

Would it be possible to make the crate compatible with serde 0.9? 0.9 makes life much easier for no_std users by introducing derive for Serialize and Deserialize in no_std. Thanks!

pretty print debugging

Any thoughts on traversal for pretty print debugging?

This

    let mut xs: Vec <u8, U8> = Vec::new();
    xs.push(0).unwrap();
    xs.push(2).unwrap();
    xs.push(4).unwrap();
    xs.push(6).unwrap();

Utilized via heapless vec crate, Looks like this in gdb..

1 = heapless::vec::Vec<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::u
int::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>> (
  heapless::i::Vec<generic_array::GenericArray<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum
::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>>> {
    buffer: core::mem::MaybeUninit<generic_array::GenericArray<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::ui
nt::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::b
it::B0>>> {
      uninit: (),
      value: core::mem::ManuallyDrop<generic_array::GenericArray<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::
uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum:
:bit::B0>>> = {
        value = generic_array::GenericArray<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::u
int::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>, typenum::bit::B0>> = {
          data = generic_array::GenericArrayImplEven<u8, generic_array::GenericArrayImplEven<u8, generic_array::Generi
cArrayImplEven<u8, generic_array::GenericArrayImplOdd<u8, ()>>>> = {
            parent1 = generic_array::GenericArrayImplEven<u8, generic_array::GenericArrayImplEven<u8, generic_array::G
enericArrayImplOdd<u8, ()>>> = {
              parent1 = generic_array::GenericArrayImplEven<u8, generic_array::GenericArrayImplOdd<u8, ()>> = {
                parent1 = generic_array::GenericArrayImplOdd<u8, ()> = {
                  parent1 = (),
                  parent2 = (),
                  data = 0
                },
                parent2 = generic_array::GenericArrayImplOdd<u8, ()> = {
                  parent1 = (),
                  parent2 = (),
                  data = 2
                },
                _marker = core::marker::PhantomData<u8>
              },
              parent2 = generic_array::GenericArrayImplEven<u8, generic_array::GenericArrayImplOdd<u8, ()>> = {
                parent1 = generic_array::GenericArrayImplOdd<u8, ()> = {
                  parent1 = (),
                  parent2 = (),
                  data = 4
                },
                parent2 = generic_array::GenericArrayImplOdd<u8, ()> = {
                  parent1 = (),
                  parent2 = (),
                  data = 6
                },
                _marker = core::marker::PhantomData<u8>
              },
              _marker = core::marker::PhantomData<u8>
            },
            parent2 = generic_array::GenericArrayImplEven<u8, generic_array::GenericArrayImplEven<u8, generic_array::G
enericArrayImplOdd<u8, ()>>> = {
              parent1 = generic_array::GenericArrayImplEven<u8, generic_array::GenericArrayImplOdd<u8, ()>> = {
                parent1 = generic_array::GenericArrayImplOdd<u8, ()> = {
                  parent1 = (),
                  parent2 = (),
                  data = 0
                },
                parent2 = generic_array::GenericArrayImplOdd<u8, ()> = {
                  parent1 = (),
                  parent2 = (),
                  data = 0
                },
                _marker = core::marker::PhantomData<u8>
              },
              parent2 = generic_array::GenericArrayImplEven<u8, generic_array::GenericArrayImplOdd<u8, ()>> = {
                parent1 = generic_array::GenericArrayImplOdd<u8, ()> = {
                  parent1 = (),
                  parent2 = (),
                  data = 0
                },
                parent2 = generic_array::GenericArrayImplOdd<u8, ()> = {
                  parent1 = (),
                  parent2 = (),
                  data = 0
                },
                _marker = core::marker::PhantomData<u8>
              },
              _marker = core::marker::PhantomData<u8>
            },
            _marker = core::marker::PhantomData<u8>
          }
        }
      }
    },
    len: 4
  }
)

For gdb theres a child function https://github.com/rust-lang/rust/blob/master/src/etc/gdb_rust_pretty_printing.py#L286

andI would have to do some sort of traversal of children, but the even and odd parents isnt immediately clear to me where to start iterating that in a non breaking way. Was hoping authors would have more ideas.

Default doesn't work

If I try to build:

GenericArray::<u8, U1>::default();

with rustc 1.17.0-nightly (3da40237e 2017-03-24) I get error:

error: no associated item named `default` found for type `generic_array::GenericArray<u8, typenum::UInt<typenum::UTerm, typenum::B1>>` in the current scope

GenericArray lacks a clean, obvious way to convert to &[u8]

I realize that this is somewhat redundant with the Deref impl, but using a GenericArray in a function call that takes a &[u8] is a bit awkward at the moment. You have to choose between:

foo(&*myarr);

or:

foo(&myarr[..])

or:

use std::deref::Deref;
foo(myarr.deref());

which are all somewhat ugly or unclear (especially to Rust newbies). How about aping Vec and providing a method GenericArray::as_slice(), used like:

foo(myarr.as_slice());

Concatenating two arrays

It would be really nice if there was a syntax like

join(arr1, arr2)

that produced a new array of the correct length, if both input arrays have the same type.

Doing it manually with copy_from_slice is less readable, and copy_from_slice can panic if you do it wrong, so it would be nice if there is a simpler API that doesn't panic in any scenario.

Why does ArrayLength need to be generic over the array type

I have several methods like this that take two type parameters because I'm using two different GenericArrays. The array lengths themselves should be always equal to each other.

pub fn do_something<N: ArrayLength<StructA>, P: ArrayLength<StructB>>(...) {}

Is there a reason why it is ArrayLength<T> instead of just ArrayLength, or is there some way this function can be generic over just one ArrayLength type and the other one is created from the first?

UB in Default impl of GenericArray

Today I was running cargo miri test on one of my projects that is using the generic-array crate internally. The cargo miri test runs tests of the project using the Rust MIR interpreter miri. Due to execution the tool is sometimes able to detect undefined behaviour in Rust code upon execution - however, there might be false positives.

The output of miri's execution:

error: Undefined Behavior: type validation failed: encountered uninitialized bytes at .value.data.parent1.parent1.data, but expected a valid enum discriminant
   --> /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/mem/maybe_uninit.rs:502:34
    |
502 |         ManuallyDrop::into_inner(self.value)
    |                                  ^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .value.data.parent1.parent1.data, but expected a valid enum discriminant
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: inside `std::mem::MaybeUninit::<generic_array::GenericArray<std::option::Option<storage2::lazy::entry::Entry<u8>>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>::assume_init` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/mem/maybe_uninit.rs:502:34
    = note: inside `std::mem::uninitialized::<generic_array::GenericArray<std::option::Option<storage2::lazy::entry::Entry<u8>>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/mem/mod.rs:664:5
    = note: inside `generic_array::ArrayBuilder::<std::option::Option<storage2::lazy::entry::Entry<u8>>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>::new` at /home/.cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.13.2/src/lib.rs:187:38
    = note: inside `<generic_array::GenericArray<std::option::Option<storage2::lazy::entry::Entry<u8>>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>> as generic_array::sequence::GenericSequence<std::option::Option<storage2::lazy::entry::Entry<u8>>>>::generate::<[closure@DefId(32:51 ~ generic_array[53b7]::impls[0]::{{impl}}[0]::default[0]::{{closure}}[0])]>` at /home/.cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.13.2/src/lib.rs:344:35
    = note: inside `generic_array::impls::<impl std::default::Default for generic_array::GenericArray<std::option::Option<storage2::lazy::entry::Entry<u8>>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>::default` at /home/.cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.13.2/src/impls.rs:17:9
note: inside `storage2::lazy::lazy_array::EntryArray::<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>::new` at core/src/storage2/lazy/lazy_array.rs:109:22
   --> core/src/storage2/lazy/lazy_array.rs:109:22
    |
109 |             entries: Default::default(),
    |                      ^^^^^^^^^^^^^^^^^^
note: inside `<storage2::lazy::lazy_array::EntryArray<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>> as std::default::Default>::default` at core/src/storage2/lazy/lazy_array.rs:119:9
   --> core/src/storage2/lazy/lazy_array.rs:119:9
    |
119 |         Self::new()
    |         ^^^^^^^^^^^
note: inside `storage2::lazy::lazy_array::LazyArray::<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>::new` at core/src/storage2/lazy/lazy_array.rs:182:45
   --> core/src/storage2/lazy/lazy_array.rs:182:45
    |
182 |             cached_entries: UnsafeCell::new(Default::default()),
    |                                             ^^^^^^^^^^^^^^^^^^
note: inside `<storage2::lazy::lazy_array::LazyArray<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>> as std::default::Default>::default` at core/src/storage2/lazy/lazy_array.rs:165:9
   --> core/src/storage2/lazy/lazy_array.rs:165:9
    |
165 |         Self::new()
    |         ^^^^^^^^^^^
note: inside `storage2::collections::smallvec::SmallVec::<u8, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>::new` at core/src/storage2/collections/smallvec/mod.rs:79:20
   --> core/src/storage2/collections/smallvec/mod.rs:79:20
    |
79  |             elems: Default::default(),
    |                    ^^^^^^^^^^^^^^^^^^
note: inside `storage2::collections::smallvec::tests::first_last_of_empty` at core/src/storage2/collections/smallvec/tests.rs:61:19
   --> core/src/storage2/collections/smallvec/tests.rs:61:19
    |
61  |     let mut vec = <SmallVec<u8, U4>>::new();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside closure at core/src/storage2/collections/smallvec/tests.rs:60:1
   --> core/src/storage2/collections/smallvec/tests.rs:60:1
    |
60  | / fn first_last_of_empty() {
61  | |     let mut vec = <SmallVec<u8, U4>>::new();
62  | |     assert_eq!(vec.first(), None);
63  | |     assert_eq!(vec.first_mut(), None);
64  | |     assert_eq!(vec.last(), None);
65  | |     assert_eq!(vec.last_mut(), None);
66  | | }
    | |_^
    = note: inside `<[closure@core/src/storage2/collections/smallvec/tests.rs:60:1: 66:2] as std::ops::FnOnce<()>>::call_once - shim` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
    = note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
    = note: inside `test::__rust_begin_short_backtrace::<fn()>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:517:5
    = note: inside closure at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:508:30
    = note: inside `<[closure@DefId(38:631 ~ test[140d]::run_test[0]::{{closure}}[2]) 0:fn()] as std::ops::FnOnce<()>>::call_once - shim(vtable)` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/ops/function.rs:232:5
    = note: inside `<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send> as std::ops::FnOnce<()>>::call_once` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/boxed.rs:1008:9
    = note: inside `<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>> as std::ops::FnOnce<()>>::call_once` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panic.rs:318:9
    = note: inside `std::panicking::r#try::do_call::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:331:40
    = note: inside `std::panicking::r#try::<(), std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:274:15
    = note: inside `std::panic::catch_unwind::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panic.rs:394:14
    = note: inside `test::run_test_in_process` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:541:18
    = note: inside closure at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:450:39
    = note: inside `test::run_test::run_test_inner` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:475:13
    = note: inside `test::run_test` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:505:28
    = note: inside `test::run_tests::<[closure@DefId(38:230 ~ test[140d]::console[0]::run_tests_console[0]::{{closure}}[2]) 0:&mut test::console::ConsoleTestState, 1:&mut std::boxed::Box<dyn test::formatters::OutputFormatter>]>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:284:13
    = note: inside `test::run_tests_console` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/console.rs:280:5
    = note: inside `test::test_main` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:120:15
    = note: inside `test::test_main_static` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libtest/lib.rs:139:5
    = note: inside `main`
    = note: inside closure at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:67:34
    = note: inside closure at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:52:73
    = note: inside `std::sys_common::backtrace::__rust_begin_short_backtrace::<[closure@DefId(1:6025 ~ std[1995]::rt[0]::lang_start_internal[0]::{{closure}}[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/sys_common/backtrace.rs:130:5
    = note: inside closure at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:52:13
    = note: inside `std::panicking::r#try::do_call::<[closure@DefId(1:6024 ~ std[1995]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:331:40
    = note: inside `std::panicking::r#try::<i32, [closure@DefId(1:6024 ~ std[1995]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe]>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panicking.rs:274:15
    = note: inside `std::panic::catch_unwind::<[closure@DefId(1:6024 ~ std[1995]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/panic.rs:394:14
    = note: inside `std::rt::lang_start_internal` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:51:25
    = note: inside `std::rt::lang_start::<()>` at /home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:67:5
    = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

So it seems to be a problem with uninitialized data in the Default implementation of GenericArray where it is using a ManuallyDrop with uninitialized data.

This is the test code that triggered the UB of my crate that is using generic-array:
https://github.com/paritytech/ink/blob/redo-init-and-flush/core/src/storage2/collections/smallvec/tests.rs#L60

I belive the problem is somewhere in this method:
https://github.com/fizyk20/generic-array/blob/master/src/lib.rs#L207
The array field is of type MaybeUninit and during the loop in fn generate (same file) the underlying array is initialized. However, in the linked method no call to assume_init is made and instead a core::mem::ptr::read is performed on the potentially uninitialized array contents. This doesn't necessarily need to be wrong, however, it could be that it confuses miri.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.