musli_zerocopy/buf/buf.rs
1use core::alloc::Layout;
2use core::fmt;
3use core::mem::{MaybeUninit, align_of, size_of};
4use core::ops::{Index, IndexMut, Range};
5use core::ptr::{NonNull, read_unaligned};
6use core::slice::SliceIndex;
7
8#[cfg(feature = "alloc")]
9use alloc::borrow::{Cow, ToOwned};
10
11#[cfg(feature = "alloc")]
12use crate::buf::OwnedBuf;
13use crate::buf::{self, Bindable, Load, LoadMut, Validator};
14use crate::endian::ByteOrder;
15use crate::error::{Error, ErrorKind};
16use crate::pointer::{Ref, Size};
17use crate::traits::{UnsizedZeroCopy, ZeroCopy};
18
19/// A buffer wrapping a slice of bytes.
20///
21/// # Examples
22///
23/// ```
24/// use musli_zerocopy::{Buf, Ref};
25///
26/// let buf = Buf::new(b"Hello World!");
27/// let unsize: Ref<str> = Ref::with_metadata(0u32, 12);
28///
29/// assert_eq!(buf.load(unsize)?, "Hello World!");
30/// # Ok::<_, musli_zerocopy::Error>(())
31/// ```
32#[repr(transparent)]
33pub struct Buf {
34 data: [u8],
35}
36
37impl Buf {
38 /// Wrap the given bytes as a buffer.
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// use musli_zerocopy::{Buf, Ref};
44 ///
45 /// let buf = Buf::new(b"Hello World!");
46 /// let unsize: Ref<str> = Ref::with_metadata(0u32, 12);
47 ///
48 /// assert_eq!(buf.load(unsize)?, "Hello World!");
49 /// # Ok::<_, musli_zerocopy::Error>(())
50 /// ```
51 #[inline]
52 pub const fn new(data: &[u8]) -> &Buf {
53 // SAFETY: The struct is repr(transparent) over [u8].
54 unsafe { &*(data as *const [u8] as *const Self) }
55 }
56
57 /// Wrap the given bytes as a mutable buffer.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use musli_zerocopy::{Buf, Ref};
63 ///
64 /// let mut bytes: [u8; 12] = *b"Hello World!";
65 ///
66 /// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
67 /// let buf = unsafe { Buf::new_mut(&mut bytes[..]) };
68 /// let unsize = Ref::<str>::with_metadata(0u32, 12);
69 ///
70 /// buf.load_mut(unsize)?.make_ascii_uppercase();
71 /// assert_eq!(buf.load(unsize)?, "HELLO WORLD!");
72 /// # Ok::<_, musli_zerocopy::Error>(())
73 /// ```
74 ///
75 /// # Safety
76 ///
77 /// Since this allows the underlying buffer to be mutated, depending on how
78 /// the buffer is used it might result in undefined bit-patterns like
79 /// padding bytes being written to it. The caller must ensure this is not
80 /// done with the structures being written by for example calling
81 /// [`ZeroCopy::initialize_padding()`] after the contents of the buffer is
82 /// modified.
83 ///
84 /// This can happen if a structure which includes padding is written to a
85 /// buffer (See [musli#283]):
86 ///
87 /// [musli#283]: https://github.com/udoprog/musli/issues/283
88 ///
89 /// ```no_run
90 /// use musli_zerocopy::{Buf, ZeroCopy};
91 ///
92 /// #[derive(ZeroCopy)]
93 /// #[repr(C)]
94 /// struct Example {
95 /// a: u8,
96 /// b: u32,
97 /// }
98 ///
99 /// #[repr(align(8))]
100 /// struct Align([u8; 16]);
101 ///
102 /// let mut bytes = Align([0xff; 16]);
103 /// let buf = unsafe { Buf::new_mut(&mut bytes.0) };
104 /// *buf.load_at_mut::<Example>(0)? = Example { a: 1, b: 2 };
105 ///
106 /// // `bytes` now contains uninitialized data from the padding in `Example`.
107 /// # Ok::<_, musli_zerocopy::Error>(())
108 /// ```
109 #[inline]
110 pub unsafe fn new_mut(data: &mut [u8]) -> &mut Buf {
111 // SAFETY: The struct is repr(transparent) over [u8].
112 unsafe { &mut *(data as *mut [u8] as *mut Self) }
113 }
114
115 /// Construct a buffer with an alignment matching that of `T` which is
116 /// either wrapped in a [`Buf`] if it is already correctly aligned, or
117 /// inside of an allocated [`OwnedBuf`].
118 ///
119 /// # Examples
120 ///
121 /// ```no_run
122 /// use std::fs::read;
123 ///
124 /// use musli_zerocopy::{Buf, Ref, ZeroCopy};
125 ///
126 /// #[derive(ZeroCopy)]
127 /// #[repr(C)]
128 /// struct Person {
129 /// name: Ref<str>,
130 /// age: u32,
131 /// }
132 ///
133 /// let bytes = read("person.bin")?;
134 /// let buf = Buf::new(&bytes).to_aligned::<u128>();
135 ///
136 /// let s = buf.load(Ref::<Person>::zero())?;
137 /// # Ok::<_, anyhow::Error>(())
138 /// ```
139 #[cfg(feature = "alloc")]
140 #[inline]
141 pub fn to_aligned<T>(&self) -> Cow<'_, Buf> {
142 self.to_aligned_with(align_of::<T>())
143 }
144
145 /// Construct a buffer with a specific alignment which is either wrapped in
146 /// a [`Buf`] if it is already correctly aligned, or inside of an allocated
147 /// [`OwnedBuf`].
148 ///
149 /// # Panics
150 ///
151 /// Panics if `align` is not a power of two.
152 ///
153 /// # Examples
154 ///
155 /// ```no_run
156 /// use std::fs::read;
157 ///
158 /// use musli_zerocopy::{Buf, Ref, ZeroCopy};
159 ///
160 /// #[derive(ZeroCopy)]
161 /// #[repr(C)]
162 /// struct Person {
163 /// name: Ref<str>,
164 /// age: u32,
165 /// }
166 ///
167 /// let bytes = read("person.bin")?;
168 /// let buf = Buf::new(&bytes).to_aligned_with(16);
169 ///
170 /// let s = buf.load(Ref::<Person>::zero())?;
171 /// # Ok::<_, anyhow::Error>(())
172 /// ```
173 #[cfg(feature = "alloc")]
174 #[inline]
175 pub fn to_aligned_with(&self, align: usize) -> Cow<'_, Buf> {
176 assert!(align.is_power_of_two(), "Alignment must be power of two");
177
178 // SAFETY: align is checked as a power of two just above.
179 if unsafe { self.is_aligned_with_unchecked(align) } {
180 Cow::Borrowed(self)
181 } else {
182 let mut buf =
183 unsafe { OwnedBuf::with_capacity_and_custom_alignment(self.len(), align) };
184
185 // SAFETY: Space for the slice has been allocated.
186 unsafe {
187 buf.store_bytes(&self.data);
188 }
189
190 Cow::Owned(buf)
191 }
192 }
193
194 /// Get the alignment of the current buffer.
195 pub fn alignment(&self) -> usize {
196 // NB: Maximum alignment supported by Rust is 2^29.
197 1usize << (self.data.as_ptr() as usize).trailing_zeros().min(29)
198 }
199
200 /// Test if the current buffer is layout compatible with the given `T`.
201 ///
202 /// # Examples
203 ///
204 /// ```
205 /// use musli_zerocopy::OwnedBuf;
206 ///
207 /// let mut buf = OwnedBuf::with_alignment::<u32>();
208 /// buf.extend_from_slice(&[1, 2, 3, 4]);
209 ///
210 /// assert!(buf.is_compatible_with::<u32>());
211 /// assert!(!buf.is_compatible_with::<u64>());
212 /// ```
213 #[inline]
214 pub fn is_compatible_with<T>(&self) -> bool
215 where
216 T: ZeroCopy,
217 {
218 self.is_compatible(Layout::new::<T>())
219 }
220
221 /// Ensure that the current buffer is layout compatible with the given `T`.
222 ///
223 /// # Examples
224 ///
225 /// ```
226 /// use musli_zerocopy::OwnedBuf;
227 ///
228 /// let mut buf = OwnedBuf::with_alignment::<u32>();
229 /// buf.extend_from_slice(&[1, 2, 3, 4]);
230 ///
231 /// assert!(buf.ensure_compatible_with::<u32>().is_ok());
232 /// assert!(buf.ensure_compatible_with::<u64>().is_err());
233 /// ```
234 #[inline]
235 pub fn ensure_compatible_with<T>(&self) -> Result<(), Error>
236 where
237 T: ZeroCopy,
238 {
239 if !self.is_compatible_with::<T>() {
240 return Err(Error::new(ErrorKind::LayoutMismatch {
241 layout: Layout::new::<T>(),
242 range: self.range(),
243 }));
244 }
245
246 Ok(())
247 }
248
249 /// Get the length of the backing buffer.
250 ///
251 /// # Examples
252 ///
253 /// ```
254 /// use musli_zerocopy::Buf;
255 ///
256 /// let buf = Buf::new(b"Hello World!");
257 /// assert_eq!(buf.len(), 12);
258 /// ```
259 #[inline]
260 pub fn len(&self) -> usize {
261 self.data.len()
262 }
263
264 /// Test if the backing buffer is empty.
265 ///
266 /// # Examples
267 ///
268 /// ```
269 /// use musli_zerocopy::Buf;
270 ///
271 /// let buf = Buf::new(b"Hello World!");
272 /// assert!(!buf.is_empty());
273 ///
274 /// let buf = Buf::new(b"");
275 /// assert!(buf.is_empty());
276 /// ```
277 #[inline]
278 pub fn is_empty(&self) -> bool {
279 self.data.is_empty()
280 }
281
282 /// Returns a reference to an element or subslice depending on the type of
283 /// index.
284 ///
285 /// - If given a position, returns a reference to the element at that
286 /// position or `None` if out of bounds.
287 /// - If given a range, returns the subslice corresponding to that range, or
288 /// `None` if out of bounds.
289 ///
290 /// # Examples
291 ///
292 /// ```
293 /// use musli_zerocopy::Buf;
294 ///
295 /// let buf = Buf::new(b"Hello World!");
296 ///
297 /// assert_eq!(buf.get(..5), Some(&b"Hello"[..]));
298 /// # Ok::<_, musli_zerocopy::Error>(())
299 /// ```
300 pub fn get<I>(&self, index: I) -> Option<&I::Output>
301 where
302 I: SliceIndex<[u8]>,
303 {
304 self.data.get(index)
305 }
306
307 /// Returns a mutable reference to an element or subslice depending on the
308 /// type of index (see [`get`]) or `None` if the index is out of bounds.
309 ///
310 /// [`get`]: slice::get
311 ///
312 /// # Examples
313 ///
314 /// ```
315 /// use musli_zerocopy::Buf;
316 ///
317 /// let mut bytes: [u8; 12] = *b"Hello World!";
318 ///
319 /// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
320 /// let buf = unsafe { Buf::new_mut(&mut bytes[..]) };
321 ///
322 /// if let Some(bytes) = buf.get_mut(..) {
323 /// bytes.make_ascii_uppercase();
324 /// }
325 ///
326 /// assert_eq!(&buf[..], &b"HELLO WORLD!"[..]);
327 /// # Ok::<_, musli_zerocopy::Error>(())
328 /// ```
329 pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
330 where
331 I: SliceIndex<[u8]>,
332 {
333 self.data.get_mut(index)
334 }
335
336 /// Load the given value as a reference.
337 ///
338 /// # Errors
339 ///
340 /// This will error if the current buffer is not aligned for the type `T`,
341 /// or for other reasons specific to what needs to be done to validate a
342 /// `&T` reference.
343 ///
344 /// # Examples
345 ///
346 /// ```
347 /// use musli_zerocopy::OwnedBuf;
348 ///
349 /// let mut buf = OwnedBuf::new();
350 ///
351 /// let first = buf.store_unsized("first");
352 /// let second = buf.store_unsized("second");
353 ///
354 /// let buf = buf.as_ref();
355 ///
356 /// assert_eq!(buf.load(first)?, "first");
357 /// assert_eq!(buf.load(second)?, "second");
358 /// # Ok::<_, musli_zerocopy::Error>(())
359 /// ```
360 #[inline]
361 pub fn load<T>(&self, ptr: T) -> Result<&T::Target, Error>
362 where
363 T: Load,
364 {
365 ptr.load(self)
366 }
367
368 /// Load a value of type `T` at the given `offset`.
369 ///
370 /// # Errors
371 ///
372 /// This will error if the current buffer is not aligned for the type `T`,
373 /// or for other reasons specific to what needs to be done to validate a
374 /// `&T` reference.
375 ///
376 /// # Examples
377 ///
378 /// ```
379 /// use musli_zerocopy::OwnedBuf;
380 ///
381 /// let mut buf = OwnedBuf::new();
382 ///
383 /// buf.store(&1u32);
384 /// buf.store(&2u32);
385 ///
386 /// let buf = buf.as_ref();
387 ///
388 /// assert_eq!(buf.load_at::<u32>(0)?, &1u32);
389 /// assert_eq!(buf.load_at::<u32>(4)?, &2u32);
390 /// # Ok::<_, musli_zerocopy::Error>(())
391 /// ```
392 pub fn load_at<T>(&self, offset: usize) -> Result<&T, Error>
393 where
394 T: ZeroCopy,
395 {
396 self.load_sized::<T>(offset)
397 }
398
399 /// Load a value of type `T` mutably at the given `offset`.
400 ///
401 /// # Errors
402 ///
403 /// This will error if the current buffer is not aligned for the type `T`,
404 /// or for other reasons specific to what needs to be done to validate a
405 /// `&T` reference.
406 ///
407 /// # Examples
408 ///
409 /// ```
410 /// use musli_zerocopy::OwnedBuf;
411 ///
412 /// let mut buf = OwnedBuf::new();
413 ///
414 /// buf.store(&1u32);
415 /// buf.store(&2u32);
416 ///
417 /// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
418 /// unsafe {
419 /// *buf.as_mut_buf().load_at_mut::<u32>(0)? += 10;
420 /// }
421 ///
422 /// assert_eq!(buf.load_at::<u32>(0)?, &11u32);
423 /// assert_eq!(buf.load_at::<u32>(4)?, &2u32);
424 /// # Ok::<_, musli_zerocopy::Error>(())
425 /// ```
426 pub fn load_at_mut<T>(&mut self, offset: usize) -> Result<&mut T, Error>
427 where
428 T: ZeroCopy,
429 {
430 self.load_sized_mut::<T>(offset)
431 }
432
433 /// Load an unaligned value of type `T` at the given `offset`.
434 ///
435 /// # Errors
436 ///
437 /// This will error if the memory at `offset` is not valid for the type `T`.
438 ///
439 /// # Examples
440 ///
441 /// ```
442 /// use musli_zerocopy::OwnedBuf;
443 ///
444 /// let mut buf = OwnedBuf::new();
445 ///
446 /// buf.store(&42u8);
447 /// buf.store(&[1u8, 0, 0, 0]);
448 /// buf.store(&[2u8, 0, 0, 0]);
449 ///
450 /// assert_eq!(buf.load_at_unaligned::<u32>(1)?, 1u32.to_le());
451 /// assert_eq!(buf.load_at_unaligned::<u32>(5)?, 2u32.to_le());
452 /// # Ok::<_, musli_zerocopy::Error>(())
453 /// ```
454 pub fn load_at_unaligned<T>(&self, offset: usize) -> Result<T, Error>
455 where
456 T: ZeroCopy,
457 {
458 self.load_sized_unaligned::<T>(offset)
459 }
460
461 /// Load the given value as a mutable reference.
462 ///
463 /// # Errors
464 ///
465 /// This will error if the current buffer is not aligned for the type `T`,
466 /// or for other reasons specific to what needs to be done to validate a
467 /// `&mut T` reference.
468 ///
469 /// # Examples
470 ///
471 /// ```
472 /// use musli_zerocopy::OwnedBuf;
473 ///
474 /// let mut buf = OwnedBuf::new();
475 ///
476 /// let first = buf.store_unsized("first");
477 /// let second = buf.store_unsized("second");
478 ///
479 /// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
480 /// let buf = unsafe { buf.as_mut_buf() };
481 ///
482 /// buf.load_mut(first)?.make_ascii_uppercase();
483 ///
484 /// assert_eq!(buf.load(first)?, "FIRST");
485 /// assert_eq!(buf.load(second)?, "second");
486 /// # Ok::<_, musli_zerocopy::Error>(())
487 /// ```
488 #[inline]
489 pub fn load_mut<T>(&mut self, ptr: T) -> Result<&mut T::Target, Error>
490 where
491 T: LoadMut,
492 {
493 ptr.load_mut(self)
494 }
495
496 /// Bind the current buffer to a value.
497 ///
498 /// This provides a more convenient API for complex types like
499 /// [`swiss::MapRef`] and [`swiss::SetRef`], and makes sure that all the
500 /// internals related to the type being bound have been validated.
501 ///
502 /// Binding a type can be be faster in cases where you interact with the
503 /// bound type a lot since accesses do not require validation, but might be
504 /// slower if the access is a "one of", or infrequent.
505 ///
506 /// [`swiss::MapRef`]: crate::swiss::MapRef
507 /// [`swiss::SetRef`]: crate::swiss::SetRef
508 ///
509 /// ## Examples
510 ///
511 /// Binding a [`swiss::Map`] ensures that all the internals of the map have
512 /// been validated:
513 ///
514 /// [`swiss::Map`]: crate::swiss::Map
515 ///
516 /// ```
517 /// use musli_zerocopy::OwnedBuf;
518 /// use musli_zerocopy::swiss;
519 ///
520 /// let mut buf = OwnedBuf::new();
521 ///
522 /// let map = swiss::store_map(&mut buf, [(1, 2), (2, 3)])?;
523 /// let map = buf.bind(map)?;
524 ///
525 /// assert_eq!(map.get(&1)?, Some(&2));
526 /// assert_eq!(map.get(&2)?, Some(&3));
527 /// assert_eq!(map.get(&3)?, None);
528 ///
529 /// assert!(map.contains_key(&1)?);
530 /// assert!(!map.contains_key(&3)?);
531 /// # Ok::<_, musli_zerocopy::Error>(())
532 /// ```
533 #[inline]
534 pub fn bind<T>(&self, ptr: T) -> Result<T::Bound<'_>, Error>
535 where
536 T: Bindable,
537 {
538 ptr.bind(self)
539 }
540
541 /// Cast the current buffer into the given type.
542 ///
543 /// This is usually only used indirectly by deriving [`ZeroCopy`].
544 ///
545 /// [`ZeroCopy`]: derive@crate::ZeroCopy
546 ///
547 /// # Safety
548 ///
549 /// The caller must ensure that the buffer is correctly sized, aligned and
550 /// contains a valid bit pattern for the destination type.
551 #[inline]
552 pub unsafe fn cast<T>(&self) -> &T {
553 unsafe { &*self.data.as_ptr().cast() }
554 }
555
556 /// Cast the current buffer into the given mutable type.
557 ///
558 /// This is usually only used indirectly by deriving [`ZeroCopy`].
559 ///
560 /// [`ZeroCopy`]: derive@crate::ZeroCopy
561 ///
562 /// # Safety
563 ///
564 /// The caller must ensure that the buffer is correctly sized, aligned and
565 /// contains a valid bit pattern for the destination type.
566 #[inline]
567 pub unsafe fn cast_mut<T>(&mut self) -> &mut T {
568 unsafe { &mut *self.data.as_mut_ptr().cast() }
569 }
570
571 /// Construct a validator over the current buffer.
572 ///
573 /// This is a struct validator, which checks that the fields specified in
574 /// order of subsequent calls to [`field`] conform to the `repr(C)`
575 /// representation.
576 ///
577 /// [`field`]: Validator::field
578 ///
579 /// # Examples
580 ///
581 /// ```
582 /// use musli_zerocopy::{OwnedBuf, ZeroCopy};
583 ///
584 /// #[derive(ZeroCopy)]
585 /// #[repr(C)]
586 /// struct Custom { field: u32, field2: u64 }
587 ///
588 /// let mut buf = OwnedBuf::new();
589 ///
590 /// let custom = buf.store(&Custom { field: 42, field2: 85 });
591 ///
592 /// let mut v = buf.validate_struct::<Custom>()?;
593 ///
594 /// // SAFETY: We're only validating fields we know are
595 /// // part of the struct, and do not go beyond.
596 /// unsafe {
597 /// v.field::<u32>()?;
598 /// v.field::<u64>()?;
599 /// }
600 /// # Ok::<_, musli_zerocopy::Error>(())
601 /// ```
602 #[inline]
603 pub fn validate_struct<T>(&self) -> Result<Validator<'_, T>, Error>
604 where
605 T: ZeroCopy,
606 {
607 self.ensure_compatible_with::<T>()?;
608 Ok(Validator::from_slice(&self.data))
609 }
610
611 pub(crate) unsafe fn get_range_from(
612 &self,
613 start: usize,
614 align: usize,
615 ) -> Result<(NonNull<u8>, usize), Error> {
616 if self.data.len() < start {
617 return Err(Error::new(ErrorKind::OutOfRangeFromBounds {
618 range: start..,
619 len: self.data.len(),
620 }));
621 };
622
623 let ptr = unsafe { NonNull::new_unchecked(self.data.as_ptr().add(start) as *mut _) };
624 let remaining = self.data.len() - start;
625
626 if !buf::is_aligned_with(ptr.as_ptr(), align) {
627 return Err(Error::new(ErrorKind::AlignmentRangeFromMismatch {
628 range: start..,
629 align,
630 }));
631 }
632
633 Ok((ptr, remaining))
634 }
635
636 pub(crate) unsafe fn get_mut_range_from(
637 &mut self,
638 start: usize,
639 align: usize,
640 ) -> Result<(NonNull<u8>, usize), Error> {
641 if self.data.len() < start {
642 return Err(Error::new(ErrorKind::OutOfRangeFromBounds {
643 range: start..,
644 len: self.data.len(),
645 }));
646 };
647
648 let ptr = unsafe { NonNull::new_unchecked(self.data.as_mut_ptr().add(start)) };
649 let remaining = self.data.len() - start;
650
651 if !buf::is_aligned_with(ptr.as_ptr(), align) {
652 return Err(Error::new(ErrorKind::AlignmentRangeFromMismatch {
653 range: start..,
654 align,
655 }));
656 }
657
658 Ok((ptr, remaining))
659 }
660
661 /// Get the given range while checking its required alignment.
662 ///
663 /// # Safety
664 ///
665 /// Specified `align` must be a power of two.
666 #[inline]
667 pub(crate) unsafe fn inner_get(
668 &self,
669 start: usize,
670 end: usize,
671 align: usize,
672 ) -> Result<&[u8], Error> {
673 let buf = self.inner_get_unaligned(start, end)?;
674
675 if !buf::is_aligned_with(buf.as_ptr(), align) {
676 return Err(Error::new(ErrorKind::AlignmentRangeMismatch {
677 addr: buf.as_ptr() as usize,
678 range: start..end,
679 align,
680 }));
681 }
682
683 Ok(buf)
684 }
685
686 /// Get the given range mutably while checking its required alignment.
687 ///
688 /// # Safety
689 ///
690 /// Specified `align` must be a power of two.
691 #[inline]
692 pub(crate) unsafe fn inner_get_mut(
693 &mut self,
694 start: usize,
695 end: usize,
696 align: usize,
697 ) -> Result<&mut [u8], Error> {
698 let buf = self.inner_get_mut_unaligned(start, end)?;
699
700 if !buf::is_aligned_with(buf.as_ptr(), align) {
701 return Err(Error::new(ErrorKind::AlignmentRangeMismatch {
702 addr: buf.as_ptr() as usize,
703 range: start..end,
704 align,
705 }));
706 }
707
708 Ok(buf)
709 }
710
711 /// Get the given range without checking that it corresponds to any given
712 /// alignment.
713 #[inline]
714 pub(crate) fn inner_get_unaligned(&self, start: usize, end: usize) -> Result<&[u8], Error> {
715 let Some(data) = self.data.get(start..end) else {
716 return Err(Error::new(ErrorKind::OutOfRangeBounds {
717 range: start..end,
718 len: self.data.len(),
719 }));
720 };
721
722 Ok(data)
723 }
724
725 /// Get the given range mutably without checking that it corresponds to any given alignment.
726 #[inline]
727 pub(crate) fn inner_get_mut_unaligned(
728 &mut self,
729 start: usize,
730 end: usize,
731 ) -> Result<&mut [u8], Error> {
732 let len = self.data.len();
733
734 let Some(data) = self.data.get_mut(start..end) else {
735 return Err(Error::new(ErrorKind::OutOfRangeBounds {
736 range: start..end,
737 len,
738 }));
739 };
740
741 Ok(data)
742 }
743
744 /// Load an unsized reference.
745 #[inline]
746 pub(crate) fn load_unsized<T, O, E>(&self, unsize: Ref<T, E, O>) -> Result<&T, Error>
747 where
748 T: ?Sized + UnsizedZeroCopy,
749 O: Size,
750 E: ByteOrder,
751 {
752 let start = unsize.offset();
753 let metadata = unsize.metadata();
754
755 // SAFETY: Alignment and size is checked just above when getting the
756 // buffer slice.
757 unsafe {
758 let (buf, remaining) = self.get_range_from(start, T::ALIGN)?;
759 let metadata = T::validate_unsized::<E, O>(buf, remaining, metadata)?;
760 Ok(&*T::with_metadata(buf, metadata))
761 }
762 }
763
764 /// Load an unsized mutable reference.
765 #[inline]
766 pub(crate) fn load_unsized_mut<T, O, E>(
767 &mut self,
768 unsize: Ref<T, E, O>,
769 ) -> Result<&mut T, Error>
770 where
771 T: ?Sized + UnsizedZeroCopy,
772 O: Size,
773 E: ByteOrder,
774 {
775 let start = unsize.offset();
776 let metadata = unsize.metadata();
777
778 // SAFETY: Alignment and size is checked just above when getting the
779 // buffer slice.
780 unsafe {
781 let (buf, remaining) = self.get_mut_range_from(start, T::ALIGN)?;
782 let metadata = T::validate_unsized::<E, O>(buf, remaining, metadata)?;
783 Ok(&mut *T::with_metadata_mut(buf, metadata))
784 }
785 }
786
787 /// Load the given sized value as a reference.
788 #[inline]
789 pub(crate) fn load_sized<T>(&self, offset: usize) -> Result<&T, Error>
790 where
791 T: ZeroCopy,
792 {
793 unsafe {
794 let end = offset + size_of::<T>();
795
796 // SAFETY: align_of::<T>() is always a power of two.
797 let buf = self.inner_get(offset, end, align_of::<T>())?;
798
799 if !T::ANY_BITS {
800 // SAFETY: We've checked the size and alignment of the buffer above.
801 // The remaining safety requirements depend on the implementation of
802 // validate.
803 T::validate(&mut Validator::from_slice(buf))?;
804 }
805
806 // SAFETY: Implementing ANY_BITS is unsafe, and requires that the
807 // type being coerced into can really inhabit any bit pattern.
808 Ok(&*buf.as_ptr().cast())
809 }
810 }
811
812 /// Swap a type `P` by reference.
813 ///
814 /// There are no requirements on alignment, and the two swapped locations
815 /// are permitted to overlap. If the values do overlap, then the overlapping
816 /// region of memory from `a` will be used. This is demonstrated in the
817 /// second example below.
818 ///
819 /// # Errors
820 ///
821 /// Errors in case any of the swapped reference is out of bounds for the
822 /// current buffer.
823 ///
824 /// ```
825 /// use musli_zerocopy::{Buf, Ref};
826 ///
827 /// let mut buf = [0, 1, 2, 3];
828 /// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
829 /// let mut buf = unsafe { Buf::new_mut(&mut buf) };
830 ///
831 /// let mut a = Ref::<u32>::new(0u32);
832 /// let mut b = Ref::<u32>::new(4u32);
833 ///
834 /// assert!(buf.swap(a, b).is_err());
835 /// ```
836 ///
837 /// # Examples
838 ///
839 /// ```
840 /// use musli_zerocopy::{Buf, Ref};
841 ///
842 /// let mut buf: [u8; 12] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
843 /// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
844 /// let mut buf = unsafe { Buf::new_mut(&mut buf) };
845 ///
846 /// let mut a = Ref::<u32>::new(2u32);
847 /// let mut b = Ref::<u32>::new(6u32);
848 ///
849 /// buf.swap(a, b)?;
850 ///
851 /// assert_eq!(&buf[..], [0, 1, 6, 7, 8, 9, 2, 3, 4, 5, 10, 11]);
852 /// # Ok::<_, musli_zerocopy::Error>(())
853 /// ```
854 ///
855 /// Overlapping positions:
856 ///
857 /// ```
858 /// use musli_zerocopy::{Buf, Ref};
859 ///
860 /// let mut buf: [u8; 7] = [0, 1, 2, 3, 4, 5, 7];
861 /// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
862 /// let mut buf = unsafe { Buf::new_mut(&mut buf) };
863 ///
864 /// let mut a = Ref::<u32>::new(1u32);
865 /// let mut b = Ref::<u32>::new(2u32);
866 ///
867 /// buf.swap(a, b)?;
868 ///
869 /// assert_eq!(&buf[..], [0, 2, 1, 2, 3, 4, 7]);
870 /// # Ok::<_, musli_zerocopy::Error>(())
871 /// ```
872 #[inline]
873 pub fn swap<T, E, O>(&mut self, a: Ref<T, E, O>, b: Ref<T, E, O>) -> Result<(), Error>
874 where
875 T: ZeroCopy,
876 E: ByteOrder,
877 O: Size,
878 {
879 let a = a.offset();
880 let b = b.offset();
881
882 if a == b {
883 return Ok(());
884 }
885
886 let start = a.max(b);
887 let end = start + size_of::<T>();
888
889 if end > self.data.len() {
890 return Err(Error::new(ErrorKind::OutOfRangeBounds {
891 range: start..end,
892 len: self.data.len(),
893 }));
894 }
895
896 // SAFETY: We've checked that both locations are in bound and we're
897 // ensuring to utilize the appropriate copy primitive depending on
898 // whether two values may or may not overlap.
899 unsafe {
900 let mut tmp = MaybeUninit::<T>::uninit();
901 let base = self.data.as_mut_ptr();
902
903 let tmp = tmp.as_mut_ptr().cast::<u8>();
904 let a = base.add(a);
905 let b = base.add(b);
906
907 tmp.copy_from_nonoverlapping(a, size_of::<T>());
908 a.copy_from(b, size_of::<T>());
909 b.copy_from_nonoverlapping(tmp, size_of::<T>());
910 }
911
912 Ok(())
913 }
914
915 /// Load the given sized value as a mutable reference.
916 #[inline]
917 pub(crate) fn load_sized_mut<T>(&mut self, offset: usize) -> Result<&mut T, Error>
918 where
919 T: ZeroCopy,
920 {
921 let end = offset + size_of::<T>();
922
923 unsafe {
924 // SAFETY: align_of::<T>() is always a power of two.
925 let buf = self.inner_get_mut(offset, end, align_of::<T>())?;
926
927 if !T::ANY_BITS {
928 // SAFETY: We've checked the size and alignment of the buffer above.
929 // The remaining safety requirements depend on the implementation of
930 // validate.
931 T::validate(&mut Validator::from_slice(buf))?;
932 }
933
934 // SAFETY: Implementing ANY_BITS is unsafe, and requires that the
935 // type being coerced into can really inhabit any bit pattern.
936 Ok(&mut *buf.as_mut_ptr().cast())
937 }
938 }
939
940 /// Load the given sized value as a reference.
941 #[inline]
942 pub(crate) fn load_sized_unaligned<T>(&self, start: usize) -> Result<T, Error>
943 where
944 T: ZeroCopy,
945 {
946 let end = start + size_of::<T>();
947
948 unsafe {
949 // SAFETY: align_of::<T>() is always a power of two.
950 let buf = self.inner_get_unaligned(start, end)?;
951
952 if !T::ANY_BITS {
953 // SAFETY: We've checked the size and alignment of the buffer above.
954 // The remaining safety requirements depend on the implementation of
955 // validate.
956 T::validate(&mut Validator::from_slice(buf))?;
957 }
958
959 // SAFETY: Implementing ANY_BITS is unsafe, and requires that the
960 // type being coerced into can really inhabit any bit pattern.
961 Ok(read_unaligned(buf.as_ptr().cast()))
962 }
963 }
964
965 /// Access the underlying slice as a pointer.
966 #[inline]
967 pub(crate) fn as_ptr(&self) -> *const u8 {
968 self.data.as_ptr()
969 }
970
971 /// The numerical range of the buffer.
972 #[inline]
973 pub(crate) fn range(&self) -> Range<usize> {
974 let range = self.data.as_ptr_range();
975 range.start as usize..range.end as usize
976 }
977
978 /// Test if the current buffer is compatible with the given layout.
979 #[inline]
980 pub(crate) fn is_compatible(&self, layout: Layout) -> bool {
981 // SAFETY: Layout::align is a power of two.
982 unsafe {
983 self.is_aligned_with_unchecked(layout.align()) && self.data.len() >= layout.size()
984 }
985 }
986
987 /// Test if the current allocation uses the alignment of `T`.
988 ///
989 /// # Examples
990 ///
991 /// ```
992 /// use musli_zerocopy::OwnedBuf;
993 ///
994 /// #[repr(align(4096))]
995 /// struct Align4096;
996 ///
997 /// let buf = OwnedBuf::new();
998 /// assert!(buf.is_aligned::<u32>());
999 /// // NB: We might have gotten lucky and hit a wide alignment by chance.
1000 /// assert!(buf.is_aligned::<Align4096>() || !buf.is_aligned::<Align4096>());
1001 /// ```
1002 #[inline]
1003 pub fn is_aligned<T>(&self) -> bool {
1004 buf::is_aligned_with(self.as_ptr(), align_of::<T>())
1005 }
1006
1007 /// Test if the current allocation uses the specified alignment.
1008 ///
1009 /// # Panics
1010 ///
1011 /// Panics if the specified alignment is not a power of two.
1012 ///
1013 /// ```should_panic
1014 /// use musli_zerocopy::OwnedBuf;
1015 ///
1016 /// let buf = OwnedBuf::new();
1017 /// buf.is_aligned_with(0);
1018 /// ```
1019 ///
1020 /// # Examples
1021 ///
1022 /// ```
1023 /// use musli_zerocopy::OwnedBuf;
1024 ///
1025 /// let buf = OwnedBuf::new();
1026 /// assert!(buf.is_aligned_with(8));
1027 /// ```
1028 #[inline]
1029 pub fn is_aligned_with(&self, align: usize) -> bool {
1030 assert!(align.is_power_of_two(), "Alignment is not a power of two");
1031 // SAFETY: align is a power of two.
1032 buf::is_aligned_with(self.as_ptr(), align)
1033 }
1034
1035 #[inline]
1036 pub(crate) unsafe fn is_aligned_with_unchecked(&self, align: usize) -> bool {
1037 buf::is_aligned_with(self.as_ptr(), align)
1038 }
1039}
1040
1041impl fmt::Debug for Buf {
1042 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1043 f.debug_tuple("Buf").field(&self.data.len()).finish()
1044 }
1045}
1046
1047#[cfg(feature = "alloc")]
1048impl ToOwned for Buf {
1049 type Owned = OwnedBuf;
1050
1051 #[inline]
1052 fn to_owned(&self) -> Self::Owned {
1053 let mut buf =
1054 unsafe { OwnedBuf::with_capacity_and_custom_alignment(self.len(), self.alignment()) };
1055
1056 buf.extend_from_slice(&self.data);
1057 buf
1058 }
1059}
1060
1061impl AsRef<Buf> for Buf {
1062 /// Trivial `AsRef<Buf>` implementation for `Buf`.
1063 ///
1064 /// # Examples
1065 ///
1066 /// ```
1067 /// use musli_zerocopy::Buf;
1068 ///
1069 /// let buf = Buf::new(&b"Hello World!"[..]);
1070 /// let buf = buf.as_ref();
1071 ///
1072 /// assert_eq!(&buf[..], b"Hello World!");
1073 /// # Ok::<_, musli_zerocopy::Error>(())
1074 /// ```
1075 #[inline]
1076 fn as_ref(&self) -> &Buf {
1077 self
1078 }
1079}
1080
1081impl AsMut<Buf> for Buf {
1082 /// Trivial `AsMut<Buf>` implementation for `Buf`.
1083 ///
1084 /// # Examples
1085 ///
1086 /// ```
1087 /// use musli_zerocopy::Buf;
1088 ///
1089 /// let mut bytes = *b"Hello World!";
1090 /// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
1091 /// let buf = unsafe { Buf::new_mut(&mut bytes[..]) };
1092 /// let buf = buf.as_mut();
1093 ///
1094 /// buf[..5].make_ascii_uppercase();
1095 /// assert_eq!(&buf[..], b"HELLO World!");
1096 /// buf[11] = b'?';
1097 /// assert_eq!(&buf[..], b"HELLO World?");
1098 /// # Ok::<_, musli_zerocopy::Error>(())
1099 /// ```
1100 #[inline]
1101 fn as_mut(&mut self) -> &mut Buf {
1102 self
1103 }
1104}
1105
1106/// Index implementation to get a slice or individual byte out of a [`Buf`].
1107///
1108/// # Examples
1109///
1110/// ```
1111/// use musli_zerocopy::Buf;
1112///
1113/// let buf = Buf::new(b"Hello World!");
1114///
1115/// assert_eq!(&buf[..], &b"Hello World!"[..]);
1116/// assert_eq!(buf[0], b'H');
1117/// # Ok::<_, musli_zerocopy::Error>(())
1118/// ```
1119impl<I> Index<I> for Buf
1120where
1121 I: SliceIndex<[u8]>,
1122{
1123 type Output = I::Output;
1124
1125 #[inline]
1126 fn index(&self, index: I) -> &I::Output {
1127 &self.data[index]
1128 }
1129}
1130
1131/// Index implementation to get a mutable slice or individual byte out of a
1132/// [`Buf`].
1133///
1134/// # Examples
1135///
1136/// ```
1137/// use musli_zerocopy::Buf;
1138///
1139/// let mut bytes = *b"Hello World!";
1140/// // SAFETY: We're not manipulating data in a way which leaves uninitialized regions.
1141/// let mut buf = unsafe { Buf::new_mut(&mut bytes[..]) };
1142///
1143/// buf[..5].make_ascii_uppercase();
1144///
1145/// assert_eq!(&buf[..], &b"HELLO World!"[..]);
1146/// buf[11] = b'?';
1147/// assert_eq!(&buf[..], &b"HELLO World?"[..]);
1148/// # Ok::<_, musli_zerocopy::Error>(())
1149/// ```
1150impl<I> IndexMut<I> for Buf
1151where
1152 I: SliceIndex<[u8]>,
1153{
1154 #[inline]
1155 fn index_mut(&mut self, index: I) -> &mut I::Output {
1156 &mut self.data[index]
1157 }
1158}