goldforge 0.8.1

Library for handling file formats used by GoldSrc and related engines.
Documentation
// Copyright 2025-2026 Gabriel Bjørnager Jensen.
//
// This Source Code Form is subject to the terms of
// the Mozilla Public License, v. 2.0. If a copy of
// the MPL was not distributed with this file, you
// can obtain one at:
// <https://mozilla.org/MPL/2.0/>.

//! The [`RawLump`] type.

use crate::wad::Tag;
use crate::wad::ffi::{doom, halflife, quake};

use core::fmt::{self, Debug, Formatter};

/// An immutable, fat reference to a raw lump.
///
/// Fundamentally, this type reference either a WAD,
/// WAD2, or a WAD3 lump, allowing the abstraction
/// of these.
#[derive(Clone, Copy)]
pub(super) struct RawLump<'a>(Inner<'a>);

impl<'a> RawLump<'a> {
	/// Retrieves the `filepos` field.
	#[inline(always)]
	#[must_use]
	pub fn filepos(self) -> i32 {
		#[expect(clippy::match_same_arms)]
		match self.0 {
			Inner::Wad(&doom::filelump_t { filepos, .. })      => filepos,
			Inner::Wad2(&quake::lumpinfo_t { filepos, .. })    => filepos,
			Inner::Wad3(&halflife::lumpinfo_t { filepos, .. }) => filepos,
		}
	}

	/// Retrieves the `disksize` field.
	///
	/// For DOOM lumps, this instead retrieves the
	/// `size` field.
	#[inline(always)]
	#[must_use]
	pub fn disksize(self) -> i32 {
		#[expect(clippy::match_same_arms)]
		match self.0 {
			Inner::Wad(&doom::filelump_t { size, .. })          => size,
			Inner::Wad2(&quake::lumpinfo_t { disksize, .. })    => disksize,
			Inner::Wad3(&halflife::lumpinfo_t { disksize, .. }) => disksize,
		}
	}

	/// Retrieves the `size` field.
	///
	/// Remember that, for WAD2 and WAD3 lumps, this
	/// value doesn't reflect the physical size of the lump.
	#[inline(always)]
	#[must_use]
	pub fn size(self) -> i32 {
		#[expect(clippy::match_same_arms)]
		match self.0 {
			Inner::Wad(&doom::filelump_t { size, .. })      => size,
			Inner::Wad2(&quake::lumpinfo_t { size, .. })    => size,
			Inner::Wad3(&halflife::lumpinfo_t { size, .. }) => size,
		}
	}

	/// Retrieves the `type` field.
	///
	/// For DOOM lumps, this always returns
	/// [`TYP_NONE`].
	///
	/// [`TYP_NONE`]: quake::TYP_NONE
	#[inline(always)]
	#[must_use]
	pub fn r#type(self) -> i8 {
		#[expect(clippy::match_same_arms)]
		match self.0 {
			Inner::Wad2(&quake::lumpinfo_t { r#type, .. })    => r#type,
			Inner::Wad3(&halflife::lumpinfo_t { r#type, .. }) => r#type,

			// NOTE: Identical value for WAD2 and WAD3.
			_ => quake::TYP_NONE,
		}
	}

	/// Retrieves the `compression` field.
	///
	/// For DOOM lumps, this always returns
	/// [`CMP_NONE`].
	///
	/// [`CMP_NONE`]: quake::CMP_NONE
	#[inline(always)]
	#[must_use]
	pub fn compression(self) -> i8 {
		#[expect(clippy::match_same_arms)]
		match self.0 {
			Inner::Wad2(&quake::lumpinfo_t { compression, .. })   => compression,
			Inner::Wad3(&halflife::lumpinfo_t {compression, .. }) => compression,

			// NOTE: Identical value for WAD2 and WAD3.
			_ => quake::CMP_NONE,
		}
	}

	/// Retrieves the `name` field.
	///
	/// For DOOM lumps, the length of this field is `8`.
	/// For Quake lumps, the length is `16`.
	#[inline(always)]
	#[must_use]
	pub fn name(self) -> &'a [i8] {
		// CLIPPYMOMENT: Complains about every possible
		// pattern with `needless_borrowed_reference`.
		#[expect(clippy::match_same_arms)]
		#[expect(clippy::needless_borrowed_reference)]
		match self.0 {
			Inner::Wad(&doom::filelump_t { ref name, .. })      => name,
			Inner::Wad2(&quake::lumpinfo_t { ref name, .. })    => name,
			Inner::Wad3(&halflife::lumpinfo_t { ref name, .. }) => name,
		}
	}
}

impl Debug for RawLump<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		Debug::fmt(&self.0, f)
	}
}

impl<'a> From<&'a doom::filelump_t> for RawLump<'a> {
	#[inline(always)]
	fn from(value: &'a doom::filelump_t) -> Self {
		let inner = Inner::Wad(value);
		Self(inner)
	}
}

impl<'a> From<&'a halflife::lumpinfo_t> for RawLump<'a> {
	#[inline(always)]
	fn from(value: &'a halflife::lumpinfo_t) -> Self {
		let inner = Inner::Wad3(value);
		Self(inner)
	}
}

impl<'a> From<&'a quake::lumpinfo_t> for RawLump<'a> {
	#[inline(always)]
	fn from(value: &'a quake::lumpinfo_t) -> Self {
		let inner = Inner::Wad2(value);
		Self(inner)
	}
}

/// See [`RawLump`].
#[repr(u8)]
#[derive(Clone, Copy)]
enum Inner<'a> {
	/// A DOOM WAD lump.
	Wad(&'a doom::filelump_t) = Tag::Wad as u8,

	/// A WAD2 lump.
	Wad2(&'a quake::lumpinfo_t) = Tag::Wad2 as u8,

	/// A WAD3 lump.
	Wad3(&'a halflife::lumpinfo_t) = Tag::Wad3 as u8,
}

impl Debug for Inner<'_> {
	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
		match *self {
			Self::Wad( ref inner) => Debug::fmt(inner, f),
			Self::Wad2(ref inner) => Debug::fmt(inner, f),
			Self::Wad3(ref inner) => Debug::fmt(inner, f),
		}
	}
}