sim-shape 0.1.3

Shape algebra, comparison, and match-hook helpers.
Documentation
use std::sync::Arc;

use sim_kernel::{Cx, Expr, Result, Symbol, shape_is_subshape_of, testing::bare_cx as cx};

use crate::{AnyShape, EffectfulShape, Shape};

use super::{
    CaptureShape, FieldShape, FieldSpec, ListShape, OneOfShape, PrattShape, ShapeExprParser,
};

fn effectful_child() -> Arc<dyn Shape> {
    Arc::new(EffectfulShape::new(Arc::new(AnyShape)))
}

struct PureParser;

impl ShapeExprParser for PureParser {
    fn label(&self) -> &str {
        "pure"
    }

    fn parse_expr(&self, _source: &str) -> Result<Expr> {
        Ok(Expr::Bool(true))
    }
}

struct EffectfulParser;

impl ShapeExprParser for EffectfulParser {
    fn label(&self) -> &str {
        "effectful"
    }

    fn is_effectful(&self) -> bool {
        true
    }

    fn parse_expr(&self, _source: &str) -> Result<Expr> {
        Ok(Expr::Bool(true))
    }
}

fn assert_effectful_not_subshape_of_any(cx: &mut Cx, shape: &dyn Shape) {
    assert!(shape.is_effectful());
    assert!(!shape_is_subshape_of(cx, shape, &AnyShape).unwrap());
}

#[test]
fn list_shape_propagates_effectful_items_and_rest() {
    let mut cx = cx();
    let effectful_item_list = ListShape::new(vec![effectful_child()]);
    let effectful_rest_list = ListShape::with_rest(Vec::new(), effectful_child());

    assert_effectful_not_subshape_of_any(&mut cx, &effectful_item_list);
    assert_effectful_not_subshape_of_any(&mut cx, &effectful_rest_list);
}

#[test]
fn capture_shape_propagates_effectful_inner() {
    let mut cx = cx();
    let shape = CaptureShape::new(Symbol::new("captured"), effectful_child());

    assert_effectful_not_subshape_of_any(&mut cx, &shape);
}

#[test]
fn one_of_shape_propagates_effectful_choice() {
    let mut cx = cx();
    let shape = OneOfShape::new(vec![Arc::new(AnyShape), effectful_child()]);

    assert_effectful_not_subshape_of_any(&mut cx, &shape);
}

#[test]
fn pratt_shape_propagates_effectful_inner() {
    let mut cx = cx();
    let shape = PrattShape::new(Arc::new(PureParser), effectful_child());

    assert_effectful_not_subshape_of_any(&mut cx, &shape);
}

#[test]
fn pratt_shape_is_effectful_when_parser_is_effectful() {
    let mut cx = cx();
    let shape = PrattShape::new(Arc::new(EffectfulParser), Arc::new(AnyShape));

    assert_effectful_not_subshape_of_any(&mut cx, &shape);
}

#[test]
fn field_shape_propagates_effectful_fields() {
    let mut cx = cx();
    let shape = FieldShape::anonymous(vec![FieldSpec::required(
        Symbol::new("x"),
        effectful_child(),
    )]);

    assert_effectful_not_subshape_of_any(&mut cx, &shape);
}