geam 0.1.1

Experimental Rust-embedded execution runtime for typed Gleam programs
use super::GleamJsonHostProfile;
use super::schema::JsonSchema;
use crate::gleam_stdlib::StoredStringTree;
use crate::{
    HostExternalEquality, HostExternalHashing, HostExternalInspection, HostExternalStorage,
    HostExternalStore,
};
use ecow::EcoString;

#[derive(Default)]
pub(super) struct Stores {
    pub(super) values: HostExternalStore<JsonPayload>,
}

pub(super) struct JsonPayload {
    pub(super) tree: StoredStringTree,
}

pub(super) struct JsonStorage;

impl<Profile> HostExternalStorage<Profile, JsonSchema> for JsonStorage
where
    Profile: GleamJsonHostProfile,
{
    type Payload = JsonPayload;

    fn store(stores: &Profile::ExternalStores) -> &HostExternalStore<Self::Payload> {
        &Profile::gleam_json_stores(stores).json.values
    }

    fn source_equal(
        _context: &HostExternalEquality<'_>,
        left: &Self::Payload,
        right: &Self::Payload,
    ) -> bool {
        left.tree.structurally_equal(&right.tree)
    }

    fn source_hash(_context: &HostExternalHashing<'_>, value: &Self::Payload) -> u64 {
        value.tree.structural_hash()
    }

    fn inspect(_context: &HostExternalInspection<'_>, value: &Self::Payload) -> EcoString {
        format!("{:?}", value.tree.flatten()).into()
    }
}

#[cfg(test)]
mod tests {
    use super::{JsonPayload, JsonSchema, JsonStorage};
    use crate::gleam_json::{GleamJsonHostProfile, GleamJsonProfile, GleamJsonProfileStores};
    use crate::gleam_stdlib::StoredStringTree;
    use crate::{
        HostExternalEquality, HostExternalHashing, HostExternalInspection, HostExternalStorage,
    };

    #[test]
    fn delegates_structural_source_semantics_and_canonical_inspection() {
        let segmented = JsonPayload {
            tree: StoredStringTree::sequence([
                StoredStringTree::text("[".into()),
                StoredStringTree::text("1".into()),
                StoredStringTree::text("]".into()),
            ]),
        };
        let same = JsonPayload {
            tree: StoredStringTree::sequence([
                StoredStringTree::text("[".into()),
                StoredStringTree::text("1".into()),
                StoredStringTree::text("]".into()),
            ]),
        };
        let flat = JsonPayload {
            tree: StoredStringTree::text("[1]".into()),
        };
        let equal =
            |_: &crate::runtime::StoredRuntimeValue, _: &crate::runtime::StoredRuntimeValue| true;
        let hash = |_: &crate::runtime::StoredRuntimeValue| 0;
        let inspect = |_: &crate::runtime::StoredRuntimeValue| "unused".into();
        let stored = crate::runtime::StoredRuntimeValue::test_int(0.into());
        assert_eq!(inspect(&stored), "unused");
        let equality = HostExternalEquality::new(&equal);
        let hashing = HostExternalHashing::new(&hash);
        let inspection = HostExternalInspection::new(&inspect);

        assert!(<JsonStorage as HostExternalStorage<
            GleamJsonProfile,
            JsonSchema,
        >>::source_equal(&equality, &segmented, &same,));
        assert!(!<JsonStorage as HostExternalStorage<
            GleamJsonProfile,
            JsonSchema,
        >>::source_equal(&equality, &segmented, &flat,));
        assert_eq!(
            <JsonStorage as HostExternalStorage<GleamJsonProfile, JsonSchema>>::source_hash(
                &hashing, &segmented,
            ),
            <JsonStorage as HostExternalStorage<GleamJsonProfile, JsonSchema>>::source_hash(
                &hashing, &same,
            ),
        );
        assert_ne!(
            <JsonStorage as HostExternalStorage<GleamJsonProfile, JsonSchema>>::source_hash(
                &hashing, &segmented,
            ),
            <JsonStorage as HostExternalStorage<GleamJsonProfile, JsonSchema>>::source_hash(
                &hashing, &flat,
            ),
        );
        assert_eq!(
            <JsonStorage as HostExternalStorage<GleamJsonProfile, JsonSchema>>::inspect(
                &inspection,
                &segmented,
            ),
            r#""[1]""#,
        );

        let stores = GleamJsonProfileStores::default();
        assert!(std::ptr::eq(
            <JsonStorage as HostExternalStorage<GleamJsonProfile, JsonSchema>>::store(&stores),
            &GleamJsonProfile::gleam_json_stores(&stores).json.values,
        ));
    }
}