How to avoid "unconstrained generic constant" with dependent associated constants in traits? - arrays

I am in the process of writing a trait with two associated constants: the first is a usize, and the other is an array of usize where with a length equal to the first constant. Essentially, my trait is equivalent to the following:
#![feature(const_trait_impl)]
#![feature(generic_const_exprs)]
trait Foo {
const SIZE: usize;
const ARR: [usize; Self::SIZE];
}
struct S;
impl const Foo for S {
const SIZE: usize = 2;
const ARR: [usize; Self::SIZE] = [1, 2];
}
fn main() {
const TEST: &[usize; 2] = &S::ARR;
println!("{:?}", TEST);
}
As of the current nightly build, this trait definition produces the following error:
error: unconstrained generic constant
--> src\main.rs:6:5
|
6 | const ARR: [usize; Self::SIZE];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); Self::SIZE]:`
Unfortunately, the suggested fix is not useful because any where bound involving Self::SIZE would be infinitely recursive. I was ready to give up until I discovered an alternative that seems to work:
#![feature(const_trait_impl)]
#![feature(generic_const_exprs)]
trait Bar {
const SIZE: usize;
fn arr() -> [usize; Self::SIZE];
}
struct S;
impl const Bar for S {
const SIZE: usize = 2;
fn arr() -> [usize; Self::SIZE] {
[1,2]
}
}
fn main() {
const TEST: &[usize; 2] = &S::arr();
println!("{:?}", TEST);
}
I am rather perplexed by this discrepancy, all things considered. Is there any way around it, or is it mostly just a matter of waiting for const language support to improve?

You can do as follows
trait Foo<const N : usize>{
const ARR : [usize; N];
}
struct S;
impl Foo<2> for S{
const ARR : [usize; 2] = [1, 2];
}
impl Foo<3> for S{
const ARR : [usize; 3] = [1, 2, 3];
}
fn main(){
const TEST : &[usize; 2] = &S::ARR;
println!("{:?}", TEST); // [1, 2]
const TEST2 : &[usize; 3] = &S::ARR;
println!("{:?}", TEST2); // [1, 2, 3]
}

Related

How to turn an array of iterators into an iterator of arrays?

Let's say I have the following array of iterators:
let arr = [0..9, 2..8, 4..8, 3..5];
How do I create an iterator that takes one element from each array every time .next() is called and returns a new array with these contents? I looked at itertools::izip and itertools::multizip, but these all didn't work with an array.
In this case, if such a function were called zip_array, I would expect the following result:
for [a, b, c, d] in zip_array(arr) {
println!("{a} {b} {c} {d}");
}
println!("end of iteration");
// 0 2 4 3
// 1 3 5 4
// end of iteration
How could one implement this function?
On nightly, this is very simple to implement (but note that the nightly implementation below may be faster):
#![feature(array_methods, array_try_map)]
pub struct ZipArray<T, const N: usize> {
array: [T; N],
}
pub fn zip_array<T: Iterator, const N: usize>(array: [T; N]) -> ZipArray<T, N> {
ZipArray { array }
}
impl<T: Iterator, const N: usize> Iterator for ZipArray<T, N> {
type Item = [T::Item; N];
fn next(&mut self) -> Option<Self::Item> {
self.array.each_mut().try_map(|i| i.next())
}
}
On stable, this require a little more work and unsafe code:
impl<T: Iterator, const N: usize> Iterator for ZipArray<T, N> {
type Item = [T::Item; N];
fn next(&mut self) -> Option<Self::Item> {
// SAFETY: It is always valid to `assume_init()` an array of `MaybeUninit`s (can be replaced
// with `MaybeUninit::uninit_array()` once stable).
let mut result: [MaybeUninit<T::Item>; N] = unsafe { MaybeUninit::uninit().assume_init() };
for (item, iterator) in std::iter::zip(&mut result, &mut self.array) {
item.write(iterator.next()?);
}
// SAFETY: We initialized the array above (can be replaced with `MaybeUninit::array_assume_init()`
// once stable).
Some(unsafe { std::mem::transmute_copy::<[MaybeUninit<T::Item>; N], [T::Item; N]>(&result) })
}
}
(Note that this does not drop items from previous iterators in case next() panics. It is not required, but a good thing to do).
On nightly you can use this code.
For stable you have to specifify the length in <[_; 4]>.
#![feature(generic_arg_infer)]
fn main() {
let mut arr = [0u8..9, 2..8, 4..8, 3..5];
for [a, b, c, d] in std::iter::from_fn(|| {
<[_;_]>::try_from(
arr.iter_mut()
.map(|x| x.next())
.collect::<Option<Vec<_>>>()?
)
.ok()
}) {
println!("{a} {b} {c} {d}");
}
println!("end of iteration");
// 0 2 4 3
// 1 3 5 4
// end of iteration
}
On stable you can use this:
pub struct ZipArray<T, const N: usize> {
array: [T; N],
}
pub fn zip_array<T: Iterator, const N: usize>(array: [T; N]) -> ZipArray<T, N> {
ZipArray { array }
}
impl<T: Iterator, const N: usize> Iterator for ZipArray<T, N>
where
<T as Iterator>::Item: Copy + Default,
{
type Item = [T::Item; N];
fn next(&mut self) -> Option<Self::Item> {
let mut item = [T::Item::default(); N];
for (index, element) in self.array.iter_mut().enumerate() {
match element.next() {
Some(value) => item[index] = value,
None => {
return None;
}
}
}
Some(item)
}
}
fn main() {
let arr = [0..9, 2..8, 4..8, 3..5];
for [a, b, c, d] in zip_array(arr) {
println!("{a} {b} {c} {d}");
}
println!("end of iteration");
}
It's probably not as performant due to copies as the unsafe version and has additional trait bounds, but it's safe.

Rust: Combine two arrays to produce a new array containing tuples of references to all combinations of the source arrays

I have two arrays,
struct Point{
position: (f32, f32),
}
struct Circle {
position: (f32, f32),
radius: f32,
}
type Points = [Option<Point>; 32];
type Circles = [Option<Circle >; 32];
And two traits,
trait Positioned {
fn get_position(&self) -> (f32, f32);
}
trait Circular {
fn get_radius(&self) -> f32;
}
And a function,
fn has_collision<P: Positioned, C: Positioned + Circular>(point: &P, circle: &C) -> bool {
//check if point is within circle
let (x, y) = point.get_position();
let (cx, cy) = circle.get_position();
let r = circle.get_radius();
(x - cx).powi(2) + (y - cy).powi(2) <= r.powi(2)
}
The Points and Circles get spawned (become Some) with values. I want to iterate over them, test for collisions, and set them to None if they are collided.
One approach is a nested loop:
fn handle_collisions(points: &mut Points , circles: &mut Circles ) {
for i in 0..points.len() {
if let Some(point) = &points[i] {
for j in 0..circles.len() {
if let Some(circle) = &mut circles[j] {
if has_collision(point, circle) {
points[i] = None;
circles[i] = None;
break;
}
}
}
}
}
}
This works, but I want to compare the performance of this with a different strategy - combine the points and circles into a single iterable of tuples, iterate over that, and then test for collisions and set them to None if they are collided.
How would I do this?
edit 1:
Here is an example that creates a new array that does not contain references to the original array:
fn vectorise(a: [i32; 3], b: [i32; 3]) -> [(i32, i32); 3*3] {
let mut result = [(0, 0); 3*3];
for i in 0..3 {
for j in 0..3 {
result[i*3+j] = (a[i], b[j]);
}
}
return result;
}
fn main() {
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
let array3 = vectorise(array1, array2);
println!("{:?}", array3);
}
The problem with this is that mutating array3 will not be reflected in array1 and array2. How do I solve this?
edit 2:
I have tried
fn vectorise<'c,>(a: &'c mut [i32; 2], b: &'c mut [i32; 2]) -> [(&'c mut i32, &'c mut i32); 4] {
let mut result = [
(&mut a[0], &mut b[0]),
(&mut a[0], &mut b[1]),
(&mut a[0], &mut b[2]),
(&mut a[1], &mut b[0])
];
result
}
fn main() {
let mut array1 = [1, 2];
let mut array2 = [4, 5];
let mut array3 = vectorise(&mut array1, &mut array2);
println!("{:?}", array3);
}
But I get the error
error[E0499]: cannot borrow `b[_]` as mutable more than once at a time
--> src\main.rs:7:21
|
2 | fn vectorise<'c,>(a: &'c mut [i32; 2], b: &'c mut [i32; 2]) -> [(&'c mut i32, &'c mut i32); 4] {
| -- lifetime `'c` defined here
3 | let mut result = [
4 | (&mut a[0], &mut b[0]),
| --------- first mutable borrow occurs here
...
7 | (&mut a[1], &mut b[0])
| ^^^^^^^^^ second mutable borrow occurs here
8 | ];
9 | result
| ------ returning this value requires that `b[_]` is borrowed for `'c`

