geam-core 0.2.3

Typed Gleam planning, host, and execution core for Geam
Documentation
use super::list::EmbeddingList;
use crate::runtime::EvaluatedCustomValue;
use crate::runtime::evaluated::{EvaluatedExternalValue, EvaluatedFunctionValue, EvaluatedValue};
use crate::runtime::state::list::{ParameterListValueId, StoredListValueId};
use ecow::EcoString;
use num_bigint::BigInt;

pub(crate) struct EmbeddingOutput {
    ints: Vec<BigInt>,
    floats: Vec<f64>,
    strings: Vec<EcoString>,
    bit_arrays: Vec<crate::BitArrayValue>,
    utf_codepoints: Vec<char>,
    variants: Vec<usize>,
    _externals: Vec<EvaluatedExternalValue>,
    bools: Vec<bool>,
    _parameter_lists: Vec<ParameterListValueId>,
    lists: Vec<StoredListValueId>,
    _functions: Vec<EvaluatedFunctionValue>,
}

impl EmbeddingOutput {
    pub(super) fn from_value(value: EvaluatedValue) -> Self {
        let mut output = Self::empty();
        output.push_reversed(value);
        output
    }

    pub(super) fn from_tuple(values: Vec<EvaluatedValue>) -> Self {
        let mut output = Self::empty();
        for value in values.into_iter().rev() {
            output.push_reversed(value);
        }
        output
    }

    pub(super) fn from_custom(value: EvaluatedCustomValue) -> Self {
        let mut output = Self::empty();
        output.push_reversed(EvaluatedValue::Custom(value));
        output
    }

    pub(crate) fn take_int(&mut self) -> BigInt {
        take_last(&mut self.ints)
    }

    pub(crate) fn take_float(&mut self) -> f64 {
        take_last(&mut self.floats)
    }

    pub(crate) fn take_string(&mut self) -> EcoString {
        take_last(&mut self.strings)
    }

    pub(crate) fn take_bit_array(&mut self) -> crate::BitArrayValue {
        take_last(&mut self.bit_arrays)
    }

    pub(crate) fn take_utf_codepoint(&mut self) -> char {
        take_last(&mut self.utf_codepoints)
    }

    pub(crate) fn take_variant(&mut self) -> usize {
        take_last(&mut self.variants)
    }

    pub(crate) fn take_bool(&mut self) -> bool {
        take_last(&mut self.bools)
    }

    pub(crate) fn take_nil(&mut self) {}

    pub(crate) fn take_list(&mut self) -> EmbeddingList {
        EmbeddingList::new(take_last(&mut self.lists))
    }

    fn empty() -> Self {
        Self {
            ints: Vec::new(),
            floats: Vec::new(),
            strings: Vec::new(),
            bit_arrays: Vec::new(),
            utf_codepoints: Vec::new(),
            variants: Vec::new(),
            _externals: Vec::new(),
            bools: Vec::new(),
            _parameter_lists: Vec::new(),
            lists: Vec::new(),
            _functions: Vec::new(),
        }
    }

    fn push_reversed(&mut self, value: EvaluatedValue) {
        match value {
            EvaluatedValue::Int(value) => self.ints.push(value),
            EvaluatedValue::Float(value) => self.floats.push(value),
            EvaluatedValue::String(value) => self.strings.push(value),
            EvaluatedValue::BitArray(value) => self.bit_arrays.push(value.into_value()),
            EvaluatedValue::UtfCodepoint(value) => self.utf_codepoints.push(value),
            EvaluatedValue::Custom(value) => {
                let (constructor, fields) = value.into_fields();
                for field in fields.into_vec().into_iter().rev() {
                    self.push_reversed(field);
                }
                self.variants.push(constructor.index());
            }
            EvaluatedValue::External(value) => self._externals.push(value),
            EvaluatedValue::Bool(value) => self.bools.push(value),
            EvaluatedValue::Nil => {}
            EvaluatedValue::Tuple(values) => {
                for value in values.into_iter().rev() {
                    self.push_reversed(value);
                }
            }
            EvaluatedValue::ParameterList(value) => self._parameter_lists.push(value),
            EvaluatedValue::List(value) => self.lists.push(value),
            EvaluatedValue::Function(value) => self._functions.push(value),
        }
    }
}

fn take_last<Value>(values: &mut Vec<Value>) -> Value {
    values.swap_remove(values.len() - 1)
}

#[cfg(test)]
mod tests {
    use super::EmbeddingOutput;
    use crate::host::HostExternalStore;
    use crate::plan::execution::function::IntFunctionId;
    use crate::plan::execution::type_::{ExternalTypeId, FunctionType, ValueType};
    use crate::runtime::evaluated::{
        EvaluatedExternalValue, EvaluatedFunctionValue, EvaluatedIntFunction, EvaluatedValue,
    };
    use crate::runtime::state::RuntimeState;
    use crate::runtime::state::list::{ListValueId, ParameterListValueId};

    #[test]
    fn retains_non_data_runtime_families_without_reinterpreting_them() {
        let plan = crate::runtime::plan_src(
            r#"
fn ints() -> List(Int) { [] }
fn parameters(values: List(value)) { values }

pub fn main() {
  let _ = ints
  let _ = parameters
  0
}
"#,
        );
        let mut echo = Vec::new();
        let mut state = RuntimeState::new(&mut echo);
        let list = state
            .lists_mut()
            .int(plan.int_list_function_id(0).type_id(), vec![1.into()]);
        let parameter = ParameterListValueId::new(plan.parameter_list_function_id(0).type_id());
        let store = HostExternalStore::default();
        let external = store.insert(
            crate::host::HostStoredValue::<num_bigint::BigInt>::new(
                crate::runtime::StoredRuntimeValue::test_int(7.into()),
            ),
            |context, left, right| context.stored_values_equal(left, right),
            |context, value| context.stored_value_hash(value),
            |context, value| context.inspect_stored_value(value),
        );
        let external = EvaluatedExternalValue::new(ExternalTypeId::new(0), external);
        let stored_equal =
            |left: &crate::runtime::StoredRuntimeValue,
             right: &crate::runtime::StoredRuntimeValue| left.value() == right.value();
        let stored_hash = |_: &crate::runtime::StoredRuntimeValue| 7;
        let stored_inspect = |_: &crate::runtime::StoredRuntimeValue| "stored".into();
        let equality = crate::host::HostExternalEquality::new(&stored_equal);
        let hashing = crate::host::HostExternalHashing::new(&stored_hash);
        let inspection = crate::host::HostExternalInspection::new(&stored_inspect);
        assert!(external.source_equal(&equality, &external));
        assert_eq!(external.source_hash(&hashing), 7);
        assert_eq!(external.lease().inspection(&inspection), "stored");
        let function = EvaluatedIntFunction::reference(
            IntFunctionId(0),
            Vec::new(),
            Vec::new(),
            FunctionType::new(Vec::new(), ValueType::Int),
        );
        let mut output = EmbeddingOutput::empty();

        output.push_reversed(EvaluatedValue::External(external));
        output.push_reversed(EvaluatedValue::ParameterList(parameter));
        output.push_reversed(EvaluatedValue::from(ListValueId::Int(list)));
        output.push_reversed(EvaluatedValue::Function(EvaluatedFunctionValue::from(
            function,
        )));

        assert_eq!(output._externals.len(), 1);
        assert_eq!(output._parameter_lists.len(), 1);
        assert_eq!(output.lists.len(), 1);
        assert_eq!(output._functions.len(), 1);
    }
}