use pattern_wishcast::pattern_wishcast;
pattern_wishcast! {
enum Value is <P: PatternFields> = {
Unit,
MaybeValue { inner: Option<Box<Self>> },
ListOfValues { items: Vec<Box<Self>> },
BoxedValue { boxed: Box<Self> },
Stuck { reason: String },
};
type FlexValue = Value is _;
type StrictValue = Value is Unit | MaybeValue { .. } | ListOfValues { .. } | BoxedValue { .. };
#[derive(SubtypingRelation(upcast=to_flex, downcast=try_to_strict))]
impl StrictValue : FlexValue;
}
#[test]
fn test_box_self_field() {
let boxed = StrictValue::BoxedValue {
boxed: Box::new(StrictValue::Unit),
};
let flex = boxed.to_flex();
assert!(flex.try_to_strict().is_ok(), "Boxed strict value should convert");
let stuck = FlexValue::Stuck {
reason: "blocked".to_string(),
_never: (),
};
let boxed_stuck = FlexValue::BoxedValue { boxed: Box::new(stuck) };
assert!(
boxed_stuck.try_to_strict().is_err(),
"Box<Self> containing Stuck should fail conversion"
);
}
#[test]
fn test_deeply_nested_structures() {
let deep = StrictValue::BoxedValue {
boxed: Box::new(StrictValue::MaybeValue {
inner: Some(Box::new(StrictValue::ListOfValues {
items: vec![Box::new(StrictValue::Unit)],
})),
}),
};
let flex = deep.to_flex();
assert!(flex.try_to_strict().is_ok(), "Deeply nested strict values should convert");
let stuck = FlexValue::Stuck {
reason: "deep".to_string(),
_never: (),
};
let deep_stuck = FlexValue::BoxedValue {
boxed: Box::new(FlexValue::MaybeValue {
inner: Some(Box::new(FlexValue::ListOfValues {
items: vec![Box::new(stuck)],
})),
}),
};
assert!(deep_stuck.try_to_strict().is_err(), "Deeply nested Stuck should fail conversion");
}
#[test]
fn test_option_box_self_field() {
let with_some = StrictValue::MaybeValue {
inner: Some(Box::new(StrictValue::Unit)),
};
let flex = with_some.to_flex();
assert!(flex.try_to_strict().is_ok(), "Should convert back to strict");
let with_none = StrictValue::MaybeValue { inner: None };
let flex_none = with_none.to_flex();
assert!(flex_none.try_to_strict().is_ok(), "None should convert to strict");
let stuck_inner = FlexValue::Stuck {
reason: "blocked".to_string(),
_never: (),
};
let with_stuck = FlexValue::MaybeValue {
inner: Some(Box::new(stuck_inner)),
};
assert!(
with_stuck.try_to_strict().is_err(),
"Option<Box<Self>> containing Stuck should fail conversion"
);
}
#[test]
fn test_vec_box_self_field() {
let empty_list = StrictValue::ListOfValues { items: vec![] };
let flex = empty_list.to_flex();
assert!(flex.try_to_strict().is_ok(), "Empty vec should convert to strict");
let list = StrictValue::ListOfValues {
items: vec![Box::new(StrictValue::Unit), Box::new(StrictValue::Unit)],
};
let flex = list.to_flex();
assert!(flex.try_to_strict().is_ok(), "Vec of strict values should convert");
let stuck = FlexValue::Stuck {
reason: "blocked".to_string(),
_never: (),
};
let list_with_stuck = FlexValue::ListOfValues {
items: vec![Box::new(FlexValue::Unit), Box::new(stuck)],
};
assert!(
list_with_stuck.try_to_strict().is_err(),
"Vec<Box<Self>> containing Stuck should fail conversion"
);
}