looklook 0.9.0

Descriptive signal synthesiser.
// Copyright 2026 Gabriel Bjørnager Jensen.
//
// This file is part of LOOKLOOK.
//
// LOOKLOOK is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later ver-
// sion.
//
// LOOKLOOK is distributed in the hope that it will be useful, but WITHOUT ANY WAR-
// RANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License along
// with LOOKLOOK. If not, see <https://www.gnu.org/licenses/>.

//! The [`Byte`] type.

use std::fmt::{self, Debug, Display, Formatter};

/// An `8`-bit byte value.
#[repr(transparent)]
#[derive(Copy)]
#[derive_const(
	Clone,
	Default,
	Eq,
	Ord,
	PartialEq,
	PartialOrd,
)]
pub struct Byte(u8);

impl Byte {
	/// The amount of bits in a byte.
	pub const BITS: u32 = 8;

	/// Constructs a long-word from a [`u8`] value.
	#[inline(always)]
	#[must_use]
	pub const fn from_u8(value: u8) -> Self {
		Self(value)
	}

	/// Constructs a long-word from an [`i8`] value.
	#[inline]
	#[must_use]
	pub const fn from_i8(value: i8) -> Self {
		Self(value.cast_unsigned())
	}

	/// Interprets the byte as a [`u8`] value.
	#[inline(always)]
	#[must_use]
	pub const fn as_u8(self) -> u8 {
		self.0
	}

	/// Interprets the byte as a [`i8`] value.
	#[inline]
	#[must_use]
	pub const fn as_i8(self) -> i8 {
		self.0.cast_signed()
	}
}

impl Debug for Byte {
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		let prefix = match self.as_u8().max(1).ilog(16) {
			0 => "$.",
			1 => "$",

			_ => {
				unreachable!();
			}
		};

		write!(f, "{prefix}{:x}", self.as_u8())
	}
}

impl Display for Byte {
	#[inline]
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		Debug::fmt(self, f)
	}
}

const impl From<i8> for Byte {
	#[inline(always)]
	fn from(value: i8) -> Self {
		Self::from_i8(value)
	}
}

const impl From<u8> for Byte {
	#[inline(always)]
	fn from(value: u8) -> Self {
		Self::from_u8(value)
	}
}