1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use core::marker::PhantomData;
use core::mem::{align_of, size_of};
use core::ops::Range;
use core::ptr::NonNull;
use crate::buf::Validator;
use crate::traits::ZeroCopy;
/// A validation cursor used over a buffer.
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Cursor<'a> {
pointer: NonNull<u8>,
_marker: PhantomData<&'a [u8]>,
}
impl<'a> Cursor<'a> {
/// Construct a new cursor from a checked slice.
pub(crate) fn new(data: &'a [u8]) -> Cursor<'a> {
// SAFETY: The pointer is guaranteed to be non-null.
unsafe {
Self {
pointer: NonNull::new_unchecked(data.as_ptr() as *mut _),
_marker: PhantomData,
}
}
}
/// Construct a validator over the current buffer.
///
/// This is a struct validator, which checks that the fields specified in
/// order of subsequent calls to [`field`] conform to the `repr(C)`
/// representation.
///
/// [`field`]: Validator::field
///
/// # Safety
///
/// The returned validator will have an unbounded lifetime, so it's up to
/// the caller to ensure that the it's not coerced into something
/// inappropriate.
///
/// # Examples
///
/// ```
/// use musli_zerocopy::{AlignedBuf, ZeroCopy};
///
/// #[derive(ZeroCopy)]
/// #[repr(C)]
/// struct Custom {
/// field: u32,
/// field2: u64,
/// }
///
/// let mut buf = AlignedBuf::new();
///
/// let custom = buf.store(&Custom {
/// field: 42,
/// field2: 85,
/// });
///
/// let buf = buf.as_aligned();
///
/// unsafe {
/// let mut v = buf.validate_struct::<Custom>()?;
/// v.field::<u32>()?;
/// v.field::<u64>()?;
/// }
///
/// # Ok::<_, musli_zerocopy::Error>(())
/// ```
#[inline]
pub unsafe fn validate_struct<T>(self) -> Validator<'a, T>
where
T: ZeroCopy,
{
Validator::new(self)
}
/// Raw advance function.
#[inline]
pub(crate) unsafe fn advance_raw(&mut self, len: usize) {
self.pointer = NonNull::new_unchecked(self.pointer.as_ptr().add(len));
}
/// Advance the cursor by the size of `T`.
///
/// # Safety
///
/// Caller must ensure that advancing the pointer by size of `T` doesn't
/// wrap around the address space.
#[inline]
pub unsafe fn advance<T>(&mut self) {
self.advance_raw(size_of::<T>());
}
/// Get the align offset needed to align `T`.
pub(crate) unsafe fn align_offset<T>(&self) -> usize {
self.pointer.as_ptr().align_offset(align_of::<T>())
}
/// Align the pointer to the alignment needed by type `T`.
///
/// # Safety
///
/// Caller must ensure that advancing the pointer to the alignment of `T`
/// doesn't wrap around the address space.
#[inline]
pub unsafe fn align<T>(&mut self) -> usize {
let offset = self.align_offset::<T>();
if offset > 0 {
self.advance_raw(offset);
}
offset
}
/// Cast the current buffer into the given type.
///
/// This is usually only used indirectly by deriving [`ZeroCopy`].
///
/// [`ZeroCopy`]: derive@crate::ZeroCopy
///
/// # Safety
///
/// The caller must ensure that the buffer is correctly sized, aligned and
/// contains a valid bit pattern for the destination type.
///
/// This also returns an unbounded lifetime, which the caller is required to
/// ensure doesn't get coerced to something inappropriate.
#[inline]
pub unsafe fn cast<T>(self) -> &'a T {
&*(self.pointer.as_ptr() as *const u8).cast()
}
/// Cast the current buffer into the given mutable type.
///
/// This is usually only used indirectly by deriving [`ZeroCopy`].
///
/// [`ZeroCopy`]: derive@crate::ZeroCopy
///
/// # Safety
///
/// The caller must ensure that the buffer is correctly sized, aligned and
/// contains a valid bit pattern for the destination type.
///
/// This also returns an unbounded lifetime, which the caller is required to
/// ensure doesn't get coerced to something inappropriate.
#[inline]
pub unsafe fn cast_mut<T>(self) -> &'a mut T {
&mut *self.pointer.as_ptr().cast()
}
/// Get the range corresponding to the cursor.
pub(crate) fn range<T>(&self) -> Range<usize> {
let start = self.pointer.as_ptr() as usize;
let end = start.wrapping_add(size_of::<T>());
start..end
}
}