use alloc::sync::Arc;
use core::{error, fmt};
#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
use crate::addresses::{AddressRange, Rom, Size, Vram};
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive]
enum AddUserSymbolErrorVariant {
Overlap {
other_name: Arc<str>,
other_vram: Vram,
other_size: Size,
},
Duplicated {
other_name: Arc<str>,
other_vram: Vram,
},
VramOutOfRnage {
segment_ranges: AddressRange<Vram>,
},
RomOutOfRange {
rom: Rom,
segment_ranges: AddressRange<Rom>,
},
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive]
#[cfg_attr(feature = "pyo3", pyclass(module = "spimdisasm"))]
pub struct AddUserSymbolError {
sym_name: Arc<str>,
sym_vram: Vram,
segment_name: Option<Arc<str>>,
variant: AddUserSymbolErrorVariant,
}
impl AddUserSymbolError {
pub(crate) fn new_overlap(
sym_name: Arc<str>,
sym_vram: Vram,
segment_name: Option<Arc<str>>,
other_name: Arc<str>,
other_vram: Vram,
other_size: Size,
) -> Self {
Self {
sym_name,
sym_vram,
segment_name,
variant: AddUserSymbolErrorVariant::Overlap {
other_name,
other_vram,
other_size,
},
}
}
pub(crate) fn new_duplicated(
sym_name: Arc<str>,
sym_vram: Vram,
segment_name: Option<Arc<str>>,
other_name: Arc<str>,
other_vram: Vram,
) -> Self {
Self {
sym_name,
sym_vram,
segment_name,
variant: AddUserSymbolErrorVariant::Duplicated {
other_name,
other_vram,
},
}
}
pub(crate) fn new_vram_out_of_range(
sym_name: Arc<str>,
sym_vram: Vram,
segment_name: Option<Arc<str>>,
segment_ranges: AddressRange<Vram>,
) -> Self {
Self {
sym_name,
sym_vram,
segment_name,
variant: AddUserSymbolErrorVariant::VramOutOfRnage { segment_ranges },
}
}
pub(crate) fn new_rom_out_of_range(
sym_name: Arc<str>,
sym_vram: Vram,
segment_name: Option<Arc<str>>,
rom: Rom,
segment_ranges: AddressRange<Rom>,
) -> Self {
Self {
sym_name,
sym_vram,
segment_name,
variant: AddUserSymbolErrorVariant::RomOutOfRange {
rom,
segment_ranges,
},
}
}
}
impl fmt::Display for AddUserSymbolError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Error when trying to add user symbol `{}` ({:?}) to ",
self.sym_name, self.sym_vram
)?;
if let Some(name) = &self.segment_name {
write!(f, "overlay segment `{name}`")?;
} else {
write!(f, "the global segment")?;
}
write!(f, ": ")?;
match &self.variant {
AddUserSymbolErrorVariant::Overlap {
other_name,
other_vram,
other_size,
} => {
write!(f,
"This symbol overlaps the symbol `{other_name}` (vram: 0x{other_vram}). `{other_name}` has a size of {other_size} bytes",
)
}
AddUserSymbolErrorVariant::Duplicated {
other_name,
other_vram,
} => {
write!(
f,
"It has the same Vram as the symbol `{other_name}` (vram: 0x{other_vram}).",
)
}
AddUserSymbolErrorVariant::VramOutOfRnage { segment_ranges } => {
write!(
f,
"Vram is outside the segment's range `{segment_ranges:?}`"
)
}
AddUserSymbolErrorVariant::RomOutOfRange {
rom,
segment_ranges,
} => {
write!(
f,
"The rom address `0x{:08X}` of the symbol is out of the rom's range `{:?}` of the segment",
rom.inner(),
segment_ranges
)
}
}
}
}
impl error::Error for AddUserSymbolError {}
#[cfg(feature = "pyo3")]
pub(crate) mod python_bindings {
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;
pyo3::create_exception!(spimdisasm, AddUserSymbolError, PyRuntimeError);
impl std::convert::From<super::AddUserSymbolError> for PyErr {
fn from(err: super::AddUserSymbolError) -> PyErr {
AddUserSymbolError::new_err(err.to_string())
}
}
}