rson-core 1.0.0

Core parsing and value types for RSON
Documentation
//! RSON value types and data model.
//!
//! This module defines the core `RsonValue` enum that represents all possible
//! values in the RSON format, along with supporting types and utilities.

use core::fmt;
#[cfg(not(feature = "std"))]
use alloc::{
    collections::BTreeMap as HashMap,
    string::{String, ToString},
    vec::Vec,
};

use indexmap::IndexMap;

/// A value in the RSON format.
///
/// This enum represents all possible values that can be expressed in RSON,
/// including both JSON-compatible values and RSON-specific extensions.
#[derive(Debug, Clone, PartialEq)]
pub enum RsonValue {
    /// Null value (maps to None in Option types)
    Null,
    
    /// Boolean value
    Bool(bool),
    
    /// Integer value
    Int(i64),
    
    /// Floating-point value  
    Float(f64),
    
    /// String value
    String(String),
    
    /// Character value (RSON extension)
    Char(char),
    
    /// Array of values
    Array(Vec<RsonValue>),
    
    /// Map with string keys (like JSON object)
    Map(IndexMap<String, RsonValue>),
    
    /// Struct with named fields (RSON extension)
    Struct {
        name: String,
        fields: IndexMap<String, RsonValue>,
    },
    
    /// Tuple with ordered values (RSON extension)
    Tuple(Vec<RsonValue>),
    
    /// Enum variant (RSON extension)
    Enum {
        name: String,
        variant: String,
        value: Option<Box<RsonValue>>,
    },
    
    /// Optional value (RSON extension)
    Option(Option<Box<RsonValue>>),
}

/// The type of an RSON value.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RsonType {
    Null,
    Bool,
    Int,
    Float,
    String,
    Char,
    Array,
    Map,
    Struct,
    Tuple,
    Enum,
    Option,
}

impl RsonValue {
    /// Get the type of this value.
    pub fn value_type(&self) -> RsonType {
        match self {
            RsonValue::Null => RsonType::Null,
            RsonValue::Bool(_) => RsonType::Bool,
            RsonValue::Int(_) => RsonType::Int,
            RsonValue::Float(_) => RsonType::Float,
            RsonValue::String(_) => RsonType::String,
            RsonValue::Char(_) => RsonType::Char,
            RsonValue::Array(_) => RsonType::Array,
            RsonValue::Map(_) => RsonType::Map,
            RsonValue::Struct { .. } => RsonType::Struct,
            RsonValue::Tuple(_) => RsonType::Tuple,
            RsonValue::Enum { .. } => RsonType::Enum,
            RsonValue::Option(_) => RsonType::Option,
        }
    }
    
    /// Check if this value is null.
    pub fn is_null(&self) -> bool {
        matches!(self, RsonValue::Null)
    }
    
    /// Check if this value is a boolean.
    pub fn is_bool(&self) -> bool {
        matches!(self, RsonValue::Bool(_))
    }
    
    /// Check if this value is a number (int or float).
    pub fn is_number(&self) -> bool {
        matches!(self, RsonValue::Int(_) | RsonValue::Float(_))
    }
    
    /// Check if this value is a string.
    pub fn is_string(&self) -> bool {
        matches!(self, RsonValue::String(_))
    }
    
    /// Check if this value is an array.
    pub fn is_array(&self) -> bool {
        matches!(self, RsonValue::Array(_))
    }
    
    /// Check if this value is a map or struct.
    pub fn is_object(&self) -> bool {
        matches!(self, RsonValue::Map(_) | RsonValue::Struct { .. })
    }
    
    /// Try to get this value as a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match self {
            RsonValue::Bool(b) => Some(*b),
            _ => None,
        }
    }
    
    /// Try to get this value as an integer.
    pub fn as_i64(&self) -> Option<i64> {
        match self {
            RsonValue::Int(i) => Some(*i),
            RsonValue::Float(f) if f.fract() == 0.0 => Some(*f as i64),
            _ => None,
        }
    }
    
    /// Try to get this value as a float.
    pub fn as_f64(&self) -> Option<f64> {
        match self {
            RsonValue::Float(f) => Some(*f),
            RsonValue::Int(i) => Some(*i as f64),
            _ => None,
        }
    }
    
    /// Try to get this value as a string reference.
    pub fn as_str(&self) -> Option<&str> {
        match self {
            RsonValue::String(s) => Some(s),
            _ => None,
        }
    }
    
    /// Try to get this value as an array reference.
    pub fn as_array(&self) -> Option<&Vec<RsonValue>> {
        match self {
            RsonValue::Array(arr) => Some(arr),
            _ => None,
        }
    }
    
    /// Try to get this value as a map reference.
    pub fn as_map(&self) -> Option<&IndexMap<String, RsonValue>> {
        match self {
            RsonValue::Map(map) => Some(map),
            _ => None,
        }
    }
    
    /// Get the value at the given index if this is an array.
    pub fn get_index(&self, index: usize) -> Option<&RsonValue> {
        match self {
            RsonValue::Array(arr) => arr.get(index),
            RsonValue::Tuple(arr) => arr.get(index),
            _ => None,
        }
    }
    
    /// Get the value with the given key if this is a map or struct.
    pub fn get(&self, key: &str) -> Option<&RsonValue> {
        match self {
            RsonValue::Map(map) => map.get(key),
            RsonValue::Struct { fields, .. } => fields.get(key),
            _ => None,
        }
    }
    
    /// Create a Some variant of Option.
    pub fn some(value: RsonValue) -> Self {
        RsonValue::Option(Some(Box::new(value)))
    }
    
    /// Create a None variant of Option.
    pub fn none() -> Self {
        RsonValue::Option(None)
    }
}

