use facet::Facet;
use facet_reflect::Partial;
use facet_testhelpers::{IPanic, test};
#[test]
fn build_with_invariants() -> Result<(), IPanic> {
#[derive(Facet, PartialEq, Debug)]
#[facet(invariants = MyNonZeroU8::invariants)]
struct MyNonZeroU8(u8);
impl MyNonZeroU8 {
fn invariants(&self) -> bool {
self.0 != 0
}
}
let mut partial: Partial<'_> = Partial::alloc::<MyNonZeroU8>()?;
partial = partial.begin_nth_field(0)?;
partial = partial.set(42u8)?;
partial = partial.end()?;
let wip: MyNonZeroU8 = partial.build()?.materialize::<MyNonZeroU8>()?;
assert_eq!(wip, MyNonZeroU8(42));
let mut partial: Partial<'_> = Partial::alloc::<MyNonZeroU8>()?;
partial = partial.begin_nth_field(0)?;
partial = partial.set(0_u8)?;
partial = partial.end()?;
let result = partial.build();
assert!(result.is_err());
Ok(())
}
#[test]
fn build_struct_with_enum_field() -> Result<(), IPanic> {
#[derive(Facet, PartialEq, Debug)]
#[repr(C)]
enum Range {
Low(u8),
High(u8),
}
#[derive(Facet, PartialEq, Debug)]
#[facet(invariants = ValidatedRange::invariants)]
struct ValidatedRange {
range: Range,
}
impl ValidatedRange {
fn invariants(&self) -> bool {
match &self.range {
Range::Low(v) => *v <= 50,
Range::High(v) => *v > 50,
}
}
}
let mut partial: Partial<'_> = Partial::alloc::<ValidatedRange>()?;
partial = partial.begin_field("range")?;
partial = partial.select_variant_named("Low")?;
partial = partial.begin_nth_field(0)?;
partial = partial.set(25u8)?;
partial = partial.end()?;
partial = partial.end()?;
let value: ValidatedRange = partial.build()?.materialize::<ValidatedRange>()?;
assert_eq!(value.range, Range::Low(25));
let mut partial: Partial<'_> = Partial::alloc::<ValidatedRange>()?;
partial = partial.begin_field("range")?;
partial = partial.select_variant_named("Low")?;
partial = partial.begin_nth_field(0)?;
partial = partial.set(75u8)?;
partial = partial.end()?;
partial = partial.end()?;
let result = partial.build();
assert!(result.is_err());
let mut partial: Partial<'_> = Partial::alloc::<ValidatedRange>()?;
partial = partial.begin_field("range")?;
partial = partial.select_variant_named("High")?;
partial = partial.begin_nth_field(0)?;
partial = partial.set(75u8)?;
partial = partial.end()?;
partial = partial.end()?;
let value: ValidatedRange = partial.build()?.materialize::<ValidatedRange>()?;
assert_eq!(value.range, Range::High(75));
let mut partial: Partial<'_> = Partial::alloc::<ValidatedRange>()?;
partial = partial.begin_field("range")?;
partial = partial.select_variant_named("High")?;
partial = partial.begin_nth_field(0)?;
partial = partial.set(25u8)?;
partial = partial.end()?;
partial = partial.end()?;
let result = partial.build();
assert!(result.is_err());
Ok(())
}
#[test]
fn build_nested_with_invariants() -> Result<(), IPanic> {
#[derive(Facet, PartialEq, Debug)]
#[facet(invariants = Point::invariants)]
struct Point {
x: i32,
y: i32,
}
impl Point {
fn invariants(&self) -> bool {
self.x >= 0 && self.y >= 0
}
}
#[derive(Facet, PartialEq, Debug)]
struct Container {
point: Point,
}
let mut partial: Partial<'_> = Partial::alloc::<Container>()?;
partial = partial.begin_field("point")?;
partial = partial.set_field("x", 10i32)?;
partial = partial.set_field("y", 20i32)?;
partial = partial.end()?;
let container: Container = partial.build()?.materialize::<Container>()?;
assert_eq!(container.point, Point { x: 10, y: 20 });
let mut partial: Partial<'_> = Partial::alloc::<Container>()?;
partial = partial.begin_field("point")?;
partial = partial.set_field("x", -10i32)?;
partial = partial.set_field("y", 20i32)?;
partial = partial.end()?;
let result = partial.build();
assert!(result.is_err());
Ok(())
}