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 [`transmute`] and [`transmute_unchecked`]
//! functions.

mod test;

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

use core::mem::ManuallyDrop;

/// Transmutes an object to another type.
///
/// The raw octet representation of the object is
/// reused. Note, however, that this isn't necessar-
/// ily equivalent to the new value being equal to
/// the old one (as per [`PartialEq::eq`]).
///
/// # Panics
///
/// This function will panic at translation time if
/// `T` and `U` aren't of the same size.
#[inline]
#[must_use]
#[track_caller]
pub const fn transmute<T, U>(value: T) -> U
where
	T: IntoOcts + Init,
	U: FromOcts,
{
	const {
		assert!(
			size_of::<T>() == size_of::<U>(),
			"cannot transmute types of different sizes",
		);
	}

	// SAFETY: We have asserted that both types are of
	// equal size. Bounds guarantee lack of type in-
	// variants.
	unsafe { transmute_unchecked(value) }
}

/// Unsafely transmutes an object to another type.
///
/// The raw octet representation of the object is
/// reused. Note, however, that this isn't necessar-
/// ily equivalent to the new value being equal to
/// the old one (as per [`PartialEq::eq`]).
///
/// This function should be used rarely, with
/// [`transmute`] guaranteeing safe transmutations
/// instead. This function may be used instead of
/// [`core::mem::transmute`] when transmuting
/// dependently-sized types (e.g. [arrays](array)).
///
/// # Safety
///
/// The sizes of `T` and `U` must be exactly equal.
/// Furthermore, callers guarantee that the exact
/// representation used by the provided value is
/// valid for objects of the destination type.
#[inline(always)]
#[must_use]
#[track_caller]
pub const unsafe fn transmute_unchecked<T, U>(value: T) -> U {
	debug_assert!(
		size_of::<T>() == size_of::<U>(),
		"cannot transmute types of different sizes",
	);

	union Transmute<Src, Dst> {
		src: ManuallyDrop<Src>,
		dst: ManuallyDrop<Dst>,
	}

	let transmute = Transmute { src: ManuallyDrop::new(value) };

	// SAFETY: Caller guarantees correct representa-
	// tion.
	unsafe { ManuallyDrop::into_inner(transmute.dst) }
}