I have a world object that I want to contain a list of TCP writers (tokio WriteHalf). I can express this in a struct, but I seem to be unable to create/initialize it.
I think I understand what the issue is: tokio doesn't want people to Copy the WriteHalf, which I understand. And rust tried to initialize the array it looks at the Some() type and concludes that it doesn't have Copy so it fails, even though I explicitly want to initialize it as an array of None.
Am I understanding the problem correctly? What would be a good way to work around this problem? I assume those using ECS for TCP connections have encountered this in some way or another.
The situation here will probably get better as const generics get stabilized.
In the mean time there are a bunch of crates that can help. To add to the one already mentioned, https://crates.io/crates/arraytools allows things like
<[_; 32]>::generate(|| None)
EDIT: Many years later, since someone randomly 'd this today, the way to do this now is std::array::from_fn(|_| None).
Since doing that unsafe {} is error-prone, there is also the array_init - Rust crate that has factored that out.
Indeed, MaybeUninit::uninit().assume_init(), i.e., mem::uninitialized(), does not break validity invariants when used on [MaybeUninit<T>; N] types, as well as with inhabited ZSTs (although this case can break safety invariants associated with the ZST API, such as it being with singleton properties). Any other case breaks the validity invariant and is thus "instant UB".
Since nobody has mentioned it yet: You can write [None, None, None, None, None, None] to initialize an array like this without any unsafe code or macros. (Yes, it gets quite verbose when you get up to 32-element arrays.)
That doesn't sound like something that fits on the stack. I know you're moving it into the Arc, but it's still created on the stack initially, and you would need something like Arc::new_uninit to get around that.