spimdisasm 2.0.0-alpha.1

MIPS disassembler
Documentation
/* SPDX-FileCopyrightText: © 2025 Decompollaborate */
/* SPDX-License-Identifier: MIT */

use alloc::sync::Arc;
use core::{fmt, hash::Hash};

use crate::addresses::{Rom, Vram};

use super::{
    GeneratedBy, LabelMetadataNameDisplay, LabelType, OwnerSegmentKind, ReferrerInfo, Referrers,
};

#[derive(Clone)]
pub struct LabelMetadata {
    generated_by: GeneratedBy,
    vram: Vram,
    owner_segment_kind: OwnerSegmentKind,
    autodetected_type: LabelType,

    rom: Option<Rom>,

    user_declared_name: Option<Arc<str>>,
    user_declared_type: Option<LabelType>,

    is_defined: bool,

    sym_creators: Referrers,
    sym_referrers: Referrers,

    visibility: Option<Arc<str>>,
}

impl LabelMetadata {
    pub(crate) fn new(
        vram: Vram,
        owner_segment_kind: OwnerSegmentKind,
        label_type: LabelType,
    ) -> Self {
        Self {
            generated_by: GeneratedBy::Autogenerated,
            vram,
            owner_segment_kind,
            autodetected_type: label_type,

            rom: None,

            user_declared_name: None,
            user_declared_type: None,

            is_defined: false,

            sym_creators: Referrers::new(),
            sym_referrers: Referrers::new(),

            visibility: None,
        }
    }

    pub(crate) fn new_user(
        vram: Vram,
        owner_segment_kind: OwnerSegmentKind,
        label_type: LabelType,
        name: Arc<str>,
        rom: Option<Rom>,
    ) -> Self {
        Self {
            generated_by: GeneratedBy::UserDeclared,

            rom,

            user_declared_name: Some(name),
            user_declared_type: Some(label_type),

            ..Self::new(vram, owner_segment_kind, label_type)
        }
    }

    pub fn generated_by(&self) -> GeneratedBy {
        self.generated_by
    }

    pub const fn vram(&self) -> Vram {
        self.vram
    }

    pub fn label_type(&self) -> LabelType {
        self.user_declared_type.unwrap_or(self.autodetected_type)
    }
    pub(crate) fn set_autodetected_type(&mut self, new_type: LabelType) {
        if self.autodetected_type.does_new_takes_precedence(new_type) {
            self.autodetected_type = new_type;
        }
    }

    pub fn owner_segment_kind(&self) -> &OwnerSegmentKind {
        &self.owner_segment_kind
    }

    pub fn rom(&self) -> Option<Rom> {
        self.rom
    }
    pub(crate) fn set_rom(&mut self, new_rom: Rom) {
        self.rom = Some(new_rom);
    }

    pub fn display_name(&self) -> LabelMetadataNameDisplay<'_> {
        LabelMetadataNameDisplay::new(self)
    }
    pub(crate) fn user_declared_name(&self) -> Option<Arc<str>> {
        self.user_declared_name.clone()
    }
    #[cfg(feature = "pyo3")]
    pub(crate) fn set_user_declared_name(&mut self, name: Arc<str>) {
        self.user_declared_name = Some(name);
    }

    pub fn is_defined(&self) -> bool {
        self.is_defined
    }
    pub(crate) fn set_defined(&mut self) {
        self.is_defined = true;
    }

    pub(crate) fn add_creator(&mut self, creator: ReferrerInfo) {
        self.sym_creators.add(creator);
    }

    /// How much this label is referenced by something else
    pub fn reference_counter(&self) -> usize {
        self.sym_referrers.reference_counter()
    }
    pub(crate) fn add_referenced_info(&mut self, referrer: ReferrerInfo) {
        self.sym_referrers.add(referrer);
    }

    pub fn visibility(&self) -> Option<Arc<str>> {
        self.visibility.clone()
    }
    pub(crate) fn set_visibility(&mut self, visibility: Arc<str>) {
        self.visibility = Some(visibility)
    }
}

impl PartialEq for LabelMetadata {
    fn eq(&self, other: &Self) -> bool {
        self.vram == other.vram && self.rom == other.rom
    }
}
impl PartialOrd for LabelMetadata {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        match self.vram.partial_cmp(&other.vram) {
            Some(core::cmp::Ordering::Equal) => {}
            ord => return ord,
        };
        self.rom.partial_cmp(&other.rom)
    }
}
impl Hash for LabelMetadata {
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        self.vram.hash(state);
        self.rom.hash(state);
    }
}

impl fmt::Debug for LabelMetadata {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "LabelMetadata {{ vram: 0x{}, name: \"{}\" }}",
            self.vram,
            self.display_name()
        )
    }
}