knave-expand 0.14.22

The reading, scoping and expansion stages of knave
Documentation
use crate::reader::{Form, FormKind};

pub struct HeldBytes;

impl HeldBytes {
    pub const PER_FORM: usize = 64;

    pub fn of_form(form: &Form) -> usize {
        let mut held = 0;
        let mut waiting = vec![form];
        while let Some(form) = waiting.pop() {
            held += Self::PER_FORM + Self::text_bytes(form.kind());
            waiting.extend(form.as_list().unwrap_or_default());
        }
        held
    }

    fn text_bytes(kind: &FormKind) -> usize {
        match kind {
            FormKind::String(text) => text.len(),
            FormKind::Symbol(symbol) => symbol.name().len(),
            FormKind::Number(number) => number.text().len(),
            FormKind::List(_) => 0,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::HeldBytes;
    use crate::reader::{Form, FormKind, Symbol};
    use crate::source::{SourceId, Span};

    struct HeldForms;

    impl HeldForms {
        fn span() -> Span {
            Span::new(SourceId::new(0), 0..1)
        }

        fn text(bytes: usize) -> Form {
            Form::new(FormKind::String("x".repeat(bytes).into()), Self::span())
        }
    }

    #[test]
    fn text_holds_its_bytes_beside_its_form() {
        assert_eq!(HeldBytes::of_form(&HeldForms::text(100)), 64 + 100);
    }

    #[test]
    fn a_list_holds_itself_and_each_form_of_its_tree() {
        let symbol = Form::new(FormKind::Symbol(Symbol::new("ab")), HeldForms::span());
        let list = Form::new(
            FormKind::List(vec![symbol, HeldForms::text(3)]),
            HeldForms::span(),
        );
        assert_eq!(HeldBytes::of_form(&list), 64 + (64 + 2) + (64 + 3));
    }
}