-
Notifications
You must be signed in to change notification settings - Fork 129
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
Give ArrayVec a const-fn constructor #93
Comments
It's an attractive idea -- maybe it needs to be a separate constructor. I don't know when Also note, that defining |
I've explored this in more detail. There's a lot that blocks it at this point:
it does not look like it can be implemented close to the present |
Ok thank you for digging deeper into this! If you think there is no way to do this in the near future than feel free to close this issue. |
If you have a Copy-only element it gets a lot easier (the implementation is also mostly free of pitfalls, so it should be more straightforward). The problem with |
Actually in my use case the elements could be Copy, yes (they aren't right now, but for semantic reasons). But wouldn't implementing that require specialization in order to distinguish between Copy/Non-Copy types? |
Revisit for Copy-only types (For example ArrayString is backed by a copy array.) We still have this issue in nightly: error: trait bounds other than `Sized` on const fn parameters are unstable
--> src/array_string.rs:45:6
|
45 | impl<A> ArrayString<A> So a |
What's the benefit of static ArrayVec? I thought ArrayVec is useful for storage items up to certain limit. A static variable in Rust cannot be changed, hence no benefit, and mutable statics are unsafe. Could you explain @michael-p? |
You would need to use interior mutability, for instance with a Mutex. So you might have something like: static BUFFER: Mutex<ArrayVec<[SomeType; 1024]> = Mutex::new(ArrayVec::new());
...
BUFFER.lock().push(my_value); Note that |
We want an ArrayVec for Copy elements eventually #32, seems there is no way around that, and it should be able to have const fn constructor exactly when ArrayString can, so the issue mentioned 2 comments back also blocks that, just to note. |
I do embedded programming either, most of my professional career... at these global arrays smells 80's like C-style globals I thought are long gone, @michael-p. I don't denounce the need for |
I would also like the ability to construct an ArrayVec in a static. I have a program with a bunch of small immutable assets, and I would like to make them statics. Currently I'm constructing them all at startup, but it would be nice to build them offline, write them out as Rust statics, and then just use that. Several of them contain Vec-s, which is handy when building the assets, but an ArrayVec would work just as well since I know that maximum size, which is quite small. I think this use case requires only something like: impl ArrayVec { I'm happy to specify a value for every array element, even though only "len" of them will be used. I don't know if that eases implementation. Since the ArrayVec is immutable static it will never be modified, which may/hopefully alleviate the question of whether the unused elements are initialized. |
It seems like const generics might be our only way to get to this (of course not stable yet); because |
Any chance of adding ArrayVec::resize_with? I just replaced a Vec with an ArrrayVec, and it was so close to just... change the declaration and the one initialization... except I also had a resize_with, and I had to rewrite that by hand. But it's trivially implementable in terms of push & pop. (If offering a code change would help, I can probably do that.) |
Need to think about how to handle the bounds check for new length (what's consistent - probably panic for out of bounds of capacity), other than that, PRs welcome for resize_with |
The constructor can be rewritten to a const fn by doing this on stable: pub const fn new() -> ArrayVec<T, CAP> {
assert_capacity_limit!(CAP);
ArrayVec { xs: Self::__UNINIT_ARRAY, len: 0 }
}
const __UNINIT_ELEM: MaybeUninit<T> = MaybeUninit::uninit();
const __UNINIT_ARRAY: [MaybeUninit<T>; CAP] = [Self::__UNINIT_ELEM; CAP]; but it would require hackily changing the macro_rules! assert_capacity_limit {
($cap:expr) => {
if std::mem::size_of::<usize>() > std::mem::size_of::<LenUint>() {
if $cap > LenUint::MAX as usize {
[/*ArrayVec: largest supported capacity is u32::MAX*/][$cap]
}
}
}
} which gives you this error in const contexts: error[E0080]: could not evaluate static initializer
--> src/lib.rs:40:17
|
40 | [/*ArrayVec: largest supported capacity is u32::MAX*/][$cap]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| index out of bounds: the length is 0 but the index is 4294967296
| inside `ArrayVec::<u8, 4294967296_usize>::new` at src/lib.rs:40:17
|
::: src/arrayvec.rs:62:57
|
62 | static ARRBVEC: ArrayVec<u8, {u32::MAX as usize + 1}> = ArrayVec::new();
| --------------- inside `ARRBVEC` at src/arrayvec.rs:62:57
...
83 | assert_capacity_limit!(CAP);
| ---------------------------- in this macro invocation
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) and this error at runtime: thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 18446744073709551615', /src/arrayvec.rs:81:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: panic did not contain expected string Don't know if you're OK pessimising the runtime error for the constructor to make it a What the associated constants are doing is using the new-ish feature to initialize arrays by repeating
|
@rodrimati1992 I thought that should give you an error that it can't use generic |
Associated constants can use the generic parameters of the struct MakeArray<T, const LEN: usize>(T);
impl<T, const LEN: usize> MakeArray<T, LEN> {
const INNER: [T; 0] = [];
pub const MAKE: [[T; 0]; LEN] = [Self::INNER; LEN];
}
fn main(){
println!("{:?}", MakeArray::<u8, 10>::MAKE);
} prints:
|
I'm not sure if this is even possible but it would be great if
ArrayVec::new()
would be aconst fn
and hence could be called in places where only constant expressions are allowed (of course behind some feature-flag since const-fn is still unstable).The reason I'd like this feature is that I work on embedded systems where it's typical to have all memory allocated statically, i.e. for a large buffer one would have something like
This works fine for arrays (and Copy types) but it would be great if I could also use an
ArrayVec
there. Again, not sure if it's even possible sincemem::uninitialized()
seems to not be a const-fn (although it should, I think) but maybe/hopefully I'm wrong. :)lazy_static!
will not work AFAIK because on first invocation of the initialization code the value gets constructed on the stack which typically will not be large enough to hold that value, even temporarily.Thanks for considering this! :)
The text was updated successfully, but these errors were encountered: