beuvy 0.1.0

Facade crate for beuvy-runtime plus optional declarative UI authoring.
Documentation
use crate::ast::{DeclarativeLiteral, DeclarativeNumber};
use std::collections::HashMap;
use std::sync::Arc;

#[derive(Debug, Clone, PartialEq)]
pub enum UiValue {
    Null,
    Text(String),
    Bool(bool),
    Number(DeclarativeNumber),
    Object(Arc<HashMap<String, UiValue>>),
    List(Arc<Vec<UiValue>>),
}

impl Default for UiValue {
    fn default() -> Self {
        Self::Null
    }
}

impl UiValue {
    pub fn object(fields: impl IntoIterator<Item = (impl Into<String>, UiValue)>) -> Self {
        Self::Object(Arc::new(
            fields
                .into_iter()
                .map(|(name, value)| (name.into(), value))
                .collect(),
        ))
    }

    pub fn list(items: impl IntoIterator<Item = UiValue>) -> Self {
        Self::List(Arc::new(items.into_iter().collect()))
    }

    pub fn text(&self) -> Option<&str> {
        match self {
            Self::Text(value) => Some(value.as_str()),
            _ => None,
        }
    }

    pub fn bool(&self) -> Option<bool> {
        match self {
            Self::Bool(value) => Some(*value),
            _ => None,
        }
    }

    pub fn number(&self) -> Option<f64> {
        match self {
            Self::Number(value) => Some(match value {
                DeclarativeNumber::I32(value) => *value as f64,
                DeclarativeNumber::I64(value) => *value as f64,
                DeclarativeNumber::F32(value) => *value as f64,
                DeclarativeNumber::F64(value) => *value,
            }),
            _ => None,
        }
    }

    pub fn list_items(&self) -> Option<&[UiValue]> {
        match self {
            Self::List(items) => Some(items.as_slice()),
            _ => None,
        }
    }

    pub fn field(&self, name: &str) -> Option<&UiValue> {
        match self {
            Self::Object(fields) => fields.get(name),
            _ => None,
        }
    }

    pub fn from_literal(value: &DeclarativeLiteral) -> Self {
        match value {
            DeclarativeLiteral::String(value) => Self::Text(value.clone()),
            DeclarativeLiteral::Bool(value) => Self::Bool(*value),
            DeclarativeLiteral::Number(value) => Self::Number(*value),
        }
    }
}

impl From<String> for UiValue {
    fn from(value: String) -> Self {
        Self::Text(value)
    }
}

impl From<&str> for UiValue {
    fn from(value: &str) -> Self {
        Self::Text(value.to_string())
    }
}

impl From<bool> for UiValue {
    fn from(value: bool) -> Self {
        Self::Bool(value)
    }
}

impl From<f32> for UiValue {
    fn from(value: f32) -> Self {
        Self::Number(DeclarativeNumber::F32(value))
    }
}

impl From<f64> for UiValue {
    fn from(value: f64) -> Self {
        Self::Number(DeclarativeNumber::F64(value))
    }
}

impl From<i32> for UiValue {
    fn from(value: i32) -> Self {
        Self::Number(DeclarativeNumber::I32(value))
    }
}

impl From<i64> for UiValue {
    fn from(value: i64) -> Self {
        Self::Number(DeclarativeNumber::I64(value))
    }
}

impl From<usize> for UiValue {
    fn from(value: usize) -> Self {
        Self::Number(DeclarativeNumber::I64(value as i64))
    }
}