kast 0.1.0

kast programming language
Documentation
use super::*;

#[derive(TryHash, PartialEq, Eq, Clone)]
struct Key {
    #[try_hash]
    value: Value,
    #[try_hash]
    target: Value,
}

impl Key {
    fn new(value: Value, target: Value) -> eyre::Result<Self> {
        let err = eyre!("cast key: value = {}, target = {}", value, target);
        let key = Self { value, target };
        key.try_hash(&mut std::hash::DefaultHasher::new())
            .map_err(|e| eyre!(e))
            .wrap_err(err)?;
        Ok(key)
    }
}

impl std::hash::Hash for Key {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.try_hash(state).unwrap()
    }
}

#[derive(Default)]
pub struct CastMap {
    map: HashMap<Key, Value>,
}

impl CastMap {
    #[allow(dead_code)]
    pub fn new() -> Self {
        Self::default()
    }
    pub fn impl_cast(&mut self, value: Value, target: Value, r#impl: Value) -> eyre::Result<()> {
        tracing::trace!("impl {value} as {target} = {impl} :: {}", r#impl.ty());
        self.map.insert(Key::new(value, target)?, r#impl);
        Ok(())
    }
    #[allow(clippy::only_used_in_recursion)]
    pub fn cast_to_ty(&self, value: Value) -> eyre::Result<Result<Type, Value>> {
        Ok(Ok(match value.expect_inferred()? {
            ValueShape::Unit => TypeShape::Unit.into(),
            ValueShape::Ref(place) => TypeShape::Ref(
                self.cast_to_ty(place.claim_value()?)?
                    .map_err(|value| eyre!("{value} is not a type"))?,
            )
            .into(),
            ValueShape::Tuple(tuple) => {
                let mut tuple_ty = Tuple::<Type>::empty();
                for (name, value) in tuple.into_values() {
                    tuple_ty.add(
                        name,
                        self.cast_to_ty(value)?
                            .map_err(|value| eyre!("{value} is not a type"))?,
                    );
                }
                TypeShape::Tuple(tuple_ty).into()
            }
            ValueShape::Binding(binding) => {
                binding.ty.infer_as(TypeShape::Type)?;
                TypeShape::Binding(binding).into()
            }
            inferred => match inferred.expect_type() {
                Ok(value) => value,
                Err(_e) => return Ok(Err(value)),
            },
        }))
    }
    pub fn cast(&self, value: Value, target: &Value) -> eyre::Result<Result<Value, Value>> {
        #[allow(clippy::single_match)]
        match target.expect_inferred()? {
            ValueShape::Type(ty) => match ty.inferred() {
                Ok(TypeShape::Type) => {
                    return self
                        .cast_to_ty(value)
                        .map(|result| result.map(ValueShape::Type).map(Into::into));
                }
                _ => {}
            },
            _ => {}
        }
        let key = Key::new(value.clone(), target.clone())?;
        Ok(self.map.get(&key).cloned().ok_or(value))
    }
}