How to implement simple N-dimensional vector in rust?

I am a newbie to rust. I am trying to create an N-dimensional vector in rust. In that process, I wanted to write a function to get the dimensions of that vector. Below code is not giving what I expected. Any help will be appreciated.

use std::any::Any;

fn main() {
    let input = vec![
        [[1, 2, 3, 4], [1, 2, 3, 4]],
        [[1, 2, 3, 4], [1, 2, 3, 4]],
        [[1, 2, 3, 4], [1, 2, 3, 4]],
    ];

    let transformed_input = input.iter()
    .map(|x| x as &dyn Any)
    .collect::<Vec<&dyn Any>>();
    

    let matrix = Matrix::new(
        transformed_input,
    );
    println!("{:?}", matrix.dimensions());
}

trait MatrixElement {
    fn data(&self) {}
}

impl MatrixElement for isize {}
#[derive(Default, Debug)]
struct Matrix<'a> {
    data: Vec<&'a dyn Any>,
}

impl<'a> Matrix<'a> {
    fn new(data: Vec<&'a dyn Any>) -> Self {
        dbg!(&data);
        Self { data }
    }

    fn dimensions(&self) -> Vec<usize> {
        let mut out: Vec<usize> = vec![];
        let mut current_vec = self.data.clone();

        while let Some(first_child) = current_vec.first() {
            if let Some(vector) = first_child.downcast_ref::<Vec<&dyn Any>>() {
                //not coming in to this if condition
                out.push(vector.len());
                current_vec = vector.clone();
            } else {
                break;
            }
        }
        out
    }
}

(Playground)

Rust doesn't have multi-dimensional vectors, and without the const generics feature (to be released later this year, maybe) it's hard to make generic code that works for any N.

See the ndarray crate:

1 Like

In your code there's a logic error - first element of a Vec is not the whole Vec itself (x[0] != x). Concrete type of your elements is [[i32; 4]; 2], and that's the only type you can downcast to.

You can't cast Vec<[[i32; 4]; 2]> to Vec<&dyn Any>, because these have different layouts in memory. You won't be able to recursively cast Vec<&dyn Any> of arrays into Vec<&dyn Any> of smaller sub-arrays. Each level would require generation of a brand new Vec, which makes this whole thing slow and cumbersome.


In general Any is probably wrong tool for this. Rust doesn't have a base type like Object in Java. dyn Any is more like a standalone object, distinct from original object, which can hold on to a reference to the original object and lend that one particular reference.

Matrix code is usually performance-critical, but dyn Any forces indirections and dynamic dispatch that prevents lots of optimizations.

dyn Any is a trait object, and it imposes "object safety" rules on types, and makes compiler treat size of these objects as an abstract thing that can't be known. This causes tons of ergonomic problems, e.g. owned trait objects don't support Clone. In your case .clone() is only allowed because &dyn Any is copyable as a pointer (doesn't actually clone anything), but it being a temporary borrow it imposes a whole another set of restrictions that will make the whole thing painfully unusable for your purposes.

1 Like

If you wanted to do it yourself, you might try a Matrix struct that wraps a Vec and is initialized with width and height; then indexing the matrix at (row,col) is indexing into the Vec at (row*width+col). You can generalize this to more dimensions by figuring out the stride along each axis, but you must be okay with accepting extents and indices as slices for now since tuples and arrays have fixed lengths.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.