geam-stdlib 0.2.0

Official Gleam standard-library providers for Geam
Documentation
use crate::dict::DictDeclaration;
use geam_core::provider::advanced::{DynamicKind, StoredDynamic};

pub(super) enum DynamicValue {
    Stored {
        representation: DynamicRepresentation,
        value: StoredDynamic<super::function::provider::DynamicPayload>,
    },
    Array {
        value: StoredDynamic<super::function::provider::DynamicPayload>,
        elements: Box<[StoredDynamic<super::function::provider::DynamicPayload>]>,
    },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DynamicRepresentation {
    Bool,
    String,
    Float,
    Int,
    BitArray,
    UtfCodepoint,
    List,
    Array,
    Dict,
    Nil,
    Function,
    Custom,
    External,
}

impl DynamicRepresentation {
    pub(super) fn from_value(
        value: &StoredDynamic<super::function::provider::DynamicPayload>,
    ) -> Self {
        if value.is_external::<DictDeclaration<(), ()>>() {
            return Self::Dict;
        }

        match value.kind() {
            DynamicKind::Int => Self::Int,
            DynamicKind::Float => Self::Float,
            DynamicKind::String => Self::String,
            DynamicKind::BitArray => Self::BitArray,
            DynamicKind::UtfCodepoint => Self::UtfCodepoint,
            DynamicKind::Bool => Self::Bool,
            DynamicKind::Nil => Self::Nil,
            DynamicKind::List => Self::List,
            DynamicKind::Tuple => Self::Array,
            DynamicKind::Custom => Self::Custom,
            DynamicKind::External => Self::External,
            DynamicKind::Function => Self::Function,
        }
    }

    pub(crate) fn name(self) -> &'static str {
        match self {
            Self::Bool => "Bool",
            Self::String => "String",
            Self::Float => "Float",
            Self::Int => "Int",
            Self::BitArray => "BitArray",
            Self::UtfCodepoint => "UtfCodepoint",
            Self::List => "List",
            Self::Array => "Array",
            Self::Dict => "Dict",
            Self::Nil => "Nil",
            Self::Function => "Function",
            Self::Custom => "Custom",
            Self::External => "External",
        }
    }
}

impl DynamicValue {
    pub(super) fn stored(value: StoredDynamic<super::function::provider::DynamicPayload>) -> Self {
        Self::Stored {
            representation: DynamicRepresentation::from_value(&value),
            value,
        }
    }

    pub(super) fn representation(&self) -> DynamicRepresentation {
        match self {
            Self::Stored { representation, .. } => *representation,
            Self::Array { .. } => DynamicRepresentation::Array,
        }
    }

    pub(super) fn value(&self) -> &StoredDynamic<super::function::provider::DynamicPayload> {
        match self {
            Self::Stored { value, .. } | Self::Array { value, .. } => value,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::DynamicRepresentation;

    #[test]
    fn representation_names_cover_every_source_classification() {
        let cases = [
            (DynamicRepresentation::Bool, "Bool"),
            (DynamicRepresentation::String, "String"),
            (DynamicRepresentation::Float, "Float"),
            (DynamicRepresentation::Int, "Int"),
            (DynamicRepresentation::BitArray, "BitArray"),
            (DynamicRepresentation::UtfCodepoint, "UtfCodepoint"),
            (DynamicRepresentation::List, "List"),
            (DynamicRepresentation::Array, "Array"),
            (DynamicRepresentation::Dict, "Dict"),
            (DynamicRepresentation::Nil, "Nil"),
            (DynamicRepresentation::Function, "Function"),
            (DynamicRepresentation::Custom, "Custom"),
            (DynamicRepresentation::External, "External"),
        ];

        for (representation, expected) in cases {
            assert_eq!(representation.name(), expected);
        }
    }
}