looklook 0.6.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
// version.
//
// LOOKLOOK is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; 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 Af-
// fero General Public License along with LOOKLOOK.
// If not, see <https://www.gnu.org/licenses/>.

//! The [`Signal`] type.

mod encode;
mod render;

use crate::signal::Mode;

/// A rendered signal.
#[derive(Clone, Debug)]
#[derive_const(Default)]
pub struct Signal {
	/// The render mode.
	mode: Mode,

	/// The raw signal data.
	///
	/// Note that the contents of this buffer are
	/// currently big-endian (for the sake of the
	/// emulated platform.)
	data: Vec<u8>,
}

impl Signal {
	/// Constructs a new, empty signal.
	#[inline]
	#[must_use]
	pub const fn new() -> Self {
		// NOTE: The default value for `Mode` has a render
		// size of zero, so we can just as well use a de-
		// fault vector.
		Default::default()
	}

	/// Overwrites the signal mode.
	///
	/// The signal buffer is cleared and reallocated to
	/// fit the new mode's needs.
	#[inline]
	pub fn set_mode(&mut self, mode: Mode) {
		self.mode = mode;
		let new_size = self.mode.sample_count();

		// Remember that we do not guarantee specific
		// values for existing data.
		self.data.resize(new_size, 0);
	}

	/// Borrows the mode.
	#[inline]
	#[must_use]
	pub const fn mode(&self) -> &Mode {
		&self.mode
	}

	/// Retrieves the signal size.
	///
	/// This is always equal to the value returned by
	/// [`sample_count`] when used on the current mode,
	/// although this method uses a cached value
	/// instead.
	///
	/// [`sample_count`]: Mode::sample_count
	#[inline]
	#[must_use]
	pub const fn size(&self) -> usize {
		self.data.len()
	}

	/// Tests if the signal is empty.
	#[inline]
	#[must_use]
	pub const fn is_empty(&self) -> bool {
		self.data.is_empty()
	}

	/// Borrows the raw signal data.
	///
	/// The format of the data returned by this method
	/// is unspecified.
	#[inline]
	#[must_use]
	pub const fn data(&self) -> &[u8] {
		&self.data
	}

	/// Mutably borrows the raw signal data.
	///
	/// The format of the data returned by this method
	/// is unspecified.
	#[inline]
	#[must_use]
	pub const fn data_mut(&mut self) -> &mut [u8] {
		&mut self.data
	}
}

impl Drop for Signal {
	#[inline(always)]
	fn drop(&mut self) {}
}