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

mod decode;

use crate::vm::{Exception, InstructionLen, InstructionVtable, Vm};

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

/// An emulated instruction.
#[derive(Debug)]
pub struct Instruction {
	/// The raw, encoded instruction.
	data: [u16; InstructionLen::MAX.get()],

	/// The instruction vtable.
	vtable: &'static InstructionVtable,
}

impl Instruction {
	/// Retrieves the instruction length.
	#[inline(always)]
	#[must_use]
	pub const fn len(&self) -> InstructionLen {
		self.vtable.len
	}
}

const impl Clone for Instruction {
	#[inline]
	fn clone(&self) -> Self {
		Self {
			data:   self.data,
			vtable: self.vtable,
		}
	}
}

impl Display for Instruction {
	#[inline(always)]
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		write!(f, "{:04x}", self.data[0])?;

		for word in self.data.iter().take(self.len().get()).skip(1) {
			write!(f, " {word:04x}")?;
		}

		f.write_str(": ")?;

		(self.vtable.fmt)(self, f)
	}
}

impl Fn<(&mut Vm,)> for Instruction {
	extern "rust-call" fn call(&self, (vm,): (&mut Vm,)) -> Self::Output {
		(self.vtable.exec)(self, vm)
	}
}

impl FnMut<(&mut Vm,)> for Instruction {
	extern "rust-call" fn call_mut(&mut self, args: (&mut Vm,)) -> Self::Output {
		self.call(args)
	}
}

impl FnOnce<(&mut Vm,)> for Instruction {
	type Output = Result<(), Exception>;

	#[inline]
	extern "rust-call" fn call_once(self, args: (&mut Vm,)) -> Self::Output {
		self.call(args)
	}
}