musli_zerocopy/buf/slice_mut.rs
1use core::borrow::Borrow;
2use core::marker::PhantomData;
3use core::mem::{ManuallyDrop, MaybeUninit, align_of, size_of, size_of_val};
4use core::ops::Deref;
5use core::ptr::NonNull;
6use core::slice::{self, SliceIndex};
7
8#[cfg(feature = "alloc")]
9use alloc::borrow::Cow;
10
11use crate::buf::{self, AllocError, Buf, DefaultAlignment, Padder, StoreBuf};
12use crate::endian::{ByteOrder, DefaultEndian};
13use crate::error::{Error, ErrorKind};
14use crate::mem::PackedMaybeUninit;
15use crate::pointer::{DefaultSize, Ref, Size};
16use crate::traits::{UnsizedZeroCopy, ZeroCopy};
17
18/// A fixed buffer wrapping a `&mut [u8]` with a dynamic alignment.
19///
20/// By default this buffer starts out having the same alignment as `usize`,
21/// making it platform specific. But this alignment can grow in demand to the
22/// types being stored in it.
23///
24/// # Examples
25///
26/// ```
27/// use musli_zerocopy::{SliceMut, ZeroCopy};
28///
29/// #[derive(ZeroCopy)]
30/// #[repr(C, align(128))]
31/// struct Custom {
32/// field: u32,
33/// }
34///
35/// let mut buf = [0; 1024];
36/// let mut buf = SliceMut::new(&mut buf);
37/// buf.store(&Custom { field: 10 })?;
38/// # Ok::<_, musli_zerocopy::Error>(())
39/// ```
40pub struct SliceMut<'a, E = DefaultEndian, O = DefaultSize>
41where
42 E: ByteOrder,
43 O: Size,
44{
45 /// Base data pointer.
46 data: NonNull<MaybeUninit<u8>>,
47 /// The initialized length of the buffer.
48 len: usize,
49 /// The capacity of the buffer.
50 capacity: usize,
51 /// The requested alignment.
52 requested: usize,
53 /// Sticky endianness and pointer size.
54 _marker: PhantomData<(&'a mut [MaybeUninit<u8>], E, O)>,
55}
56
57impl<'a> SliceMut<'a> {
58 /// Construct a new empty buffer with a requested default alignment.
59 ///
60 /// The default alignment is guaranteed to be larger than 0.
61 ///
62 /// # Examples
63 ///
64 /// ```
65 /// use musli_zerocopy::SliceMut;
66 ///
67 /// let mut buf = [0; 1024];
68 /// let buf = SliceMut::new(&mut buf);
69 /// assert!(buf.is_empty());
70 /// ```
71 pub fn new(bytes: &'a mut [u8]) -> Self {
72 Self::with_alignment::<DefaultAlignment>(bytes)
73 }
74
75 /// Construct a new empty buffer with a requested default alignment from an
76 /// uninitialized buffer.
77 ///
78 /// The default alignment is guaranteed to be larger than 0.
79 ///
80 /// # Examples
81 ///
82 /// ```
83 /// use std::mem::MaybeUninit;
84 /// use musli_zerocopy::SliceMut;
85 ///
86 /// let mut buf: [MaybeUninit<u8>; 1024] = unsafe { MaybeUninit::uninit().assume_init() };
87 /// let mut buf = SliceMut::new_uninit(&mut buf);
88 /// assert!(buf.is_empty());
89 ///
90 /// let number = buf.store(&42u32)?;
91 /// # Ok::<_, musli_zerocopy::Error>(())
92 /// ```
93 pub fn new_uninit(bytes: &'a mut [MaybeUninit<u8>]) -> Self {
94 Self::with_alignment_uninit::<DefaultAlignment>(bytes)
95 }
96
97 /// Construct a new empty buffer with the an alignment request matching that
98 /// of `T`.
99 ///
100 /// Note that this does not guarantee that the underlying buffer is aligned.
101 ///
102 /// # Examples
103 ///
104 /// ```
105 /// use musli_zerocopy::SliceMut;
106 ///
107 /// let mut buf = [0; 1024];
108 /// let buf = SliceMut::with_alignment::<u64>(&mut buf);
109 /// assert!(buf.is_empty());
110 /// assert_eq!(buf.requested(), 8);
111 /// ```
112 pub fn with_alignment<T>(bytes: &'a mut [u8]) -> Self {
113 let align = align_of::<T>();
114 let capacity = bytes.len();
115
116 Self {
117 data: unsafe { NonNull::new_unchecked(bytes.as_mut_ptr().cast()) },
118 len: 0,
119 capacity,
120 requested: align,
121 _marker: PhantomData,
122 }
123 }
124
125 /// Construct a new empty buffer with the an alignment request matching that
126 /// of `T` from an uninitialized buffer.
127 ///
128 /// Note that this does not guarantee that the underlying buffer is aligned.
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// use musli_zerocopy::SliceMut;
134 ///
135 /// let mut buf = [0; 1024];
136 /// let buf = SliceMut::with_alignment::<u64>(&mut buf);
137 /// assert!(buf.is_empty());
138 /// assert_eq!(buf.requested(), 8);
139 /// ```
140 pub fn with_alignment_uninit<T>(bytes: &'a mut [MaybeUninit<u8>]) -> Self {
141 let align = align_of::<T>();
142 let capacity = bytes.len();
143
144 Self {
145 data: unsafe { NonNull::new_unchecked(bytes.as_mut_ptr()) },
146 len: 0,
147 capacity,
148 requested: align,
149 _marker: PhantomData,
150 }
151 }
152}
153
154impl<'a, E, O> SliceMut<'a, E, O>
155where
156 E: ByteOrder,
157 O: Size,
158{
159 /// Modify the buffer to utilize the specified pointer size when inserting
160 /// references.
161 ///
162 /// # Examples
163 ///
164 /// ```
165 /// use musli_zerocopy::SliceMut;
166 ///
167 /// let mut buf = SliceMut::new(&mut [0; 16])
168 /// .with_size::<u8>();
169 /// ```
170 #[inline]
171 pub fn with_size<U>(self) -> SliceMut<'a, E, U>
172 where
173 U: Size,
174 {
175 let this = ManuallyDrop::new(self);
176
177 SliceMut {
178 data: this.data,
179 len: this.len,
180 capacity: this.capacity,
181 requested: this.requested,
182 _marker: PhantomData,
183 }
184 }
185
186 /// Modify the buffer to utilize the specified byte order when inserting
187 /// references.
188 ///
189 /// # Examples
190 ///
191 /// ```
192 /// use musli_zerocopy::{endian, SliceMut};
193 ///
194 /// let mut buf = [0; 1024];
195 /// let mut buf = SliceMut::new(&mut buf)
196 /// .with_byte_order::<endian::Little>();
197 /// ```
198 #[inline]
199 pub fn with_byte_order<U>(self) -> SliceMut<'a, U, O>
200 where
201 U: ByteOrder,
202 {
203 let this = ManuallyDrop::new(self);
204
205 SliceMut {
206 data: this.data,
207 len: this.len,
208 capacity: this.capacity,
209 requested: this.requested,
210 _marker: PhantomData,
211 }
212 }
213
214 /// Get the current length of the buffer.
215 ///
216 /// # Examples
217 ///
218 /// ```
219 /// use musli_zerocopy::SliceMut;
220 ///
221 /// let mut buf = [0; 1024];
222 /// let buf = SliceMut::new(&mut buf);
223 /// assert_eq!(buf.len(), 0);
224 /// ```
225 #[inline]
226 pub fn len(&self) -> usize {
227 self.len
228 }
229
230 /// Clear the current buffer.
231 ///
232 /// # Examples
233 ///
234 /// ```
235 /// use musli_zerocopy::SliceMut;
236 ///
237 /// let mut buf = [0; 1024];
238 /// let mut buf = SliceMut::new(&mut buf);
239 /// assert_eq!(buf.capacity(), 1024);
240 /// buf.extend_from_slice(&[1, 2, 3, 4])?;
241 ///
242 /// assert_eq!(buf.len(), 4);
243 /// buf.clear();
244 /// assert_eq!(buf.capacity(), 1024);
245 /// assert_eq!(buf.len(), 0);
246 /// # Ok::<_, musli_zerocopy::Error>(())
247 /// ```
248 #[inline]
249 pub fn clear(&mut self) {
250 self.len = 0;
251 }
252
253 /// Test if the buffer is empty.
254 ///
255 /// # Examples
256 ///
257 /// ```
258 /// use musli_zerocopy::SliceMut;
259 ///
260 /// let mut buf = [0; 1024];
261 /// let buf = SliceMut::new(&mut buf);
262 /// assert!(buf.is_empty());
263 /// ```
264 #[inline]
265 pub fn is_empty(&self) -> bool {
266 self.len == 0
267 }
268
269 /// Get the current capacity of the buffer.
270 ///
271 /// # Examples
272 ///
273 /// ```
274 /// use musli_zerocopy::SliceMut;
275 ///
276 /// let mut buf = [0; 1024];
277 /// let buf = SliceMut::new(&mut buf);
278 /// assert_eq!(buf.capacity(), 1024);
279 /// ```
280 #[inline]
281 pub fn capacity(&self) -> usize {
282 self.capacity
283 }
284
285 /// Return the requested alignment of the buffer.
286 ///
287 /// # Examples
288 ///
289 /// ```
290 /// use musli_zerocopy::SliceMut;
291 ///
292 /// let mut buf = [0; 1024];
293 /// let buf = SliceMut::with_alignment::<u64>(&mut buf);
294 /// assert!(buf.is_empty());
295 /// assert_eq!(buf.requested(), 8);
296 /// ```
297 #[inline]
298 pub fn requested(&self) -> usize {
299 self.requested
300 }
301
302 /// Reserve capacity for at least `capacity` more bytes in this buffer.
303 ///
304 /// # Examples
305 ///
306 /// ```
307 /// use musli_zerocopy::SliceMut;
308 ///
309 /// let mut buf = [0; 1024];
310 /// let mut buf = SliceMut::new(&mut buf);
311 /// assert_eq!(buf.capacity(), 1024);
312 ///
313 /// buf.reserve(10);
314 /// assert!(buf.capacity() >= 10);
315 /// ```
316 #[inline]
317 pub fn reserve(&mut self, capacity: usize) -> Result<(), AllocError> {
318 let new_capacity = self
319 .len
320 .checked_add(capacity)
321 .ok_or_else(|| AllocError::capacity(self.capacity, usize::MAX))?;
322 self.ensure_capacity(new_capacity)
323 }
324
325 /// Advance the length of the owned buffer by `size`.
326 ///
327 /// # Safety
328 ///
329 /// The caller must ensure that bytes up until `len() + size` has been
330 /// initialized in this buffer.
331 #[inline]
332 pub unsafe fn advance(&mut self, size: usize) {
333 self.len += size;
334 }
335
336 /// Get get a raw pointer to the current buffer.
337 #[inline]
338 pub fn as_ptr(&self) -> *const MaybeUninit<u8> {
339 self.data.as_ptr() as *const _
340 }
341
342 /// Get get a raw mutable pointer to the current buffer.
343 #[inline]
344 pub fn as_mut_ptr(&mut self) -> *mut MaybeUninit<u8> {
345 self.data.as_ptr()
346 }
347
348 /// Extract a slice containing the entire buffer.
349 ///
350 /// # Examples
351 ///
352 /// ```
353 /// use musli_zerocopy::SliceMut;
354 ///
355 /// let mut buf = [0; 1024];
356 /// let mut buf = SliceMut::new(&mut buf);
357 /// buf.extend_from_slice(b"hello world")?;
358 /// assert_eq!(buf.as_slice(), b"hello world");
359 /// # Ok::<_, musli_zerocopy::Error>(())
360 /// ```
361 #[inline]
362 pub fn as_slice(&self) -> &[u8] {
363 // SAFETY: We only expose the initialized part of the buffer.
364 unsafe { slice::from_raw_parts(self.as_ptr().cast(), self.len()) }
365 }
366
367 /// Extract a mutable slice containing the entire buffer.
368 ///
369 /// # Examples
370 ///
371 /// ```
372 /// use musli_zerocopy::SliceMut;
373 ///
374 /// let mut buf = [0; 1024];
375 /// let mut buf = SliceMut::new(&mut buf);
376 /// buf.extend_from_slice(b"hello world")?;
377 /// buf.as_mut_slice().make_ascii_uppercase();
378 /// assert_eq!(buf.as_slice(), b"HELLO WORLD");
379 /// # Ok::<_, musli_zerocopy::Error>(())
380 /// ```
381 #[inline]
382 pub fn as_mut_slice(&mut self) -> &mut [u8] {
383 // SAFETY: We only expose the initialized part of the buffer.
384 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr().cast(), self.len()) }
385 }
386
387 /// Access the buffer mutably.
388 ///
389 /// # Examples
390 ///
391 /// ```
392 /// use musli_zerocopy::SliceMut;
393 ///
394 /// let mut buf = [0; 1024];
395 /// let mut buf = SliceMut::new(&mut buf);
396 /// let slice = buf.store_unsized("hello world")?;
397 ///
398 /// // SAFETY: We don't manipulate the underlying buffer in a way which leaves uninitialized data.
399 /// let mut buf = unsafe { buf.as_mut_buf() };
400 ///
401 /// buf.load_mut(slice)?.make_ascii_uppercase();
402 /// assert_eq!(buf.load(slice)?, "HELLO WORLD");
403 /// # Ok::<_, musli_zerocopy::Error>(())
404 /// ```
405 ///
406 /// # Safety
407 ///
408 /// Since this allows the underlying buffer to be mutated, depending on how
409 /// the buffer is used it might result in undefined bit-patterns like
410 /// padding bytes being written to it. The caller must ensure this is not
411 /// done with the structures being written by for example calling
412 /// [`ZeroCopy::initialize_padding()`] after the contents of the buffer is
413 /// modified.
414 ///
415 /// See [`Buf::new_mut`] for more information.
416 #[inline]
417 pub unsafe fn as_mut_buf(&mut self) -> &mut Buf {
418 unsafe { Buf::new_mut(self.as_mut_slice()) }
419 }
420
421 /// Store an uninitialized value.
422 ///
423 /// This allows values to be inserted before they can be initialized, which
424 /// can be useful if you need them to be in a certain location in the buffer
425 /// but don't have access to their value yet.
426 ///
427 /// The memory for `T` will be zero-initialized at [`next_offset<T>()`] and
428 /// the length and alignment requirement of `SliceMut` updated to reflect
429 /// that an instance of `T` has been stored. But that representation might
430 /// not match the representation of `T`[^non-zero].
431 ///
432 /// To get the offset where the value will be written, call
433 /// [`next_offset<T>()`] before storing the value.
434 ///
435 /// > **Note:** this does not return [`std::mem::MaybeUninit`], instead we
436 /// > use an internal [`PackedMaybeUninit`] which is similar but has
437 /// > different properties. See [its documentation][PackedMaybeUninit] for
438 /// > more.
439 ///
440 /// [`next_offset<T>()`]: Self::next_offset()
441 /// [^non-zero]: Like with [`NonZero*`][core::num] types.
442 ///
443 /// # Examples
444 ///
445 /// ```
446 /// use musli_zerocopy::mem::PackedMaybeUninit;
447 /// use musli_zerocopy::{SliceMut, Ref, ZeroCopy};
448 ///
449 /// #[derive(ZeroCopy)]
450 /// #[repr(C)]
451 /// struct Custom { field: u32, string: Ref<str> }
452 ///
453 /// let mut buf = [0; 1024];
454 /// let mut buf = SliceMut::new(&mut buf);
455 /// let reference: Ref<PackedMaybeUninit<Custom>> = buf.store_uninit::<Custom>()?;
456 ///
457 /// let string = buf.store_unsized("Hello World!")?;
458 ///
459 /// buf.load_uninit_mut(reference)?.write(&Custom { field: 42, string });
460 ///
461 /// let reference = reference.assume_init();
462 /// assert_eq!(reference.offset(), 0);
463 /// # Ok::<_, musli_zerocopy::Error>(())
464 /// ```
465 #[inline]
466 pub fn store_uninit<T>(&mut self) -> Result<Ref<PackedMaybeUninit<T>, E, O>, Error>
467 where
468 T: ZeroCopy,
469 {
470 // SAFETY: We've just reserved capacity for this write.
471 unsafe {
472 self.next_offset_with_and_reserve(align_of::<T>(), size_of::<T>())?;
473 let offset = self.len;
474 self.data
475 .as_ptr()
476 .add(self.len)
477 .write_bytes(0, size_of::<T>());
478 self.len += size_of::<T>();
479 Ok(Ref::try_with_metadata_unchecked(offset, ())?)
480 }
481 }
482
483 /// Write a reference that might not have been initialized.
484 ///
485 /// This does not prevent [`Ref`] from different instances of [`SliceMut`]
486 /// from being written. It would only result in garbled data, but wouldn't
487 /// be a safety concern.
488 ///
489 /// > **Note:** this does not return [`std::mem::MaybeUninit`], instead we
490 /// > use an internal [`MaybeUninit`] which is similar but has different
491 /// > properties. See [its documentation][MaybeUninit] for more.
492 ///
493 /// # Panics
494 ///
495 /// Panics if the reference [`Ref::offset()`] and size of `T` does not fit
496 /// within the [`len()`] of the current structure. This might happen if you
497 /// try and use a reference constructed from a different [`SliceMut`]
498 /// instance.
499 ///
500 /// [`len()`]: Self::len()
501 ///
502 /// ```should_panic
503 /// use musli_zerocopy::SliceMut;
504 ///
505 /// let mut buf = [0; 1024];
506 /// let mut buf2 = SliceMut::new(&mut buf);
507 /// buf2.store(&10u32);
508 ///
509 /// let number = buf2.store_uninit::<u32>()?;
510 ///
511 /// let mut buf = [0; 0];
512 /// let mut buf1 = SliceMut::new(&mut buf);
513 /// buf1.load_uninit_mut(number)?;
514 /// # Ok::<_, musli_zerocopy::Error>(())
515 /// ```
516 ///
517 /// # Examples
518 ///
519 /// ```
520 /// use musli_zerocopy::{SliceMut, Ref, ZeroCopy};
521 /// use musli_zerocopy::mem::PackedMaybeUninit;
522 ///
523 /// #[derive(ZeroCopy)]
524 /// #[repr(C)]
525 /// struct Custom { field: u32, string: Ref<str> }
526 ///
527 /// let mut buf = [0; 1024];
528 /// let mut buf = SliceMut::new(&mut buf);
529 /// let reference: Ref<PackedMaybeUninit<Custom>> = buf.store_uninit::<Custom>()?;
530 ///
531 /// let string = buf.store_unsized("Hello World!")?;
532 ///
533 /// buf.load_uninit_mut(reference)?.write(&Custom { field: 42, string });
534 ///
535 /// let reference = reference.assume_init();
536 /// assert_eq!(reference.offset(), 0);
537 /// # Ok::<_, musli_zerocopy::Error>(())
538 /// ```
539 #[inline]
540 pub fn load_uninit_mut<T, U, I>(
541 &mut self,
542 reference: Ref<PackedMaybeUninit<T>, U, I>,
543 ) -> Result<&mut PackedMaybeUninit<T>, Error>
544 where
545 T: ZeroCopy,
546 U: ByteOrder,
547 I: Size,
548 {
549 let at = reference.offset();
550
551 // The whole value must fit in the initialized region, since the
552 // returned reference can be used to write `size_of::<T>()` bytes.
553 if at
554 .checked_add(size_of::<T>())
555 .is_none_or(|end| end > self.len)
556 {
557 return Err(Error::new(ErrorKind::OutOfRangeBounds {
558 range: at..at.saturating_add(size_of::<T>()),
559 len: self.len,
560 }));
561 }
562
563 // SAFETY: We've checked that `at..at + size_of::<T>()` is within the
564 // initialized region of the buffer above. `MaybeUninit<T>` has no
565 // representation requirements and is unaligned.
566 Ok(unsafe { &mut *(self.data.as_ptr().add(at) as *mut PackedMaybeUninit<T>) })
567 }
568
569 /// Insert a value with the given size.
570 ///
571 /// The memory for `T` will be initialized at [`next_offset<T>()`] and the
572 /// length and alignment requirement of `SliceMut` updated to reflect that
573 /// an instance of `T` has been stored.
574 ///
575 /// To get the offset where the value will be written, call
576 /// [`next_offset<T>()`] before storing the value or access the offset
577 /// through the [`Ref::offset`] being returned.
578 ///
579 /// [`next_offset<T>()`]: Self::next_offset
580 ///
581 /// # Examples
582 ///
583 /// ```
584 /// use musli_zerocopy::{SliceMut, Ref, ZeroCopy};
585 ///
586 /// #[derive(ZeroCopy)]
587 /// #[repr(C)]
588 /// struct Custom { field: u32, string: Ref<str> }
589 ///
590 /// let mut buf = [0; 1024];
591 /// let mut buf = SliceMut::new(&mut buf);
592 ///
593 /// let string = buf.store_unsized("string")?;
594 /// let custom = buf.store(&Custom { field: 1, string })?;
595 /// let custom2 = buf.store(&Custom { field: 2, string })?;
596 ///
597 /// let buf = buf.to_requested()?;
598 ///
599 /// let custom = buf.load(custom)?;
600 /// assert_eq!(custom.field, 1);
601 /// assert_eq!(buf.load(custom.string)?, "string");
602 ///
603 /// let custom2 = buf.load(custom2)?;
604 /// assert_eq!(custom2.field, 2);
605 /// assert_eq!(buf.load(custom2.string)?, "string");
606 /// # Ok::<_, musli_zerocopy::Error>(())
607 /// ```
608 ///
609 /// Storing an array:
610 ///
611 ///
612 /// ```
613 /// use musli_zerocopy::{ZeroCopy, SliceMut};
614 ///
615 /// // Element with padding.
616 /// #[derive(Debug, PartialEq, ZeroCopy)]
617 /// #[repr(C)]
618 /// struct Element {
619 /// first: u8,
620 /// second: u32,
621 /// }
622 ///
623 /// let values = [
624 /// Element { first: 0x01, second: 0x01020304u32 },
625 /// Element { first: 0x02, second: 0x01020304u32 }
626 /// ];
627 ///
628 /// let mut buf = [0; 1024];
629 /// let mut buf = SliceMut::new(&mut buf);
630 /// let array = buf.store(&values)?;
631 ///
632 /// let buf = buf.to_requested()?;
633 ///
634 /// assert_eq!(buf.load(array)?, &values);
635 /// # Ok::<_, musli_zerocopy::Error>(())
636 /// ```
637 #[inline]
638 pub fn store<T>(&mut self, value: &T) -> Result<Ref<T, E, O>, Error>
639 where
640 T: ZeroCopy,
641 {
642 self.next_offset_with_and_reserve(align_of::<T>(), size_of::<T>())?;
643
644 // SAFETY: We're ensuring to both align the internal buffer and store
645 // the value.
646 unsafe { self.store_unchecked(value) }
647 }
648
649 /// Insert a value with the given size without ensuring that the buffer has
650 /// the reserved capacity for to or is properly aligned.
651 ///
652 /// This is a low level API which is tricky to use correctly. The
653 /// recommended way to use this is through [`SliceMut::store`].
654 ///
655 /// [`SliceMut::store`]: Self::store
656 ///
657 /// # Safety
658 ///
659 /// The caller has to ensure that the buffer has the required capacity for
660 /// `&T` and is properly aligned. This can easily be accomplished by calling
661 /// [`request_align::<T>()`] followed by [`align_in_place()`] before this
662 /// function. A safe variant of this function is [`SliceMut::store`].
663 ///
664 /// [`align_in_place()`]: Self::align_in_place
665 /// [`SliceMut::store`]: Self::store
666 /// [`request_align::<T>()`]: Self::request_align
667 ///
668 /// # Examples
669 ///
670 /// ```
671 /// use std::mem::size_of;
672 ///
673 /// use musli_zerocopy::{SliceMut, Ref, ZeroCopy};
674 ///
675 /// #[derive(ZeroCopy)]
676 /// #[repr(C, align(4096))]
677 /// struct Custom { field: u32, string: Ref<str> }
678 ///
679 /// let mut buf = [0; 12288];
680 /// let mut buf = SliceMut::new(&mut buf);
681 ///
682 /// let string = buf.store_unsized("string")?;
683 ///
684 /// buf.request_align::<Custom>()?;
685 /// buf.reserve(2 * size_of::<Custom>())?;
686 ///
687 /// // SAFETY: We've ensure that the buffer is internally aligned and sized just above.
688 /// let custom = unsafe { buf.store_unchecked(&Custom { field: 1, string })? };
689 /// let custom2 = unsafe { buf.store_unchecked(&Custom { field: 2, string })? };
690 ///
691 /// let buf = buf.to_requested()?;
692 ///
693 /// let custom = buf.load(custom)?;
694 /// assert_eq!(custom.field, 1);
695 /// assert_eq!(buf.load(custom.string)?, "string");
696 ///
697 /// let custom2 = buf.load(custom2)?;
698 /// assert_eq!(custom2.field, 2);
699 /// assert_eq!(buf.load(custom2.string)?, "string");
700 /// # Ok::<_, musli_zerocopy::Error>(())
701 /// ```
702 #[inline]
703 pub unsafe fn store_unchecked<T>(&mut self, value: &T) -> Result<Ref<T, E, O>, Error>
704 where
705 T: ZeroCopy,
706 {
707 let offset = self.len;
708
709 unsafe {
710 let ptr = NonNull::new_unchecked(self.data.as_ptr().add(offset));
711 buf::store_unaligned(ptr, value);
712 self.len += size_of::<T>();
713 Ok(Ref::try_with_metadata_unchecked(offset, ())?)
714 }
715 }
716
717 /// Either return the current buffer, or allocate one which has a
718 /// [`requested()`] alignment.
719 ///
720 /// [`requested()`]: Self::requested
721 ///
722 /// # Examples
723 ///
724 /// ```
725 /// use musli_zerocopy::SliceMut;
726 ///
727 /// let mut buf = [0; 1024];
728 /// let mut buf = SliceMut::new(&mut buf);
729 ///
730 /// let first = buf.store_unsized("first")?;
731 /// let second = buf.store_unsized("second")?;
732 ///
733 /// let buf = buf.to_requested()?;
734 ///
735 /// assert_eq!(buf.load(first)?, "first");
736 /// assert_eq!(buf.load(second)?, "second");
737 /// # Ok::<_, musli_zerocopy::Error>(())
738 /// ```
739 #[cfg(feature = "alloc")]
740 pub fn to_requested(&self) -> Result<Cow<'_, Buf>, AllocError> {
741 self.to_aligned_with(self.requested)
742 }
743
744 /// Write a value to the buffer.
745 ///
746 /// # Examples
747 ///
748 /// ```
749 /// use musli_zerocopy::SliceMut;
750 ///
751 /// let mut buf = [0; 1024];
752 /// let mut buf = SliceMut::new(&mut buf);
753 ///
754 /// let first = buf.store_unsized("first")?;
755 /// let second = buf.store_unsized("second")?;
756 ///
757 /// let buf = buf.to_requested()?;
758 ///
759 /// assert_eq!(buf.load(first)?, "first");
760 /// assert_eq!(buf.load(second)?, "second");
761 /// # Ok::<_, musli_zerocopy::Error>(())
762 /// ```
763 #[inline]
764 pub fn store_unsized<T>(&mut self, value: &T) -> Result<Ref<T, E, O>, Error>
765 where
766 T: ?Sized + UnsizedZeroCopy,
767 {
768 unsafe {
769 let size = size_of_val(value);
770 self.next_offset_with_and_reserve(T::ALIGN, size)?;
771 let offset = self.len;
772 let ptr = NonNull::new_unchecked(self.data.as_ptr().add(offset));
773 ptr.as_ptr()
774 .copy_from_nonoverlapping(value.as_ptr().cast(), size);
775
776 if T::PADDED {
777 let mut padder = Padder::new(ptr);
778 value.pad(&mut padder);
779 padder.remaining_unsized(value);
780 }
781
782 self.len += size;
783 Ok(Ref::try_with_metadata_unchecked(offset, value.metadata())?)
784 }
785 }
786
787 /// Insert a slice into the buffer.
788 ///
789 /// # Examples
790 ///
791 /// ```
792 /// use musli_zerocopy::SliceMut;
793 ///
794 /// let mut buf = [0; 1024];
795 /// let mut buf = SliceMut::new(&mut buf);
796 ///
797 /// let values = [buf.store_unsized("first")?, buf.store_unsized("second")?];
798 /// let slice = buf.store_slice(&values)?;
799 /// let buf = buf.to_requested()?;
800 ///
801 /// let slice = buf.load(slice)?;
802 /// assert_eq!(buf.load(slice[0])?, "first");
803 /// assert_eq!(buf.load(slice[1])?, "second");
804 /// # Ok::<_, musli_zerocopy::Error>(())
805 /// ```
806 #[inline(always)]
807 pub fn store_slice<T>(&mut self, values: &[T]) -> Result<Ref<[T], E, O>, Error>
808 where
809 T: ZeroCopy,
810 {
811 self.store_unsized(values)
812 }
813
814 /// Extend the buffer from a slice.
815 ///
816 /// Note that this only extends the underlying buffer but does not ensure
817 /// that any required alignment is abided by.
818 ///
819 /// To do this, the caller must call [`request_align()`] with the appropriate
820 /// alignment, otherwise the necessary alignment to decode the buffer again
821 /// will be lost.
822 ///
823 /// [`request_align()`]: Self::request_align
824 ///
825 /// # Errors
826 ///
827 /// This is a raw API, and does not guarantee that any given alignment will
828 /// be respected.
829 ///
830 /// # Examples
831 ///
832 /// ```
833 /// use musli_zerocopy::{SliceMut, Ref};
834 ///
835 /// let mut buf = [0; 1024];
836 /// let mut buf = SliceMut::with_alignment::<()>(&mut buf);
837 ///
838 /// // Add one byte of padding to throw of any incidental alignment.
839 /// buf.extend_from_slice(&[1])?;
840 ///
841 /// let ptr: Ref<u32> = Ref::new(buf.next_offset::<u32>()?);
842 /// buf.extend_from_slice(&[1, 2, 3, 4])?;
843 ///
844 /// let buf = buf.to_requested()?;
845 ///
846 /// assert_eq!(*buf.load(ptr)?, u32::from_ne_bytes([1, 2, 3, 4]));
847 /// # Ok::<_, musli_zerocopy::Error>(())
848 /// ```
849 pub fn extend_from_slice(&mut self, bytes: &[u8]) -> Result<(), AllocError> {
850 self.reserve(bytes.len())?;
851
852 // SAFETY: We just checked that there is space in the slice.
853 unsafe {
854 self.store_bytes(bytes);
855 }
856
857 Ok(())
858 }
859
860 /// Fill and initialize the buffer with `byte` up to `len`.
861 pub(crate) fn fill(&mut self, byte: u8, len: usize) -> Result<(), AllocError> {
862 self.reserve(len)?;
863
864 unsafe {
865 let ptr = self.data.as_ptr().add(self.len);
866 ptr.write_bytes(byte, len);
867 self.len += len;
868 }
869
870 Ok(())
871 }
872
873 /// Store the slice without allocating.
874 ///
875 /// # Safety
876 ///
877 /// The caller must ensure that the buffer has the capacity for
878 /// `bytes.len()` and that the value being stored is not padded as per
879 /// `ZeroCopy::PADDED`.
880 #[inline]
881 pub(crate) unsafe fn store_bytes<T>(&mut self, values: &[T])
882 where
883 T: ZeroCopy,
884 {
885 unsafe {
886 let dst = self.as_mut_ptr().add(self.len);
887 dst.copy_from_nonoverlapping(values.as_ptr().cast(), size_of_val(values));
888 self.len += size_of_val(values);
889 }
890 }
891
892 /// Request that the current buffer should have at least the specified
893 /// alignment and zero-initialize the buffer up to the next position which
894 /// matches the given alignment.
895 ///
896 /// Note that this does not guarantee that the internal buffer is aligned
897 /// in-memory. An instance of [`SliceMut`] cannot guarantee this.
898 ///
899 /// ```
900 /// use musli_zerocopy::SliceMut;
901 /// let mut buf = [0; 1024];
902 /// let mut buf = SliceMut::new(&mut buf);
903 ///
904 /// buf.extend_from_slice(&[1, 2])?;
905 /// buf.request_align::<u32>()?;
906 ///
907 /// assert_eq!(buf.as_slice(), &[1, 2, 0, 0]);
908 /// # Ok::<_, musli_zerocopy::buf::AllocError>(())
909 /// ```
910 ///
911 /// # Safety
912 ///
913 /// The caller must guarantee that the alignment is a power of two.
914 ///
915 /// # Examples
916 ///
917 /// ```
918 /// use musli_zerocopy::SliceMut;
919 ///
920 /// let mut buf = [0; 1024];
921 /// let mut buf = SliceMut::new(&mut buf);
922 /// buf.extend_from_slice(&[1, 2, 3, 4])?;
923 /// buf.request_align::<u64>()?;
924 /// buf.extend_from_slice(&[5, 6, 7, 8])?;
925 ///
926 /// assert_eq!(buf.as_slice(), &[1, 2, 3, 4, 0, 0, 0, 0, 5, 6, 7, 8]);
927 /// # Ok::<_, musli_zerocopy::buf::AllocError>(())
928 /// ```
929 #[inline]
930 pub fn request_align<T>(&mut self) -> Result<(), AllocError>
931 where
932 T: ZeroCopy,
933 {
934 self.requested = self.requested.max(align_of::<T>());
935 self.ensure_aligned_and_reserve(align_of::<T>(), size_of::<T>())?;
936 Ok(())
937 }
938
939 /// Ensure that the current buffer is aligned under the assumption that it
940 /// needs to be allocated.
941 #[inline]
942 fn ensure_aligned_and_reserve(
943 &mut self,
944 align: usize,
945 reserve: usize,
946 ) -> Result<(), AllocError> {
947 let extra = buf::padding_to(self.len, align);
948 self.reserve(extra + reserve)?;
949
950 // SAFETY: The length is ensures to be within the address space.
951 unsafe {
952 self.data.as_ptr().add(self.len).write_bytes(0, extra);
953 self.len += extra;
954 }
955
956 Ok(())
957 }
958
959 /// Construct a pointer aligned for `align` into the current buffer which
960 /// points to the next location that will be written.
961 #[inline]
962 pub(crate) fn next_offset_with_and_reserve(
963 &mut self,
964 align: usize,
965 reserve: usize,
966 ) -> Result<(), AllocError> {
967 if !align.is_power_of_two() {
968 return Err(AllocError::capacity(0, align));
969 }
970 self.requested = self.requested.max(align);
971 self.ensure_aligned_and_reserve(align, reserve)?;
972 Ok(())
973 }
974
975 /// Construct a pointer aligned for `T` into the current buffer which points
976 /// to the next location that will be written.
977 ///
978 /// This ensures that the alignment of the pointer is a multiple of `align`
979 /// and that the current buffer has the capacity for store `T`.
980 ///
981 /// # Examples
982 ///
983 /// ```
984 /// use musli_zerocopy::{SliceMut, Ref};
985 ///
986 /// let mut buf = [0; 1024];
987 /// let mut buf = SliceMut::new(&mut buf);
988 ///
989 /// // Add one byte of padding to throw of any incidental alignment.
990 /// buf.extend_from_slice(&[1])?;
991 ///
992 /// let ptr: Ref<u32> = Ref::new(buf.next_offset::<u32>()?);
993 /// buf.extend_from_slice(&[1, 2, 3, 4])?;
994 ///
995 /// let buf = buf.to_requested()?;
996 ///
997 /// assert_eq!(*buf.load(ptr)?, u32::from_ne_bytes([1, 2, 3, 4]));
998 /// # Ok::<_, musli_zerocopy::Error>(())
999 /// ```
1000 #[inline]
1001 pub fn next_offset<T>(&mut self) -> Result<usize, AllocError> {
1002 // SAFETY: The alignment of `T` is guaranteed to be a power of two. We
1003 // also make sure to reserve space for `T` since it is very likely that
1004 // it will be written immediately after this.
1005 self.next_offset_with_and_reserve(align_of::<T>(), size_of::<T>())?;
1006 Ok(self.len)
1007 }
1008
1009 // Ensure that the new capacity is available or panic.
1010 #[inline]
1011 fn ensure_capacity(&mut self, new_capacity: usize) -> Result<(), AllocError> {
1012 let new_capacity = new_capacity.max(self.requested);
1013
1014 if self.capacity < new_capacity {
1015 return Err(AllocError::capacity(self.capacity, new_capacity));
1016 }
1017
1018 Ok(())
1019 }
1020}
1021
1022/// `SliceMut` are `Send` because the data they reference is unaliased.
1023unsafe impl Send for SliceMut<'_> {}
1024/// `SliceMut` are `Sync` since they are `Send` and the data they reference is
1025/// unaliased.
1026unsafe impl Sync for SliceMut<'_> {}
1027
1028impl<E, O> Deref for SliceMut<'_, E, O>
1029where
1030 E: ByteOrder,
1031 O: Size,
1032{
1033 type Target = Buf;
1034
1035 #[inline]
1036 fn deref(&self) -> &Self::Target {
1037 Buf::new(self.as_slice())
1038 }
1039}
1040
1041impl<E, O> AsRef<Buf> for SliceMut<'_, E, O>
1042where
1043 E: ByteOrder,
1044 O: Size,
1045{
1046 /// Trivial `AsRef<Buf>` implementation for `SliceMut<O>`.
1047 ///
1048 /// # Examples
1049 ///
1050 /// ```
1051 /// use musli_zerocopy::SliceMut;
1052 ///
1053 /// let mut buf = [0; 1024];
1054 /// let mut buf = SliceMut::new(&mut buf);
1055 /// let slice = buf.store_unsized("hello world")?;
1056 ///
1057 /// let buf = buf.to_requested()?;
1058 ///
1059 /// assert_eq!(buf.load(slice)?, "hello world");
1060 /// # Ok::<_, musli_zerocopy::Error>(())
1061 /// ```
1062 #[inline]
1063 fn as_ref(&self) -> &Buf {
1064 self
1065 }
1066}
1067
1068impl<E, O> Borrow<Buf> for SliceMut<'_, E, O>
1069where
1070 E: ByteOrder,
1071 O: Size,
1072{
1073 #[inline]
1074 fn borrow(&self) -> &Buf {
1075 self.as_ref()
1076 }
1077}
1078
1079impl<E, O> StoreBuf for SliceMut<'_, E, O>
1080where
1081 E: ByteOrder,
1082 O: Size,
1083{
1084 type ByteOrder = E;
1085 type Size = O;
1086
1087 #[inline]
1088 fn len(&self) -> usize {
1089 SliceMut::len(self)
1090 }
1091
1092 #[inline]
1093 fn truncate(&mut self, len: usize) {
1094 if self.len > len {
1095 self.len = len;
1096 }
1097 }
1098
1099 #[inline]
1100 fn store_unsized<T>(&mut self, value: &T) -> Result<Ref<T, Self::ByteOrder, Self::Size>, Error>
1101 where
1102 T: ?Sized + UnsizedZeroCopy,
1103 {
1104 SliceMut::store_unsized(self, value)
1105 }
1106
1107 #[inline]
1108 fn store<T>(&mut self, value: &T) -> Result<Ref<T, Self::ByteOrder, Self::Size>, Error>
1109 where
1110 T: ZeroCopy,
1111 {
1112 SliceMut::store(self, value)
1113 }
1114
1115 #[inline]
1116 fn swap<T>(
1117 &mut self,
1118 a: Ref<T, Self::ByteOrder, Self::Size>,
1119 b: Ref<T, Self::ByteOrder, Self::Size>,
1120 ) -> Result<(), Error>
1121 where
1122 T: ZeroCopy,
1123 {
1124 // SAFETY: Since we are swapping two locations which have the same type
1125 // `T`, it does not affect the initialized state of the buffer.
1126 let buf = unsafe { self.as_mut_buf() };
1127 Buf::swap(buf, a, b)
1128 }
1129
1130 #[inline]
1131 fn align_in_place(&mut self) -> Result<(), AllocError> {
1132 // SAFETY: self.requested is guaranteed to be a power of two.
1133 if !buf::is_aligned_with(self.as_ptr(), self.requested) {
1134 return Err(AllocError::misaligned(self.as_ptr(), self.requested));
1135 }
1136
1137 Ok(())
1138 }
1139
1140 #[inline]
1141 fn next_offset<T>(&mut self) -> Result<usize, AllocError> {
1142 SliceMut::next_offset::<T>(self)
1143 }
1144
1145 #[inline]
1146 fn next_offset_with_and_reserve(
1147 &mut self,
1148 align: usize,
1149 reserve: usize,
1150 ) -> Result<(), AllocError> {
1151 SliceMut::next_offset_with_and_reserve(self, align, reserve)
1152 }
1153
1154 #[inline]
1155 fn fill(&mut self, byte: u8, len: usize) -> Result<(), AllocError> {
1156 SliceMut::fill(self, byte, len)
1157 }
1158
1159 #[inline]
1160 fn get<I>(&self, index: I) -> Option<&I::Output>
1161 where
1162 I: SliceIndex<[u8]>,
1163 {
1164 Buf::get(self, index)
1165 }
1166
1167 #[inline]
1168 unsafe fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
1169 where
1170 I: SliceIndex<[u8]>,
1171 {
1172 unsafe { SliceMut::as_mut_buf(self).get_mut(index) }
1173 }
1174
1175 #[inline]
1176 fn as_buf(&self) -> &Buf {
1177 self
1178 }
1179
1180 #[inline]
1181 unsafe fn as_mut_buf(&mut self) -> &mut Buf {
1182 unsafe { SliceMut::as_mut_buf(self) }
1183 }
1184}