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 [`Config`] structure.

use crate::config::{Builder, Format};
use crate::signal::Mode;

use std::assert_matches;

/// A render configuration.
#[derive(Debug)]
#[derive_const(Clone)]
pub struct Config {
	/// The sampling depth
	pub sample_depth: u8,

	/// The amount of channels.
	pub channel_count: u8,

	/// The frame width.
	pub width: u16,

	/// The frame height.
	pub height: u16,

	/// The total count of frames.
	pub frame_count: u32,

	/// The frame rate.
	pub frame_rate: u32,

	/// The output format.
	pub format: Format,
}

impl Config {
	/// The maximum sampling depth.
	pub const MAX_SAMPLE_DEPTH: u32 = 2_u32.pow(u8::BITS - 1);

	/// The maximum sampling depth.
	pub const MAX_CHANNEL_COUNT: u32 = Mode::MAX_CHANNEL_COUNT;

	/// The maximum frame width/height.
	pub const MAX_WIDTH: u32 = Mode::MAX_WIDTH;

	/// The maximum render frame_count.
	pub const MAX_FRAME_COUNT: u32 = Mode::MAX_FRAME_COUNT;

	/// The maximum frame rate.
	pub const MAX_FRAME_RATE: u32 = 2_u32.pow(u32::BITS - 1);

	/// Constructs a new config from a config builder.
	#[must_use]
	pub fn from_builder(builder: Builder) -> Self {
		let sample_depth = builder.sample_depth
			.expect("expected sampling depth");

		let channel_count = builder.channel_count
			.expect("expected channel count");

		let width = builder.width
			.expect("expected frame width");

		let height = builder.height
			.expect("expected frame height");

		let frame_count = builder.frame_count
			.expect("expected frame count");

		let frame_rate = builder.frame_rate
			.expect("expected frame frame rate");

		let format = builder.format
			.expect("expected output format");

		assert_matches!(
			sample_depth,
			1..=Self::MAX_SAMPLE_DEPTH,
			"sampling depth must be non-zero and at most `{}`",
			Self::MAX_SAMPLE_DEPTH,
		);

		assert_matches!(
			channel_count,
			1..=Self::MAX_CHANNEL_COUNT,
			"channel count must be non-zero and at most `{}`",
			Self::MAX_CHANNEL_COUNT,
		);

		assert_matches!(
			width,
			1..=Self::MAX_WIDTH,
			"frame width must be non-zero and at most `{}`",
			Self::MAX_WIDTH,
		);

		assert_matches!(
			height,
			1..=Self::MAX_WIDTH,
			"frame height must be non-zero and at most `{}`",
			Self::MAX_WIDTH,
		);

		assert_matches!(
			frame_count,
			1..=Self::MAX_FRAME_COUNT,
			"frame count must be non-zero and at most `{}`",
			Self::MAX_FRAME_COUNT,
		);

		assert_matches!(
			frame_rate,
			0..=Self::MAX_FRAME_RATE,
			"frame count may not be greater than `{}`",
			Self::MAX_FRAME_RATE,
		);

		Self {
			sample_depth:  sample_depth as u8,
			channel_count: channel_count as u8,
			width:         width as u16,
			height:        height as u16,
			frame_count,
			frame_rate,
			format,
		}
	}
}