array_macro/
lib.rs

1// SPDX-FileCopyrightText: 2017 - 2022 Kamila Borowska <kamila@borowska.pw>
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5//! Array multiple elements constructor syntax.
6//!
7//! While Rust does provide those, they require copy, and you cannot obtain the
8//! index that will be created. This crate provides syntax that fixes both of
9//! those issues.
10//!
11//! # Examples
12//!
13//! ```
14//! # #[macro_use]
15//! # extern crate array_macro;
16//! # fn main() {
17//! assert_eq!(array![String::from("x"); 2], [String::from("x"), String::from("x")]);
18//! assert_eq!(array![x => x; 3], [0, 1, 2]);
19//! # }
20//! ```
21
22#![no_std]
23#![deny(missing_docs)]
24
25#[doc(hidden)]
26pub extern crate core as __core;
27
28/// Creates an array containing the arguments.
29///
30/// This macro provides a way to repeat the same macro element multiple times
31/// without requiring `Copy` implementation as array expressions require.
32///
33/// There are two forms of this macro.
34///
35/// - Create an array from a given element and size. This will `Clone` the element.
36///
37///   ```
38///   use array_macro::array;
39///   assert_eq!(array![vec![1, 2, 3]; 2], [[1, 2, 3], [1, 2, 3]]);
40///   ```
41///
42///   Unlike array expressions this syntax supports all elements which implement
43///   `Clone`.
44///
45/// - Create an array from a given expression that is based on index and size.
46///   This doesn't require the element to implement `Clone`.
47///
48///   ```
49///   use array_macro::array;
50///   assert_eq!(array![x => x * 2; 3], [0, 2, 4]);
51///   ```
52///
53///   This form can be used for declaring `const` variables.
54///
55///   ```
56///   use array_macro::array;
57///   const ARRAY: [String; 3] = array![_ => String::new(); 3];
58///   assert_eq!(ARRAY, ["", "", ""]);
59///   ```
60///
61/// # Limitations
62///
63/// When using a form with provided index it's not possible to use `break`
64/// or `continue` without providing a label. This won't compile.
65///
66/// ```compile_fail
67/// use array_macro::array;
68/// loop {
69///     array![_ => break; 1];
70/// }
71/// ```
72///
73/// To work-around this issue you can provide a label.
74///
75/// ```
76/// use array_macro::array;
77/// 'label: loop {
78///     array![_ => break 'label; 1];
79/// }
80/// ```
81#[macro_export]
82macro_rules! array {
83    [$expr:expr; $count:expr] => {{
84        let value = $expr;
85        $crate::array![_ => $crate::__core::clone::Clone::clone(&value); $count]
86    }};
87    [$i:pat => $e:expr; $count:expr] => {
88        $crate::__array![$i => $e; $count]
89    };
90}
91
92use core::mem::{ManuallyDrop, MaybeUninit};
93use core::ptr;
94
95#[doc(hidden)]
96#[repr(transparent)]
97pub struct __ArrayVec<T, const N: usize>(pub __ArrayVecInner<T, N>);
98
99impl<T, const N: usize> Drop for __ArrayVec<T, N> {
100    fn drop(&mut self) {
101        // This is safe as arr[..len] is initialized due to
102        // __ArrayVecInner's type invariant.
103        let initialized = &mut self.0.arr[..self.0.len] as *mut _ as *mut [T];
104        unsafe { ptr::drop_in_place(initialized) };
105    }
106}
107
108// Type invariant: arr[..len] must be initialized
109#[doc(hidden)]
110#[non_exhaustive]
111pub struct __ArrayVecInner<T, const N: usize> {
112    pub arr: [MaybeUninit<T>; N],
113    pub len: usize,
114    // This field exists so that array! macro could retrieve the value of N.
115    // The method to retrieve N cannot be directly on __ArrayVecInner as
116    // borrowing it could cause a reference to interior mutable data to
117    // be created which is not allowed in `const fn`.
118    //
119    // Because this field doesn't actually store anything it's not possible
120    // to replace it in an already existing instance of __ArrayVecInner.
121    pub capacity: __Capacity<N>,
122}
123
124impl<T, const N: usize> __ArrayVecInner<T, N> {
125    #[doc(hidden)]
126    pub const unsafe fn new(arr: [MaybeUninit<T>; N]) -> Self {
127        Self {
128            arr,
129            len: 0,
130            capacity: __Capacity,
131        }
132    }
133}
134
135#[doc(hidden)]
136pub struct __Capacity<const N: usize>;
137
138impl<const N: usize> __Capacity<N> {
139    #[doc(hidden)]
140    pub const fn get(&self) -> usize {
141        N
142    }
143}
144#[doc(hidden)]
145#[repr(C)]
146pub union __Transmuter<T, const N: usize> {
147    pub init_uninit_array: ManuallyDrop<MaybeUninit<[T; N]>>,
148    pub uninit_array: ManuallyDrop<[MaybeUninit<T>; N]>,
149    pub out: ManuallyDrop<[T; N]>,
150}
151
152#[doc(hidden)]
153#[repr(C)]
154pub union __ArrayVecTransmuter<T, const N: usize> {
155    pub vec: ManuallyDrop<__ArrayVec<T, N>>,
156    pub inner: ManuallyDrop<__ArrayVecInner<T, N>>,
157}
158
159#[doc(hidden)]
160#[macro_export]
161macro_rules! __array {
162    [$i:pat => $e:expr; $count:expr] => {{
163        let mut vec = $crate::__ArrayVec::<_, {$count}>(unsafe { $crate::__ArrayVecInner::new(
164            // An uninitialized `[MaybeUninit<_>; LEN]` is valid.
165            $crate::__core::mem::ManuallyDrop::into_inner(unsafe {
166                $crate::__Transmuter {
167                    init_uninit_array: $crate::__core::mem::ManuallyDrop::new($crate::__core::mem::MaybeUninit::uninit()),
168                }
169                .uninit_array
170            }),
171        )});
172        while vec.0.len < (&vec.0.capacity).get() {
173            let $i = vec.0.len;
174            let _please_do_not_use_continue_without_label;
175            let value;
176            struct __PleaseDoNotUseBreakWithoutLabel;
177            loop {
178                _please_do_not_use_continue_without_label = ();
179                value = $e;
180                break __PleaseDoNotUseBreakWithoutLabel;
181            };
182            // This writes an initialized element.
183            vec.0.arr[vec.0.len] = $crate::__core::mem::MaybeUninit::new(value);
184            // We just wrote a valid element, so we can add 1 to len, it's valid.
185            vec.0.len += 1;
186        }
187        // When leaving this loop, vec.0.len must equal to $count due
188        // to loop condition. It cannot be more as len is increased by 1
189        // every time loop is iterated on, and $count never changes.
190
191        // __ArrayVec is representation compatible with __ArrayVecInner
192        // due to #[repr(transparent)] in __ArrayVec.
193        let inner = $crate::__core::mem::ManuallyDrop::into_inner(unsafe {
194            $crate::__ArrayVecTransmuter {
195                vec: $crate::__core::mem::ManuallyDrop::new(vec),
196            }
197            .inner
198        });
199        // At this point the array is fully initialized, as vec.0.len == $count,
200        // so converting an array of potentially uninitialized elements into fully
201        // initialized array is safe.
202        $crate::__core::mem::ManuallyDrop::into_inner(unsafe {
203            $crate::__Transmuter {
204                uninit_array: $crate::__core::mem::ManuallyDrop::new(inner.arr),
205            }
206            .out
207        })
208    }}
209}