Skip to content
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

A vec! like macro #128

Open
nico-abram opened this issue Aug 13, 2019 · 7 comments
Open

A vec! like macro #128

nico-abram opened this issue Aug 13, 2019 · 7 comments

Comments

@nico-abram
Copy link

Maybe arrvec! or arr_vec! ?

@bluss
Copy link
Owner

bluss commented Aug 15, 2019

We already have ArrayVec::from([array literal here]) which serves this purpose quite well, not sure what the benefits of a macro are.

@Alexhuszagh
Copy link

Alexhuszagh commented Sep 1, 2019

@bluss The macro allows you to concisely initialize an arrayvec with a potentially larger backing store.

Say I have the following type code:

type StorageType = ArrayVec<[u64; 20]>;

pub fn main() {
    // This fails, due to mismatched types, expected an array with 20 elements, got an array with 1 element.
    let s: StorageType = ArrayVec::from([1]);
}

There's no really good way to initialize from a macro without copying, but a simple way to implement an arrayvec macro would be:

#[macro_export]
macro_rules! arrvec {
    // This only works if the ArrayVec is the same size as the input array.
    ($elem:expr; $n:expr) => ({
        $crate::ArrayVec::from([$elem; $n])
    });
    // This just repeatedly calls `push`. I don't believe there's a concise way to count the number of expressions.
    ($($x:expr),*$(,)*) => ({
        // Allow an unused mut variable, since if the sequence is empty,
        // the vec will never be mutated.
        #[allow(unused_mut)] {
            let mut vec = $crate::ArrayVec::new();
            $(vec.push($x);)*
            vec
        }
    });
}

Please feel free to use that code.

If you'd like to count the number of elements, and then directly initialize and set the length, you could likely do that with:

macro_rules! count {
    () => (0usize);
    ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
}

However, you'd likely have to use a for loop to assign by index, because I don't believe there's a generic way to count the number of elements you'd have to pad the array with using a macro, which pretty much defeats the purpose.

@bluss
Copy link
Owner

bluss commented Sep 2, 2019

Interesting. Counting expressions -- see the little book of rust macros, or the maplit macros. But is not needed - you can write it to use extend with an exact size arrayvec into the inferred size one. That's kind of nice.

@bluss
Copy link
Owner

bluss commented Sep 29, 2019

@Alexhuszagh I've thought about this, and

  1. To be efficient, that macro needs a method that implements something like this: ArrayVec::<[_; 128]>::from_array([1, 2, 3, 4]) which allows starting with a shorter array than the full capacity. And that's easy and efficient to implement. We avoid push, which would be slow. Main challenge I see here is to give it a name, because just from is already taken 🙂

  2. Then we have a method that serves the purpose and don't need a macro. Macros are only necessary when we can't express it with regular methods.

@Boscop
Copy link

Boscop commented Oct 5, 2019

You can use this: https://crates.io/crates/array-macro
E.g.:

ArrayVec::from(array![vec![]; 16])

But it may not be in-place (may move the whole array)..

@avl
Copy link

avl commented Jul 11, 2020

I think such a macro would be nice, even if the only advantage was that it made arrayvec work more like Vec and SmallVec. This would make it easier to remember how to construct an "ArrayVec literal".

@Boscop
Copy link

Boscop commented Jul 6, 2023

@Alexhuszagh What about ArrayVec::from_iter([x])?
Wouldn't it result in very optimized code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants