cadmpeg-ir 0.6.6

CAD data model, validation, diffing, and codec API for cadmpeg.
// SPDX-License-Identifier: Apache-2.0
#![allow(clippy::unwrap_used)]

use crate::geometry::pcurve::PcurveGeometry;

fn nurbs_pcurve_leaf() -> PcurveGeometry {
    PcurveGeometry::Nurbs {
        nurbs: crate::geometry::pcurve::PcurveNurbs::from_lanes(
            1,
            vec![0.0, 0.0, 1.0, 1.0],
            vec![
                crate::math::Point2::new(0.0, 0.0),
                crate::math::Point2::new(1.0, 1.0),
            ],
            None,
            false,
        )
        .unwrap(),
    }
}

fn placed_pcurve(placements: usize) -> Result<PcurveGeometry, &'static str> {
    let mut geometry = nurbs_pcurve_leaf();
    for _ in 0..placements {
        geometry = PcurveGeometry::Transformed(crate::geometry::pcurve::PlacedPcurve::try_new(
            Box::new(geometry),
            crate::transform::Transform2::identity(),
        )?);
    }
    Ok(geometry)
}

#[test]
fn pcurve_parameter_domain_preserves_session_depth_refusals() {
    use cadmpeg_core::decode::{DecodeArena, DecodeContext, DecodePolicy, ResourceDimension};
    use cadmpeg_core::CodecError;
    let geometry = placed_pcurve(2).unwrap();
    for (cap, held_frame) in [(0, false), (2, false), (2, true)] {
        let arena = DecodeArena::new();
        let mut policy = DecodePolicy::service();
        policy.limits.max_recursion_depth = cap;
        let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).unwrap();
        let guard = held_frame.then(|| ctx.enter_nested_limit("caller frame").unwrap());
        let limit = geometry.parameter_domain(&ctx).unwrap_err();
        assert_eq!(limit.dimension, ResourceDimension::RecursionDepth);
        assert_eq!(limit.limit, cap);
        assert_eq!(limit.used, cap);
        assert_eq!(limit.additional, 1);
        assert_eq!(limit.operation, "pcurve parameter domain nesting");
        drop(guard);
        assert!(
            matches!(ctx.finish_session(), Err(CodecError::ResourceLimit(original)) if original == limit)
        );
    }
}

#[test]
fn pcurve_parameter_domain_stops_at_the_admitted_nesting_depth() {
    let arena = cadmpeg_core::decode::DecodeArena::new();
    let mut policy = cadmpeg_core::decode::DecodePolicy::service();
    policy.limits.max_recursion_depth =
        cadmpeg_core::decode::u64_from_index(crate::geometry::MAX_GEOMETRY_NESTING + 1);
    let (ctx, _) =
        cadmpeg_core::decode::DecodeContext::from_root_bytes(&[], &arena, &policy).unwrap();
    let accepted = placed_pcurve(crate::geometry::MAX_GEOMETRY_NESTING).expect("admitted nesting");
    assert!(accepted.parameter_domain(&ctx).unwrap().is_some());

    // Constructor admission also rejects a carrier beyond the inline bound.
    assert_eq!(
        placed_pcurve(crate::geometry::MAX_GEOMETRY_NESTING + 1),
        Err("PlacedPcurve.basis nests past the admitted inline basis depth")
    );
}