ltk_ritobin 0.12.0

Ritobin text format parser and writer for League Toolkit
Documentation
use std::fmt::Display;

use ltk_hash::{BinHash, HashValue};

use crate::span::Span;
use crate::Spanned;

#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "span_print", derive(crate::span::DebugSpans))]
pub struct HashedLiteral<H> {
    pub value: H,
    /// What this hash was originally, before being coerced to a hash
    pub originally: Spanned<Originally>,
}

/// See [`HashedLiteral::originally`] for information.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Originally {
    /// A `HexLit` token (`0xdeadbeef`), its value was used directly & no coercion was needed
    #[default]
    HexLit,
    /// A `String` token (`"hello"`), its text value was hashed
    /// (i.e. with all escapes resolved & quotes excluded)
    String,
    /// A `Name` token (`helloWorld`), the text of that token was hashed
    Name,
    /// A `Null` token. `pointer` & `embed` can be constructed from `null`.
    Null,
}

impl<H> HashedLiteral<H> {
    #[inline(always)]
    #[must_use]
    pub fn new(span: Span, originally: Originally, value: H) -> Self {
        Self {
            value,
            originally: Spanned::new(span, originally),
        }
    }

    #[inline(always)]
    #[must_use]
    pub fn with_span(mut self, span: Span) -> Self {
        self.originally.span = span;
        self
    }

    #[inline(always)]
    #[must_use]
    pub fn with_value<NewHash>(self, value: NewHash) -> HashedLiteral<NewHash> {
        HashedLiteral {
            value,
            originally: self.originally,
        }
    }

    /// The span of the originating token that coerced to this hash
    #[inline(always)]
    #[must_use]
    pub fn span(&self) -> Span {
        self.originally.span
    }

    /// What this hash was originally, before being coerced to a hash
    #[inline(always)]
    #[must_use]
    pub fn original_kind(&self) -> Originally {
        self.originally.value
    }

    #[inline(always)]
    #[must_use]
    /// Whether this hash was originally a hash literal (`HexLit` token)
    pub fn was_hash(&self) -> bool {
        matches!(self.original_kind(), Originally::HexLit)
    }
    #[inline(always)]
    #[must_use]
    /// Whether this hash was originally a string literal, like for a property key (`String` token)
    pub fn was_str(&self) -> bool {
        matches!(self.original_kind(), Originally::String)
    }
    #[inline(always)]
    #[must_use]
    /// Whether this hash was originally a raw name, like for a class hash (`Name` token)
    pub fn was_name(&self) -> bool {
        matches!(self.original_kind(), Originally::Name)
    }
}

impl HashedLiteral<HashValue> {
    /// Returns the literal with a [`BinHash`] value. Returns `None` if the width is 8.
    #[inline(always)]
    #[must_use]
    pub fn try_as_bin_hash(self) -> Option<HashedLiteral<BinHash>> {
        let value = self.value.try_as_bin_hash()?;
        Some(self.with_value(value))
    }
}

impl<H: Display> Display for HashedLiteral<H> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "0x{}", self.value)
    }
}