oct 0.26.0

Octonary transcodings.
Documentation
// Copyright 2024-2025 Gabriel Bjørnager Jensen.
//
// This Source Code Form is subject to the terms of
// the Mozilla Public License, v. 2.0. If a copy of
// the MPL was not distributed with this file, you
// can obtain one at:
// <https://mozilla.org/MPL/2.0/>.

//! The [`IntoOcts`] trait.

mod test;

use crate::{FromOcts, Immutable, Init};

use core::mem::MaybeUninit;
use core::slice;

#[cfg(target_arch = "x86")]
use core::arch::x86::{
	__m128,
	__m128bh,
	__m128d,
	__m128i,
	__m256,
	__m256bh,
	__m256d,
	__m256i,
	__m512,
	__m512bh,
	__m512d,
	__m512i,
};

/// Denotes a type representable as octets (bytes).
///
/// This trait is implemented for any, possible type
/// -- which is safe, given Rust's octonary memory
/// model. The real crème de la crème, however,
/// comes when the implementing type additionally
/// implements [`Init`], as this allows for
/// conversions into readable octets (see
/// [`as_octs`] and [`as_octs_mut`]).
///
/// [`as_octs`]: Self::as_octs
/// [`as_octs_mut`]: Self::as_octs_mut
///
/// # Safety
///
/// The provided functions of this trait may not be
/// overriden.
pub unsafe trait IntoOcts {
	/// Reinterprets the object as a slice of octets.
	#[inline(always)]
	#[must_use]
	fn as_octs(&self) -> &[u8]
	where
		Self: Init + Immutable,
	{
		let len  = size_of_val(self);
		let data = &raw const *self as *const u8;

		// SAFETY: `Init` guarantees initialised data.
		// `size_of_val` guarantees the exact size of the
		// referenced object. Additionally, `Immutable`
		// guarantees interiour-immutability.
		unsafe { slice::from_raw_parts(data, len) }
	}

	/// Reinterprets the object as a mutable slice of
	/// octets.
	///
	/// This method requires [`FromOcts`] as we cannot
	/// alone guarantee whether any write to the
	/// returned slice is valid.
	#[inline(always)]
	#[must_use]
	fn as_octs_mut(&mut self) -> &mut [u8]
	where
		Self: Init + FromOcts,
	{
		let len  = size_of_val(self);
		let data = &raw mut *self as *mut u8;

		// SAFETY: `Init` guarantees initialised data.
		// `size_of_val` guarantees the exact size of the
		// referenced object. Lastly, `FromOcts` guarantees
		// that any write to the returned slice is valid.
		unsafe { slice::from_raw_parts_mut(data, len) }
	}

	/// Reinterprets the object as a slice of
	/// uninitialised octets.
	///
	/// This operation is valid for any, possible type.
	/// Do note, however, that the returned octets can
	/// rarely be used for anything other than copy
	/// operations.
	#[inline(always)]
	#[must_use]
	fn as_uninit_octs(&self) -> &[MaybeUninit<u8>]
	where
		Self: Immutable,
	{
		let len  = size_of_val(self);
		let data = &raw const *self as *const MaybeUninit<u8>;

		// SAFETY: `size_of_val` guarantees the exact size
		// of the referenced object. Additionally,
		// `Immutable` guarantees interiour-immutability.
		unsafe { slice::from_raw_parts(data, len) }
	}

	/// Reinterprets the object as a mutable slice of
	/// uninitialised octets.
	///
	/// The initialisation state of any write to the
	/// returned slice is inherited by the original
	/// object. Thus, this method can be used to
	/// initialise an otherwise uninitialised object.
	///
	/// This method requires [`FromOcts`] as we cannot
	/// alone guarantee whether any write to the
	/// returned slice is valid.
	#[inline(always)]
	#[must_use]
	fn as_uninit_octs_mut(&mut self) -> &mut [MaybeUninit<u8>]
	where
		Self: FromOcts,
	{
		let len  = size_of_val(self);
		let data = &raw mut *self as *mut MaybeUninit<u8>;

		// SAFETY: `size_of_val` guarantees the exact size
		// of the referenced object. `FromOcts` guarantees
		// that any write to the returned slice is valid.
		unsafe { slice::from_raw_parts_mut(data, len) }
	}
}

unsafe impl<T: ?Sized> IntoOcts for T {}