Const array from range

How can I generate a long const array with values taken from a range?
Bonus: 1) working with no_std, 2) without using any crates
What I would like to do:
struct A {
a: i32,
b: B
}
enum B {
One,
Two
}
const AS: [A; 1024] = [A{a: 1, b: B::One}, A{a: 2, b: B::One}, ..., A{a: 1024, b: B::One}]
The furthest I got so far is:
macro_rules! generate_list {
($($a:expr)+, $variant:expr) => {
[ $( A { a: $a, b: $variant } )* ]
}
}
const AS: [A; 1024] = generate_list!(1..1025i32, B::One);
At least one problem with this seems to be that the macro is evaluated before the range expression is expanded to a list of literals.
I'm not sure if its idiomatic, but perhaps the following might work for your use case:
#[derive(Debug, Copy, Clone)]
pub struct A {
a: i32,
b: B,
}
#[derive(Debug, Copy, Clone)]
pub enum B {
One,
Two,
}
const fn gen_array<const N: usize>(offset: i32, b: B) -> [A; N] {
let mut res = [A { a: offset, b }; N];
let mut i = 0;
while i < N as i32 {
res[i as usize].a = offset + i;
i += 1;
}
res
}
const AS: [A; 42] = gen_array(0, B::One);
fn main() {
println!("{:#?}", AS);
}
Playground
I used a while loop, as a for loop is currently not allowed within a const context as E0744 indicates.
The above would generate 42 values for AS with an offset of 0:
[
A {
a: 0,
b: One,
},
A {
a: 1,
b: One,
},
...
A {
a: 41,
b: One,
},
]
The Godbolt Compiler Explorer shows that it generates the same instructions as writing it out manually.

