looklook 0.8.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 [`Sr`] type.

use crate::vm::TraceMode;

use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter};

/// The `SR` status register.
#[repr(transparent)]
#[derive(Copy)]
#[derive_const(Clone)]
pub struct Sr(u16);

impl Sr {
	/// Constructs a new, default status register.
	#[inline(always)]
	#[must_use]
	pub const fn new() -> Self {
		Self::from_u16(0b0000_0000_0000_0000)
	}

	/// Reinterprets a [`u16`] scalar as a status register.
	///
	/// Unimplemented bits are masked away.
	#[inline]
	#[must_use]
	pub const fn from_u16(mut value: u16) -> Self {
		value &= 0b1111_1111_1111_1111;

		Self(value)
	}

	/// Reads the tracing mode.
	#[inline]
	#[must_use]
	pub const fn trace_mode(&self) -> TraceMode {
		TraceMode::from_u16(self.as_u16())
	}

	/// Reinterprets the status register as a [`u16`] scalar.
	///
	/// Unimplemented bits are read as zero.
	#[inline(always)]
	#[must_use]
	pub const fn as_u16(self) -> u16 {
		self.0
	}
}

impl Debug for Sr {
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		let nibble0 = self.as_u16() & 0b1111;
		let nibble1 = self.as_u16() >> 4 & 0b1111;
		let nibble2 = self.as_u16() >> 8 & 0b1111;
		let nibble3 = self.as_u16() >> 12;

		write!(f, "0b{nibble0:04b}_{nibble1:04b}_{nibble2:04b}_{nibble3:04b}")
	}
}

const impl Default for Sr {
	#[inline(always)]
	fn default() -> Self {
		const { Self::new() }
	}
}

const impl Eq for Sr {}

const impl Ord for Sr {
	#[inline]
	fn cmp(&self, other: &Self) -> Ordering {
		self.as_u16().cmp(&other.as_u16())
	}
}

const impl PartialEq for Sr {
	#[inline]
	fn eq(&self, other: &Self) -> bool {
		self.as_u16().eq(&other.as_u16())
	}
}

const impl PartialOrd for Sr {
	#[inline]
	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
		Some(self.cmp(other))
	}
}