[idea] vec macro expand

I hope that when building Vec through vec! macros, I can expand other arrays and make their elements part of the array, simplifying code writing. The example code is as follows:

let a = vec![3, 4];
let b = vec![5, 6];
let c = vec![1, 2, ...a, ...b]; // then c = [1, 2, 3, 4, 5, 6]
1 Like
let a = vec![3, 4];
let b = vec![5, 6];
let c = [vec![1, 2], a, b].concat();  // c = [1, 2, 3, 4, 5, 6]

This is what I do today. Might have a couple extra allocations, but most of time it's good enough for me.

I'm not opposing add new vec! syntax though. Do note ..a means RangeTo<Vec<{interger}>> in current Rust, so you can't use this exact syntax, but I guess we can do bikeshedding later.

1 Like

Have you tried the code you proposing? That's already valid syntax, and if you remove the 1, 2, part then it will even compile.

1 Like

I hope to expand instead of generating Vec<RangeTo<Vec<{integer}>>>type data

Yes, that's the point. You can't just reuse syntax that already has a meaning in the context.

3 Likes

I hope that someday .. will always denote a range and ... always a spread/unpack/rest.

4 Likes

Everyone's opinions were surprisingly unanimous, so I revised my thoughts and changed them to: ...

You can always create your own macro. I used pub since its not valid in expressions, but if you used a proc_macro you could use whatever you want. This should also be more performant than [vec![1, 2], a, b].concat(). (Downside is that this could play poorly with type inference.)

macro_rules! collection {
    ( $e:expr $(,)? ) => {{
        let mut this = Default::default();
        // using array, but iter::once could be faster?
        Extend::extend(&mut this, [$e]);
        
        this
    }};
    ( pub $e:expr $(,)? ) => {{
        let mut this = Default::default();
        
        Extend::extend(&mut this, $e);
        
        this
    }};
    
    ( $e:expr, $( $t:tt )* ) => {{
        let mut this = collection![$e];
        
        collection![this; $( $t )*];

        this    
    }};
    ( pub $e:expr, $( $t:tt )* ) => {{
        let mut this = collection![pub $e];   
        
        collection![this; $( $t )*];
        
        this
    }};

    ( $this:ident; $e:expr, $( $t:tt )* ) => {{
        Extend::extend(&mut $this, [$e]);
        
        collection![$this; $( $t )*];
    }};
    ( $this:ident; pub $e:expr, $( $t:tt )* ) => {{
        Extend::extend(&mut $this, $e);
        
        collection![$this; $( $t )*];
    }};
    
    ( $this:ident; $( $e:expr)? $(,)? ) => {$({
        Extend::extend(&mut $this, [$e]);
    })*};
    ( $this:ident; $( pub $e:expr )? $(,)? ) => {$({
        Extend::extend(&mut $this, $e);
    })*};
    
    () => { vec![] };
}

// hint to tell the compiler that the output shoule be `Vec<_>`
macro_rules! vec {
    ( $( $t:tt )* ) => {{
        let this: Vec<_> = collection![$( $t )*];
        
        this
    }};
}

fn main() {
    // works nicely with iterators
    let a = b"Hello world".iter().copied();
    let b = [4, 5, 6,];
    let c = vec![pub a, 3, pub b,];
    
    println!("{:?}", c);
}

Check out velcro::vec.

You may be interested in Pre-RFC: Unpacking to Array and Tuple Literals I've been working on (though somewhat slowly as of late, due to being busy with dayjob stuff). Although that pre-RFC is principally about unpacking into array and tuple literals, vectors would be a natural follow-up (and are actually mentioned as such at the end). :slight_smile: