1#![no_std]
3
4use core::mem::MaybeUninit;
5
6mod util;
7
8pub struct Cursor<'a, T, const N: usize> {
18 slice: &'a mut [MaybeUninit<T>; N],
19}
20
21impl<'a, T, const N: usize> Cursor<'a, T, N> {
22 pub fn new(slice: &'a mut [MaybeUninit<T>; N]) -> Self {
24 Self { slice }
25 }
26
27 fn write_impl(&mut self, value: [T; N]) {
28 *self.slice = value.map(|v| MaybeUninit::new(v));
29 }
30
31 pub fn finish(mut self, value: [T; N]) {
36 self.write_impl(value);
37 core::mem::forget(self);
38 }
39
40 pub fn write<const L: usize, const R: usize>(self, value: [T; L]) -> Cursor<'a, T, R> {
46 let (l, r) = self.split::<L, R>();
47 l.finish(value);
48 r
49 }
50
51 fn into_buf(self) -> &'a mut [MaybeUninit<T>; N] {
52 unsafe { core::mem::transmute(self) }
53 }
54
55 pub fn split<const L: usize, const R: usize>(self) -> (Cursor<'a, T, L>, Cursor<'a, T, R>) {
61 let buf = self.into_buf();
62 let (l, r) = crate::util::split_mut::<_, N, L, R>(buf);
63 (Cursor { slice: l }, Cursor { slice: r })
64 }
65
66 pub fn assert_size<const M: usize>(self) -> Cursor<'a, T, M> {
79 let (l, _) = self.split::<M, 0>();
80 l
81 }
82}
83
84impl<T, const N: usize> Drop for Cursor<'_, T, N> {
85 fn drop(&mut self) {
87 if N > 0 {
88 panic!("Cursor still has uninitialized bytes");
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use core::sync::atomic::AtomicU8;
96
97 use super::*;
98
99 #[test]
100 fn test_drop() {
101 struct DropCounter<'a>(&'a AtomicU8);
102 impl core::ops::Drop for DropCounter<'_> {
103 fn drop(&mut self) {
104 self.0.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
105 }
106 }
107
108 let value = AtomicU8::new(0);
109 {
110 let mut data: [MaybeUninit<DropCounter<'_>>; 1] = [MaybeUninit::uninit()];
111 Cursor::new(&mut data).finish([DropCounter(&value)]);
112 }
113 assert_eq!(value.load(core::sync::atomic::Ordering::SeqCst), 0);
114
115 let value = AtomicU8::new(0);
116 {
117 let mut data: [MaybeUninit<DropCounter<'_>>; 2] =
118 [MaybeUninit::uninit(), MaybeUninit::uninit()];
119 Cursor::new(&mut data).finish([DropCounter(&value), DropCounter(&value)]);
120 }
121 assert_eq!(value.load(core::sync::atomic::Ordering::SeqCst), 0);
122
123 let value = AtomicU8::new(0);
124 {
125 let mut data: [MaybeUninit<DropCounter<'_>>; 1] = [MaybeUninit::uninit()];
126 Cursor::new(&mut data).finish([DropCounter(&value)]);
127 let [value] = data;
128 unsafe { value.assume_init() };
129 }
130 assert_eq!(value.load(core::sync::atomic::Ordering::SeqCst), 1);
131
132 let value = AtomicU8::new(0);
133 {
134 let mut data: [MaybeUninit<DropCounter<'_>>; 2] =
135 [MaybeUninit::uninit(), MaybeUninit::uninit()];
136 Cursor::new(&mut data).finish([DropCounter(&value), DropCounter(&value)]);
137 let [value0, value1] = data;
138 unsafe { value0.assume_init() };
139 unsafe { value1.assume_init() };
140 }
141 assert_eq!(value.load(core::sync::atomic::Ordering::SeqCst), 2);
142 }
143
144 #[test]
145 fn test_initalized() {
146 let mut data: [MaybeUninit<u8>; 4] = [MaybeUninit::new(0); 4];
147 Cursor::new(&mut data).write([1, 2]).finish([3, 4]);
148 assert_eq!(data.map(|d| unsafe { d.assume_init() }), [1, 2, 3, 4]);
149 }
150}