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