How to initialize an array with an iterator in Rust? [duplicate]

I'm having trouble initializing a fixed length array. My attempts so far all result in the same "use of possibly uninitialized variable: foo_array" error:
#[derive(Debug)]
struct Foo { a: u32, b: u32 }
impl Default for Foo {
fn default() -> Foo { Foo{a:1, b:2} }
}
pub fn main() {
let mut foo_array: [Foo; 10];
// Do something here to in-place initialize foo_array?
for f in foo_array.iter() {
println!("{:?}", f);
}
}
error[E0381]: use of possibly uninitialized variable: `foo_array`
--> src/main.rs:13:14
|
13 | for f in foo_array.iter() {
| ^^^^^^^^^ use of possibly uninitialized `foo_array`
I implemented the Default trait, but Rust does not seem to call this by default akin to a C++ constructor.
What is the proper way to initialize a fixed length array? I'd like to do an efficient in-place initialization rather than some sort of copy.
Related: Why is the Copy trait needed for default (struct valued) array initialization?
Related: Is there a way to not have to initialize arrays twice?
The safe but somewhat inefficient solution:
#[derive(Copy, Clone, Debug)]
struct Foo {
a: u32,
b: u32,
}
fn main() {
let mut foo_array = [Foo { a: 10, b: 10 }; 10];
}
Since you're specifically asking for a solution without copies:
use std::mem::MaybeUninit;
#[derive(Debug)]
struct Foo {
a: u32,
b: u32,
}
// We're just implementing Drop to prove there are no unnecessary copies.
impl Drop for Foo {
fn drop(&mut self) {
println!("Destructor running for a Foo");
}
}
pub fn main() {
let array = {
// Create an array of uninitialized values.
let mut array: [MaybeUninit<Foo>; 10] = unsafe { MaybeUninit::uninit().assume_init() };
for (i, element) in array.iter_mut().enumerate() {
let foo = Foo { a: i as u32, b: 0 };
*element = MaybeUninit::new(foo);
}
unsafe { std::mem::transmute::<_, [Foo; 10]>(array) }
};
for element in array.iter() {
println!("{:?}", element);
}
}
This is recommended by the documentation of MaybeUninit.
You can use the arrayvec crate:
Cargo.toml
[package]
name = "initialize_array"
version = "0.1.0"
edition = "2018"
[dependencies]
arrayvec = "0.7.2"
src/main.rs
use arrayvec::ArrayVec;
use std::iter;
#[derive(Clone)]
struct Foo {
a: u32,
b: u32,
}
fn main() {
let foo_array: [Foo; 10] = iter::repeat(Foo { a: 10, b: 10 })
.take(10)
.collect::<ArrayVec<_, 10>>()
.into_inner()
.unwrap_or_else(|_| unreachable!());
}
The easiest way is to derive Copy on your type and initialize the array with that, copying the element N times:
#[derive(Copy)]
struct Foo {
a: u32,
b: u32,
}
let mut foo_array = [Foo { a: 1, b: 2 }; 10];
If you want to avoid copying, there are a couple options. You can use the Default trait:
let mut foo_array: [Foo; 10] = Default::default();
However, this is limited to arrays up to 32 elements. With const generics, it is now possible for the standard library to provide Default for all arrays. However, this would be a backward incompatible change for subtle reasons that are being worked on.
For now, you can take advantage of the fact that const values are also allowed in array repetition expressions:
const FOO: Foo = Foo { a: 1, b: 2 };
let mut foo_array = [FOO; 10];
If you're on nightly, you can use array::map:
#![feature(array_map)]
let mut foo_array = [(); 10].map(|_| Foo::default())

How can I initialize an array using a function? [duplicate]

This question already has answers here:
Initialize a large, fixed-size array with non-Copy types
(8 answers)
Closed last month.
I want to create an array of 10 empty vectors in Rust, but [Vec::new(); 10] doesn't work as Vec doesn't implement Copy. How can I do this, and in more general terms how can I initialize a array by repeatedly calling a function?
As of Rust 1.55.0, Sep 2021
You can use array's .map() method for general functions:
let arr: [Vec<u32>; 10] = [(); 10].map(|_| Vec::with_capacity(100));
(With Rust 1.63.0, Aug 2022 consider using from_fn).
As of Rust 1.63
Use from_fn:
let array: [usize; 5] = core::array::from_fn(|i| i * 2);
assert_eq!(array, [0, 2, 4, 8, 10]);
For your specific case, you can just use Default:
let v: [Vec<String>; 10] = Default::default();
For the general case, you can create an iterator out of your function and then collect into the array using ArrayVec:
use arrayvec::ArrayVec; // 0.4.10
use std::iter;
fn make<R>(f: impl FnMut() -> R) -> [R; 10] {
let a: ArrayVec<_> = iter::repeat_with(f).collect();
a.into_inner()
.unwrap_or_else(|_| panic!("Did not have enough elements"))
}
fn main() {
let mut a = 0;
let arr = make(|| {
a += 3;
a
});
println!("{:?}", arr);
// [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
}
See also:
How do I collect into an array?
I see two possible approaches
First
A simple solution using macro
macro_rules! array {
($v: expr; 1) => ([$v]);
($v: expr; 2) => ([$v, $v]);
($v: expr; 3) => ([$v, $v, $v]);
($v: expr; 4) => ([$v, $v, $v, $v]);
($v: expr; 5) => ([$v, $v, $v, $v, $v]);
// until 32
}
let a = array![Vec::new(); 3];
It's a bit verbose, but even the standard library uses this kind of construct.
Second
After realizing a connection between this question and another that I had answered before, I wrote this solution using nodrop
extern crate nodrop;
macro_rules! array {
($e: expr; $n:expr) => (
{
use std::mem;
use std::ptr;
use nodrop::NoDrop;
struct ArrayBuilder<T> {
len: usize,
data: *mut T,
}
impl<T> Drop for ArrayBuilder<T> {
fn drop(&mut self) {
unsafe {
while self.len > 0 {
let offset = (self.len as isize) - 1;
self.len -= 1;
ptr::drop_in_place(self.data.offset(offset));
}
}
}
}
let mut v: NoDrop<[_; $n]> = NoDrop::new(unsafe {
mem::uninitialized()
});
// helps type inference for v
if false { v[0] = $e; }
let mut builder = ArrayBuilder {
len: 0,
data: (&mut *v as *mut _) as *mut _
};
unsafe {
for i in 0..$n {
ptr::write(builder.data.offset(i as isize), $e);
builder.len = i + 1;
}
}
builder.len = 0;
v.into_inner()
}
)
}
let a = array![Vec::new(); 3];
And a test that indicates that it does not leak memory
#[test]
fn test() {
static mut COUNT: usize = 0;
#[derive(Debug)]
struct X(usize);
impl Drop for X {
fn drop(&mut self) {
println!("drop {:?}", self.0);
}
}
impl X {
fn new() -> X {
unsafe {
if COUNT == 3 {
panic!();
}
let x = X(COUNT);
COUNT += 1;
x
}
}
}
array![X::new(); 6];
}
In this test, the method X::new panics when creating X(3), so X(0), X(1), X(2) must be dropped.
Others
There is an unsafe solution here.
Edit: Outdated (applies to a Rust version lower than 1.55.0):
There is a crate called arr_macro that does exactly what you want:
fn main() {
let array: [Vec<String>; 10] = arr![Vec::new(); 10];
println!("{:?}", array) // [[], [], [], [], [], [], [], [], [], []]
}

Resources