default_option_arr/lib.rs
1//! When dealing with non-`Copy`/`Clone` types `T`, such as arrays of type `[Option<T>; N]` cannot
2//! be created even though the default type `None` could be applied.
3//!
4//! For a given type
5//!
6//! ```
7//! // This type does not implement Copy.
8//! struct Complicated;
9//! ```
10//!
11//! The following code fails to compile with the compiler error "the trait `Copy` is not implemented for `Complicated`":
12//!
13//! ```compile_fail
14//! # struct Complicated;
15//! let arr: [Option<Complicated>; 10] = [None; 10];
16//! ```
17//!
18//! This crate simplifies array creation of these cases through the `none_arr!` macro:
19//!
20//! ```
21//! # use default_option_arr::none_arr;
22//! # struct Complicated;
23//! let arr = none_arr![Complicated; 10];
24//!
25//! // The result is an array of Option<Complicated>.
26//! let arr: [Option<Complicated>; 10] = arr;
27//!
28//! assert_eq!(arr.len(), 10);
29//! for item in arr.into_iter() {
30//! assert!(item.is_none());
31//! }
32//! ```
33
34#![cfg_attr(not(feature = "std" ), no_std)]
35
36// Unsafe code is required for the initialization.
37#![allow(unsafe_code)]
38
39/// Creates an array of type `[Option<T>; N]` and default-initializes it to `None`
40/// for every element.
41///
42/// ## Macro Arguments
43///
44/// * `$t` - The type to wrap into an `Option<T>`.
45/// * `$n` - The number of elements for the array.
46///
47/// ## Example
48///
49/// When dealing with non-`Copy`/`Clone` types, arrays of type `[Option<T>; N]` cannot be
50/// created even though the default type `None` could be applied:
51///
52/// ```compile_fail
53/// // This type does not implement Copy/Clone.
54/// struct Complicated;
55///
56/// // Fails with "the trait `Copy` is not implemented for `Complicated`":
57/// let arr: [Option<Complicated>; 10] = [None; 10];
58/// ```
59///
60/// This crate simplifies array creation of these cases through the `none_arr` macro:
61///
62/// ```
63/// # use default_option_arr::none_arr;
64/// # struct Complicated;
65/// let arr = none_arr![Complicated; 10];
66///
67/// // The result is an array of Option<Complicated>.
68/// let arr: [Option<Complicated>; 10] = arr;
69///
70/// assert_eq!(arr.len(), 10);
71/// for item in arr.into_iter() {
72/// assert!(item.is_none());
73/// }
74/// ```
75#[macro_export]
76macro_rules! none_arr {
77 ($t:ty; $n:expr) => {{
78 use core::mem::MaybeUninit;
79
80 let mut uninit_data: MaybeUninit<[Option<$t>; $n]> = MaybeUninit::uninit();
81 let array = uninit_data.as_mut_ptr();
82 unsafe { &mut *array }.fill_with(|| None);
83 unsafe { uninit_data.assume_init() }
84 }};
85}
86
87/// Creates an array of type `[Cell<Option<T>>; N]` and default-initializes it to `Cell:new(None)`
88/// for every element. Similar to [`none_arr`], plus a [`Cell`](core::cell::Cell).
89///
90/// ## Macro Arguments
91///
92/// * `$t` - The type to wrap into an `Cell<Option<T>>`.
93/// * `$n` - The number of elements for the array.
94///
95/// ## Example
96///
97/// When dealing with non-`Copy`/`Clone` types, arrays of type `[Option<T>; N]` cannot be
98/// created even though the default type `None` could be applied:
99///
100/// ```compile_fail
101/// # use core::cell::Cell;
102/// // This type does not implement Copy/Clone.
103/// struct Complicated;
104///
105/// // Fails with "the trait `Copy` is not implemented for `Complicated`":
106/// let arr: [Cell<Option<Complicated>>; 10] = [Cell::new(None); 10];
107/// ```
108///
109/// This crate simplifies array creation of these cases through the `none_cell_arr` macro:
110///
111/// ```
112/// # use core::cell::Cell;
113/// # use default_option_arr::none_cell_arr;
114/// # struct Complicated;
115/// let arr = none_cell_arr![Complicated; 10];
116///
117/// // The result is an array of Cell<Option<Complicated>>.
118/// let arr: [Cell<Option<Complicated>>; 10] = arr;
119///
120/// assert_eq!(arr.len(), 10);
121/// for item in arr.into_iter() {
122/// assert!(item.take().is_none());
123/// }
124/// ```
125#[macro_export]
126macro_rules! none_cell_arr {
127 ($t:ty; $n:expr) => {{
128 use core::cell::Cell;
129 use core::mem::MaybeUninit;
130
131 let mut uninit_data: MaybeUninit<[Cell<Option<$t>>; $n]> = MaybeUninit::uninit();
132 let array = uninit_data.as_mut_ptr();
133 unsafe { &mut *array }.fill_with(|| Cell::new(None));
134 unsafe { uninit_data.assume_init() }
135 }};
136}
137
138/// Creates an array of type `[RefCell<Option<T>>; N]` and default-initializes it to `Cell:new(None)`
139/// for every element. Similar to [`none_cell_arr`], but with a [`RefCell`](core::cell::RefCell).
140///
141/// ## Macro Arguments
142///
143/// * `$t` - The type to wrap into an `RefCell<Option<T>>`.
144/// * `$n` - The number of elements for the array.
145///
146/// ## Example
147///
148/// When dealing with non-`Copy`/`Clone` types, arrays of type `[RefCell<Option<T>>; N]` cannot be
149/// created even though the default type `None` could be applied:
150///
151/// ```compile_fail
152/// # use core::cell::RefCell;
153/// // This type does not implement Copy/Clone.
154/// struct Complicated;
155///
156/// // Fails with "the trait `Copy` is not implemented for `Complicated`":
157/// let arr: [RefCell<Option<Complicated>>; 10] = [RefCell::new(None); 10];
158/// ```
159///
160/// This crate simplifies array creation of these cases through the `none_refcell_arr` macro:
161///
162/// ```
163/// # use core::cell::RefCell;
164/// # use default_option_arr::none_refcell_arr;
165/// # struct Complicated;
166/// let arr = none_refcell_arr![Complicated; 10];
167///
168/// // The result is an array of Cell<Option<Complicated>>.
169/// let arr: [RefCell<Option<Complicated>>; 10] = arr;
170///
171/// assert_eq!(arr.len(), 10);
172/// for item in arr.into_iter() {
173/// assert!(item.take().is_none());
174/// }
175/// ```
176#[macro_export]
177macro_rules! none_refcell_arr {
178 ($t:ty; $n:expr) => {{
179 use core::cell::RefCell;
180 use core::mem::MaybeUninit;
181
182 let mut uninit_data: MaybeUninit<[RefCell<Option<$t>>; $n]> = MaybeUninit::uninit();
183 let array = uninit_data.as_mut_ptr();
184 unsafe { &mut *array }.fill_with(|| RefCell::new(None));
185 unsafe { uninit_data.assume_init() }
186 }};
187}
188
189#[cfg(test)]
190mod tests {
191 use core::mem::MaybeUninit;
192
193 // No copy, no clone.
194 struct Complicated;
195
196 #[test]
197 fn it_works() {
198 let arr = none_arr![Complicated; 10];
199
200 assert_eq!(arr.len(), 10);
201 for item in arr.into_iter() {
202 assert!(item.is_none());
203 }
204 }
205
206 #[test]
207 fn cell_works() {
208 let arr = none_cell_arr![Complicated; 10];
209
210 assert_eq!(arr.len(), 10);
211 for item in arr.into_iter() {
212 assert!(item.take().is_none());
213 }
214 }
215
216 #[test]
217 fn refcell_works() {
218 let arr = none_refcell_arr![Complicated; 10];
219
220 assert_eq!(arr.len(), 10);
221 for item in arr.into_iter() {
222 assert!(item.borrow().is_none());
223 }
224 }
225
226 #[test]
227 fn reference_loop() {
228 let mut uninit_data: MaybeUninit<[Option<Complicated>; 10]> = MaybeUninit::uninit();
229 let mut ptr = uninit_data.as_mut_ptr() as *mut Option<Complicated>;
230 for _ in 0..10 {
231 unsafe {
232 ptr.write(None);
233 ptr = ptr.add(1);
234 }
235 }
236 let arr = unsafe { uninit_data.assume_init() };
237
238 assert_eq!(arr.len(), 10);
239 for item in arr.into_iter() {
240 assert!(item.is_none());
241 }
242 }
243
244 #[test]
245 fn reference_fill_with() {
246 let mut uninit_data: MaybeUninit<[Option<Complicated>; 10]> = MaybeUninit::uninit();
247 let array = uninit_data.as_mut_ptr();
248 unsafe { &mut *array }.fill_with(|| None);
249 let arr = unsafe { uninit_data.assume_init() };
250
251 assert_eq!(arr.len(), 10);
252 for item in arr.into_iter() {
253 assert!(item.is_none());
254 }
255 }
256
257 #[test]
258 #[cfg(feature = "std")]
259 fn reference_vec() {
260 let arr: [Option<Complicated>; 10] = (0..10)
261 .into_iter()
262 .map(|_| None)
263 .collect::<Vec<_>>()
264 .try_into()
265 .map_err(|_| "try_into failed") // Debug required otherwise
266 .expect("initialization failed");
267
268 assert_eq!(arr.len(), 10);
269 for item in arr.into_iter() {
270 assert!(item.is_none());
271 }
272 }
273}