impl fmt::Display for RsonValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RsonValue::Null => write!(f, "null"),
            RsonValue::Bool(b) => write!(f, "{}", b),
            RsonValue::Int(i) => write!(f, "{}", i),
            RsonValue::Float(fl) => write!(f, "{}", fl),
            RsonValue::String(s) => write!(f, "\"{}\"", s),
            RsonValue::Char(c) => write!(f, "'{}'", c),
            RsonValue::Array(arr) => {
                write!(f, "[")?;
                for (i, item) in arr.iter().enumerate() {
                    if i > 0 { write!(f, ", ")?; }
                    write!(f, "{}", item)?;
                }
                write!(f, "]")
            }
            RsonValue::Map(map) => {
                write!(f, "{{")?;
                for (i, (key, value)) in map.iter().enumerate() {
                    if i > 0 { write!(f, ", ")?; }
                    write!(f, "{}: {}", key, value)?;
                }
                write!(f, "}}")
            }
            RsonValue::Struct { name, fields } => {
                write!(f, "{}(", name)?;
                for (i, (key, value)) in fields.iter().enumerate() {
                    if i > 0 { write!(f, ", ")?; }
                    write!(f, "{}: {}", key, value)?;
                }
                write!(f, ")")
            }
            RsonValue::Tuple(values) => {
                write!(f, "(")?;
                for (i, value) in values.iter().enumerate() {
                    if i > 0 { write!(f, ", ")?; }
                    write!(f, "{}", value)?;
                }
                write!(f, ")")
            }
            RsonValue::Enum { name, variant, value } => {
                write!(f, "{}::{}", name, variant)?;
                if let Some(val) = value {
                    write!(f, "({})", val)?;
                }
                Ok(())
            }
            RsonValue::Option(Some(value)) => write!(f, "Some({})", value),
            RsonValue::Option(None) => write!(f, "None"),
        }
    }
}

impl fmt::Display for RsonType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RsonType::Null => write!(f, "null"),
            RsonType::Bool => write!(f, "bool"),
            RsonType::Int => write!(f, "int"),
            RsonType::Float => write!(f, "float"),
            RsonType::String => write!(f, "string"),
            RsonType::Char => write!(f, "char"),
            RsonType::Array => write!(f, "array"),
            RsonType::Map => write!(f, "map"),
            RsonType::Struct => write!(f, "struct"),
            RsonType::Tuple => write!(f, "tuple"),
            RsonType::Enum => write!(f, "enum"),
            RsonType::Option => write!(f, "option"),
        }
    }
}

// Convenience constructors
impl From<bool> for RsonValue {
    fn from(b: bool) -> Self {
        RsonValue::Bool(b)
    }
}

impl From<i32> for RsonValue {
    fn from(i: i32) -> Self {
        RsonValue::Int(i as i64)
    }
}

impl From<i64> for RsonValue {
    fn from(i: i64) -> Self {
        RsonValue::Int(i)
    }
}

impl From<f64> for RsonValue {
    fn from(f: f64) -> Self {
        RsonValue::Float(f)
    }
}

impl From<String> for RsonValue {
    fn from(s: String) -> Self {
        RsonValue::String(s)
    }
}

impl From<&str> for RsonValue {
    fn from(s: &str) -> Self {
        RsonValue::String(s.to_string())
    }
}

impl From<char> for RsonValue {
    fn from(c: char) -> Self {
        RsonValue::Char(c)
    }
}

impl<T: Into<RsonValue>> From<Vec<T>> for RsonValue {
    fn from(vec: Vec<T>) -> Self {
        RsonValue::Array(vec.into_iter().map(Into::into).collect())
    }
}

impl<T: Into<RsonValue>> From<Option<T>> for RsonValue {
    fn from(opt: Option<T>) -> Self {
        RsonValue::Option(opt.map(|v| Box::new(v.into())))
    }
}