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}