ltk_ritobin 0.12.0

Ritobin text format parser and writer for League Toolkit
Documentation
use std::{convert::Infallible, fmt, str::FromStr};

use crate::{
    ast::{
        node::{roots::Roots, TypeExpr},
        RootEntry, Value,
    },
    Spanned,
};

mod kind;
use crate::span::Span;
pub use kind::*;

/// The kind of bin a ritobin file describes, read from its `type` root.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FileKind {
    Prop,
    Patch,
    Unknown,
}

impl FileKind {
    /// The `type` root value naming this kind.
    ///
    /// [`Self::Unknown`] names no kind, and is written as `"unknown"` by this method.
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::Prop => "PROP",
            Self::Patch => "PTCH",
            Self::Unknown => "unknown",
        }
    }
}

impl fmt::Display for FileKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl FromStr for FileKind {
    type Err = Infallible;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(match s {
            "PROP" => Self::Prop,
            "PTCH" => Self::Patch,
            _ => Self::Unknown,
        })
    }
}

#[derive(Debug, Clone, Copy)]
pub struct KnownRoot<V> {
    pub(crate) idx: usize,
    pub value: V,
}

impl<V> KnownRoot<V> {
    /// Get the original root that this information was derived from
    pub fn original<'a>(&self, roots: &'a Roots) -> &'a Root {
        &roots.all[self.idx]
    }

    pub fn into_inner(self) -> V {
        self.value
    }
}

#[cfg(feature = "span_print")]
impl<V: crate::span::DebugSpans> crate::span::DebugSpans for KnownRoot<V> {
    fn fmt(&self, text: &str, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("KnownRoot")
            .field("idx", &self.idx)
            .field("value", &crate::span::debug_with_source(&self.value, text))
            .finish()
    }
}

#[derive(Debug, Clone)]
#[cfg_attr(feature = "span_print", derive(crate::span::DebugSpans))]
/// A root is a special-cased property (`key: type = value`), that exists at the top level of a
/// ritobin file.
pub struct Root {
    pub idx: usize,
    pub name: Spanned<RootKind>,
    pub type_expr: Spanned<Option<TypeExpr>>,
    pub value: Option<RootValue>,
}

impl Root {
    /// Get the span of the whole root property
    #[inline(always)]
    #[must_use]
    pub fn span(&self) -> Span {
        self.name.span.cover(
            self.value
                .as_ref()
                .map(RootValue::span)
                .unwrap_or(self.type_expr.span),
        )
    }

    /// The span of the root's value, or of the whole root when it has none.
    #[must_use]
    pub(crate) fn value_span(&self) -> Span {
        self.value.as_ref().map_or(self.span(), RootValue::span)
    }
}

#[derive(Debug, Clone)]
#[cfg_attr(feature = "span_print", derive(crate::span::DebugSpans))]
pub enum RootValue {
    Value(Value),
    /// The resolved entries of the `entries` root. Stores extra span to preserve the original `Value::Map` span
    Entries(Spanned<Vec<RootEntry>>),
}

impl RootValue {
    pub fn as_value(&self) -> Option<&Value> {
        match self {
            RootValue::Value(v) => Some(v),
            _ => None,
        }
    }

    pub fn span(&self) -> Span {
        match self {
            RootValue::Value(v) => v.span(),
            RootValue::Entries(e) => e.span,
        }
    }
}