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 [`Instruction`] type.

/// An 6800x0 instruction.
#[repr(transparent)]
#[derive(Copy, Debug)]
#[derive_const(
	Clone,
	Eq,
	Ord,
	PartialEq,
	PartialOrd,
)]
pub struct Instruction([u16; 5]);

impl Instruction {
	/// The maximum amount of words in an instruction.
	pub const MAX_LEN: usize = 5;

	/// The `NOP` instruction.
	pub const NOP: Self = Self::from_slice(&[0b0100111001110001]);

	/// Copies words from a slice contiuously into an instruction.
	///
	/// The final buffer is zero-padded to fit. Extraneous words are ignored.
	#[inline]
	#[must_use]
	pub const fn from_slice(s: &[u16]) -> Self {
		let words = match *s {
			[word0, word1, word2, word3, word4, ..] => {
				[word0, word1, word2, word3, word4]
			}

			[word0, word1, word2, word3] => {
				[word0, word1, word2, word3, 0]
			}

			[word0, word1, word2] => {
				[word0, word1, word2, 0, 0]
			}

			[word0, word1] => {
				[word0, word1, 0, 0, 0]
			}

			[word0] => {
				[word0, 0, 0, 0, 0]
			}

			[] => {
				[0, 0, 0, 0, 0]
			}
		};

		Self(words)
	}

	/// Computes the length of the instruction.
	#[expect(clippy::len_without_is_empty)]
	#[must_use]
	pub const fn len(self) -> usize {
		todo!();
	}

	/// Reinterprets the entire instruction buffer as native-endian bytes.
	#[inline]
	#[must_use]
	pub const fn as_ne_bytes(self) -> [u8; 10] {
		let [word0, word1, word2, word3, word4] = self.0;

		let [byte0, byte1] = word0.to_ne_bytes();
		let [byte2, byte3] = word1.to_ne_bytes();
		let [byte4, byte5] = word2.to_ne_bytes();
		let [byte6, byte7] = word3.to_ne_bytes();
		let [byte8, byte9] = word4.to_ne_bytes();

		[
			byte0, byte1, byte2, byte3, byte4, byte5, byte6, byte7,
			byte8, byte9,
		]
	}
}

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