diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/plain/src/methods.rs | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/plain/src/methods.rs')
-rw-r--r-- | third_party/rust/plain/src/methods.rs | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/third_party/rust/plain/src/methods.rs b/third_party/rust/plain/src/methods.rs new file mode 100644 index 0000000000..58be4a2500 --- /dev/null +++ b/third_party/rust/plain/src/methods.rs @@ -0,0 +1,198 @@ + +use core::{mem, slice}; + +use {Error, Plain}; + +/// Check if a byte slice is aligned suitably for type T. +#[inline] +pub fn is_aligned<T>(bytes: &[u8]) -> bool { + ((bytes.as_ptr() as usize) % mem::align_of::<T>()) == 0 +} + +#[inline(always)] +fn check_alignment<T>(bytes: &[u8]) -> Result<(), Error> { + if is_aligned::<T>(bytes) { + Ok(()) + } else { + Err(Error::BadAlignment) + } +} + +#[inline(always)] +fn check_length<T>(bytes: &[u8], len: usize) -> Result<(), Error> { + if mem::size_of::<T>() > 0 && (bytes.len() / mem::size_of::<T>()) < len { + Err(Error::TooShort) + } else { + Ok(()) + } +} + +/// Interpret data as bytes. Not safe for data with padding. +#[inline(always)] +pub unsafe fn as_bytes<S>(s: &S) -> &[u8] +where + S: ?Sized, +{ + let bptr = s as *const S as *const u8; + let bsize = mem::size_of_val(s); + slice::from_raw_parts(bptr, bsize) +} + +/// Interpret data as mutable bytes. +/// Reading is not safe for data with padding. Writing is ok. +#[inline(always)] +pub unsafe fn as_mut_bytes<S>(s: &mut S) -> &mut [u8] +where + S: Plain + ?Sized, +{ + let bptr = s as *mut S as *mut u8; + let bsize = mem::size_of_val(s); + slice::from_raw_parts_mut(bptr, bsize) +} + +/// Safely converts a byte slice to a reference. +/// +/// However, if the byte slice is not long enough +/// to contain target type, or if it doesn't +/// satisfy the type's alignment requirements, +/// the function returns an error. +/// +/// The function will not fail when the +/// byte slice is longer than necessary, since it is +/// a common practice to interpret the beginning of +/// a slice as a fixed-size header. +/// +/// In many cases it is preferrable to allocate +/// a value/slice of the target type and use +/// [`copy_from_bytes()`](fn.copy_from_bytes.html) to copy +/// data instead. That way, any issues with alignment +/// are implicitly avoided. +/// +#[inline] +pub fn from_bytes<T>(bytes: &[u8]) -> Result<&T, Error> +where + T: Plain, +{ + try!(check_alignment::<T>(bytes)); + try!(check_length::<T>(bytes, 1)); + Ok(unsafe { &*(bytes.as_ptr() as *const T) }) +} + +/// Similar to [`from_bytes()`](fn.from_bytes.html), +/// except that the output is a slice of T, instead +/// of a reference to a single T. All concerns about +/// alignment also apply here, but size is handled +/// differently. +/// +/// The result slice's length is set to be +/// `bytes.len() / size_of::<T>()`, and there +/// are no requirements for input size. I.e. +/// the result may be empty slice, and the input +/// slice doesn't necessarily have to end on `T`'s +/// boundary. The latter has pragmatic reasons: If the +/// length of the array is not known in advance, +/// e.g. if it's terminated by a special element, +/// it's perfectly legal to turn the whole rest +/// of data into `&[T]` and set the proper length +/// after inspecting the array. +/// +/// In many cases it is preferrable to allocate +/// a value/slice of the target type and use +/// [`copy_from_bytes()`](fn.copy_from_bytes.html) to copy +/// data instead. That way, any issues with alignment +/// are implicitly avoided. +/// +#[inline] +pub fn slice_from_bytes<T>(bytes: &[u8]) -> Result<&[T], Error> +where + T: Plain, +{ + let len = bytes.len() / mem::size_of::<T>(); + slice_from_bytes_len(bytes, len) +} + + +/// Same as [`slice_from_bytes()`](fn.slice_from_bytes.html), +/// except that it takes explicit length of the result slice. +/// +/// If the input slice cannot satisfy the length, returns error. +/// The input slice is allowed to be longer than necessary. +/// +#[inline] +pub fn slice_from_bytes_len<T>(bytes: &[u8], len: usize) -> Result<&[T], Error> +where + T: Plain, +{ + try!(check_alignment::<T>(bytes)); + try!(check_length::<T>(bytes, len)); + Ok(unsafe { + slice::from_raw_parts(bytes.as_ptr() as *const T, len) + }) +} + +/// See [`from_bytes()`](fn.from_bytes.html). +/// +/// Does the same, except with mutable references. +/// +#[inline] +pub fn from_mut_bytes<T>(bytes: &mut [u8]) -> Result<&mut T, Error> +where + T: Plain, +{ + try!(check_alignment::<T>(bytes)); + try!(check_length::<T>(bytes, 1)); + Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) }) +} + +/// See [`slice_from_bytes()`](fn.slice_from_bytes.html). +/// +/// Does the same, except with mutable references. +/// +#[inline] +pub fn slice_from_mut_bytes<T>(bytes: &mut [u8]) -> Result<&mut [T], Error> +where + T: Plain, +{ + let len = bytes.len() / mem::size_of::<T>(); + slice_from_mut_bytes_len(bytes, len) +} + +/// See [`slice_from_bytes_len()`](fn.slice_from_bytes_len.html). +/// +/// Does the same, except with mutable references. +/// +#[inline] +pub fn slice_from_mut_bytes_len<T>(bytes: &mut [u8], len: usize) -> Result<&mut [T], Error> +where + T: Plain, +{ + try!(check_alignment::<T>(bytes)); + try!(check_length::<T>(bytes, len)); + Ok(unsafe { + slice::from_raw_parts_mut(bytes.as_ptr() as *mut T, len) + }) +} + +/// Copies data from a byte slice into existing memory. +/// Suitable when [`from_bytes()`](fn.from_bytes.html) would normally +/// be used, but the data is not aligned properly in memory. +/// +/// For an example how to use it, see crate-level documentation. +/// +#[inline] +pub fn copy_from_bytes<T>(into: &mut T, bytes: &[u8]) -> Result<(), Error> +where + T: Plain + ?Sized, +{ + let sz = mem::size_of_val(into); + + if bytes.len() < sz { + return Err(Error::TooShort); + } + + unsafe { + as_mut_bytes(into).copy_from_slice(&bytes[..sz]); + } + + Ok(()) +} |