knave 0.14.22

A Lisp programming language for humans and agents that infers types and ownership and compiles to readable Rust
Documentation
use super::boxed_payload::BoxedPayload;
use super::payload_position::PayloadPosition;
use super::ty::Type;
use super::type_declarations::TypeDeclarations;
use crate::core::BindingId;

#[derive(Clone, Copy)]
pub(super) struct VariantPayloads<'a> {
    types: &'a TypeDeclarations,
}

impl<'a> VariantPayloads<'a> {
    pub(super) fn new(types: &'a TypeDeclarations) -> Self {
        Self { types }
    }

    pub(super) fn variant_count(&self, owner: BindingId) -> Option<usize> {
        self.types
            .enums
            .get(owner)
            .map(|definition| definition.variants.len())
    }

    pub(super) fn visible(&self, owner: BindingId, index: usize, arguments: &[Type]) -> Vec<Type> {
        self.types
            .enums
            .get(owner)
            .and_then(|definition| definition.instantiated_payload(index, arguments))
            .unwrap_or_default()
            .into_iter()
            .enumerate()
            .map(|(payload, stored)| {
                let position = PayloadPosition {
                    variant: index,
                    payload,
                };
                self.seen_by_pattern(BoxedPayload::at(owner, position), stored)
            })
            .collect()
    }

    pub(super) fn seen_by_pattern(&self, payload: BoxedPayload, stored: Type) -> Type {
        match self.is_inferred_box(payload) {
            true => self.unboxed(&stored).clone(),
            false => stored,
        }
    }

    pub(super) fn written<'p>(&self, payload: BoxedPayload, stored: &'p Type) -> &'p Type {
        match self.is_inferred_box(payload) {
            true => self.unboxed(stored),
            false => stored,
        }
    }

    pub(super) fn is_inferred_box(&self, payload: BoxedPayload) -> bool {
        self.types.inferred_boxes.contains(&payload)
    }

    fn unboxed<'p>(&self, inferred_box: &'p Type) -> &'p Type {
        match inferred_box {
            Type::Named(binding, arguments) if Some(*binding) == self.types.box_binding => {
                match arguments.as_slice() {
                    [argument] => argument,
                    _ => panic!("an inferred box has one type argument"),
                }
            }
            _ => panic!("an inferred box is a box"),
        }
    }
}