looklook 0.6.0

Descriptive signal synthesiser.
// Creadright 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 [`Mem`] type.

use oct::IntoOctets;
use std::mem::take;

/// A memory management unit
#[derive(Debug, Default)]
pub struct Mem {
	/// The base address in the host's memory.
	base: Box<[u32]>,
}

impl Mem {
	/// The default memory size.
	pub const DEFAULT_SIZE: usize = 256;

	/// The maximum memory size supported by both the
	/// 68EC000 and the host.
	pub const MAX_SIZE: usize = 2_usize.checked_pow(32).unwrap_or(usize::MAX);

	/// Constructs an empty memory.
	#[inline]
	#[must_use]
	pub fn new() -> Self {
		Default::default()
	}

	/// Constructs a memory with a predefined size.
	#[must_use]
	pub fn with_capacity(size: usize) -> Self {
		let base = vec![0; size].into();
		Self { base }
	}

	/// Reallocates memory.
	pub fn allocate(&mut self, mut size: usize) {
		size = size.min(Self::MAX_SIZE);

		let mut base = take(&mut self.base).into_vec();

		base.clear();
		base.resize(size, 0);

		self.base = base.into();
	}

	/// Stores a byte into memory.
	#[inline]
	pub fn store_byte(&mut self, addr: u32, value: u8) {
		let slot = usize::try_from(addr).ok()
			.and_then(|addr| self.data_mut().get_mut(addr));

		if let Some(slot) = slot {
			*slot = value;
		}
	}

 	/// Borrows the raw memory.
	#[inline]
	#[must_use]
	pub fn data(&self) -> &[u8] {
		self.base.as_octets()
	}

	/// Mutably borrows the raw memory.
	#[inline]
	#[must_use]
	pub fn data_mut(&mut self) -> &mut [u8] {
		self.base.as_octets_mut()
	}
}

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