use std::sync::Arc;
use facet::Facet;
use facet_reflect::Partial;
use facet_testhelpers::{IPanic, test};
#[derive(Debug, PartialEq, Facet)]
struct Inner {
value: i32,
}
#[derive(Debug, PartialEq, Facet)]
struct OuterYesArc {
inner: Arc<Inner>,
}
#[derive(Debug, PartialEq, Facet)]
struct OuterNoArc {
inner: Inner,
}
#[test]
fn outer_no_arc() {
let mut partial: Partial<'_> = Partial::alloc::<OuterNoArc>().unwrap();
partial = partial.begin_field("inner").unwrap();
partial = partial.begin_field("value").unwrap();
partial = partial.set(1234_i32).unwrap();
partial = partial.end().unwrap();
partial = partial.end().unwrap();
let o = partial
.build()
.unwrap()
.materialize::<OuterNoArc>()
.unwrap();
assert_eq!(
o,
OuterNoArc {
inner: Inner { value: 1234 }
}
);
}
#[test]
fn outer_yes_arc_put() {
let mut partial: Partial<'_> = Partial::alloc::<OuterYesArc>().unwrap();
let inner = Arc::new(Inner { value: 5678 });
partial = partial.begin_field("inner").unwrap();
partial = partial.set(inner.clone()).unwrap();
partial = partial.end().unwrap();
let o = partial
.build()
.unwrap()
.materialize::<OuterYesArc>()
.unwrap();
assert_eq!(o, OuterYesArc { inner });
}
#[test]
fn outer_yes_arc_pointee() {
let mut partial: Partial<'_> = Partial::alloc::<OuterYesArc>().unwrap();
partial = partial.begin_field("inner").unwrap();
partial = partial.begin_smart_ptr().unwrap();
partial = partial.begin_field("value").unwrap();
partial = partial.set(4321_i32).unwrap();
partial = partial.end().unwrap();
partial = partial.end().unwrap();
partial = partial.end().unwrap();
let o = partial
.build()
.unwrap()
.materialize::<OuterYesArc>()
.unwrap();
assert_eq!(
o,
OuterYesArc {
inner: Arc::new(Inner { value: 4321 })
}
);
}
#[test]
fn outer_yes_arc_field_named_twice_error() {
let mut partial: Partial<'_> = Partial::alloc::<OuterYesArc>().unwrap();
partial = partial.begin_field("inner").unwrap();
let err = partial.begin_field("value").err().unwrap();
let err_string = format!("{err}");
assert!(
err_string.contains("opaque types cannot be reflected upon"),
"Error message should mention 'opaque types cannot be reflected upon', got: {err_string}"
);
}
#[test]
fn arc_str_begin_smart_ptr_good() {
let mut partial = Partial::alloc::<Arc<str>>().unwrap();
partial = partial.begin_smart_ptr().unwrap();
partial = partial.set(String::from("foobar")).unwrap();
partial = partial.end().unwrap();
let built = partial.build().unwrap().materialize::<Arc<str>>().unwrap();
assert_eq!(&*built, "foobar");
}
#[test]
fn arc_str_begin_smart_ptr_bad_1() {
let partial = Partial::alloc::<Arc<str>>().unwrap();
let _err = partial.build().unwrap_err();
#[cfg(not(miri))]
insta::assert_snapshot!(_err);
}
#[test]
fn arc_str_begin_smart_ptr_bad_2a() {
let mut partial = Partial::alloc::<Arc<str>>().unwrap();
partial = partial.begin_smart_ptr().unwrap();
let _err = partial.build().unwrap_err();
#[cfg(not(miri))]
insta::assert_snapshot!(_err);
}
#[test]
fn arc_str_begin_smart_ptr_bad_2b() {
let mut partial = Partial::alloc::<Arc<str>>().unwrap();
partial = partial.begin_smart_ptr().unwrap();
let _err = match partial.end() {
Ok(_) => panic!("expected error"),
Err(e) => e,
};
#[cfg(not(miri))]
insta::assert_snapshot!(_err);
}
#[test]
fn arc_str_begin_smart_ptr_bad_3() {
let mut partial = Partial::alloc::<Arc<str>>().unwrap();
partial = partial.begin_smart_ptr().unwrap();
partial = partial.set(String::from("foobar")).unwrap();
let _err = partial.build().unwrap_err();
#[cfg(not(miri))]
insta::assert_snapshot!(_err);
}
#[test]
fn rc_str_begin_smart_ptr_once() {
use std::rc::Rc;
let mut partial = Partial::alloc::<Rc<str>>().unwrap();
partial = partial.begin_smart_ptr().unwrap();
partial = partial.set(String::from("foobar")).unwrap();
partial = partial.end().unwrap();
let built = partial
.build()
.unwrap()
.materialize::<std::rc::Rc<str>>()
.unwrap();
assert_eq!(&*built, "foobar");
}
#[test]
fn rc_str_begin_smart_ptr_twice() -> Result<(), IPanic> {
use std::rc::Rc;
let mut partial = Partial::alloc::<Rc<str>>()?;
eprintln!("==== first go");
partial = partial.begin_smart_ptr()?;
partial = partial.set(String::from("foobar"))?;
partial = partial.end()?;
eprintln!("==== second go");
partial = partial.begin_smart_ptr()?;
partial = partial.set(String::from("barbaz"))?;
partial = partial.end()?;
eprintln!("==== build");
let built = partial.build()?.materialize::<std::rc::Rc<str>>()?;
assert_eq!(&*built, "barbaz");
Ok(())
}
#[test]
fn box_str_begin_smart_ptr() {
let mut partial = Partial::alloc::<Box<str>>().unwrap();
partial = partial.begin_smart_ptr().unwrap();
partial = partial.set(String::from("foobar")).unwrap();
partial = partial.end().unwrap();
let built = partial.build().unwrap().materialize::<Box<str>>().unwrap();
assert_eq!(&*built, "foobar");
}
#[test]
fn arc_slice_u8_begin_smart_ptr_good() {
{
let mut partial = Partial::alloc::<Vec<u8>>().unwrap();
partial = partial.init_list().unwrap();
partial = partial.push(2_u8).unwrap();
partial = partial.push(3_u8).unwrap();
partial = partial.push(4_u8).unwrap();
let built = partial.build().unwrap().materialize::<Vec<u8>>().unwrap();
assert_eq!(&*built, &[2, 3, 4]);
}
{
let mut partial = Partial::alloc::<Arc<[u8]>>().unwrap();
partial = partial.begin_smart_ptr().unwrap();
partial = partial.init_list().unwrap();
partial = partial.push(2_u8).unwrap();
partial = partial.push(3_u8).unwrap();
partial = partial.push(4_u8).unwrap();
partial = partial.end().unwrap();
let built = partial.build().unwrap().materialize::<Arc<[u8]>>().unwrap();
assert_eq!(&*built, &[2, 3, 4]);
}
}
#[cfg(not(miri))]
macro_rules! assert_snapshot {
($($tt:tt)*) => {
insta::assert_snapshot!($($tt)*)
};
}
#[cfg(miri)]
macro_rules! assert_snapshot {
($($tt:tt)*) => {{ let _ = $($tt)*; }};
}
#[test]
fn box_init() -> Result<(), IPanic> {
let hv = Partial::alloc::<Box<u32>>()?
.begin_smart_ptr()?
.set(42u32)?
.end()?
.build()?
.materialize::<Box<u32>>()?;
assert_eq!(*hv, 42);
Ok(())
}
#[test]
fn box_partial_init() -> Result<(), IPanic> {
assert_snapshot!(Partial::alloc::<Box<u32>>()?.build().unwrap_err());
Ok(())
}
#[test]
fn box_struct() -> Result<(), IPanic> {
#[derive(Facet, Debug, PartialEq)]
struct Point {
x: f64,
y: f64,
}
let hv = Partial::alloc::<Box<Point>>()?
.begin_smart_ptr()?
.set_field("x", 1.0)?
.set_field("y", 2.0)?
.end()?
.build()?
.materialize::<Box<Point>>()?;
assert_eq!(*hv, Point { x: 1.0, y: 2.0 });
Ok(())
}
#[test]
fn drop_box_partially_initialized() -> Result<(), IPanic> {
use core::sync::atomic::{AtomicUsize, Ordering};
static BOX_DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
static INNER_DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
#[derive(Facet, Debug)]
struct DropCounter {
value: u32,
}
impl Drop for DropCounter {
fn drop(&mut self) {
INNER_DROP_COUNT.fetch_add(1, Ordering::SeqCst);
println!("Dropping DropCounter with value: {}", self.value);
}
}
BOX_DROP_COUNT.store(0, Ordering::SeqCst);
INNER_DROP_COUNT.store(0, Ordering::SeqCst);
{
let mut partial = Partial::alloc::<Box<DropCounter>>()?;
partial = partial.begin_smart_ptr()?;
partial = partial.set(DropCounter { value: 99 })?;
let _partial = partial.end()?;
}
assert_eq!(
INNER_DROP_COUNT.load(Ordering::SeqCst),
1,
"Should drop the inner value through Box's drop"
);
Ok(())
}
#[test]
fn arc_init() -> Result<(), IPanic> {
let hv = Partial::alloc::<Arc<u32>>()?
.begin_smart_ptr()?
.set(42u32)?
.end()?
.build()?
.materialize::<Arc<u32>>()?;
assert_eq!(*hv, 42);
Ok(())
}
#[test]
fn arc_partial_init() -> Result<(), IPanic> {
assert_snapshot!(Partial::alloc::<Arc<u32>>()?.build().unwrap_err());
Ok(())
}
#[test]
fn arc_struct() -> Result<(), IPanic> {
#[derive(Facet, Debug, PartialEq)]
struct Point {
x: f64,
y: f64,
}
let hv = Partial::alloc::<Arc<Point>>()?
.begin_smart_ptr()?
.set_field("x", 3.0)?
.set_field("y", 4.0)?
.end()?
.build()?
.materialize::<Arc<Point>>()?;
assert_eq!(*hv, Point { x: 3.0, y: 4.0 });
Ok(())
}
#[test]
fn drop_arc_partially_initialized() -> Result<(), IPanic> {
use core::sync::atomic::{AtomicUsize, Ordering};
static INNER_DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
#[derive(Facet, Debug)]
struct DropCounter {
value: u32,
}
impl Drop for DropCounter {
fn drop(&mut self) {
INNER_DROP_COUNT.fetch_add(1, Ordering::SeqCst);
println!("Dropping DropCounter with value: {}", self.value);
}
}
INNER_DROP_COUNT.store(0, Ordering::SeqCst);
{
let mut partial = Partial::alloc::<Arc<DropCounter>>()?;
partial = partial.begin_smart_ptr()?;
partial = partial.set(DropCounter { value: 123 })?;
let _partial = partial.end()?;
}
assert_eq!(
INNER_DROP_COUNT.load(Ordering::SeqCst),
1,
"Should drop the inner value through Arc's drop"
);
Ok(())
}