use std::{cell::RefCell, rc::Rc}; use rsconnect::{clone, Connect, ConnectInterface, ConnectNodeInterface}; mod common; #[test] #[should_panic] fn cyclic_dependency_error_direct() { let mut conn = Connect::new(); let a = conn.observed(1); let b = conn.observed(2); let comp_fun = Box::new(clone!( move |conn: &mut Connect| *conn.get(&a) + *conn.get(&b) )) as Box i32>; let comp_fun = Rc::new(RefCell::new(comp_fun)); let comp_fun_clone = comp_fun.clone(); let c = conn.computed(move |conn| comp_fun_clone.borrow()(conn)); *comp_fun.borrow_mut() = Box::new(clone!(move |conn: &mut Connect| *conn.get(&c))); // Minor issue: this doesn't panic with the correct error message conn.set(&b, 3); } #[test] #[should_panic(expected = "Cyclic dependency")] fn cyclic_dependency_error() { let mut conn = Connect::new(); let a = conn.observed(1); let comp_fun = Box::new(clone!(move |conn: &mut Connect| *conn.get(&a) + 1)) as Box i32>; let comp_fun = Rc::new(RefCell::new(comp_fun)); let comp_fun_clone = comp_fun.clone(); let b = conn.computed(move |conn| comp_fun_clone.borrow()(conn)); let c = conn.computed(clone!(move |conn| *conn.get(&b) + 1)); let d = conn.computed(clone!(move |conn| *conn.get(&c) + 1)); let e = conn.computed(clone!(move |conn| *conn.get(&d) + 1)); assert_eq!(*conn.get(&e), 5); // This changes computed function to refer to A and D (previously only A): // // A <- B <- C <- D <- E // | ^ // |_________| *comp_fun.borrow_mut() = Box::new(clone!( move |conn: &mut Connect| *conn.get(&a) + *conn.get(&d) )); // This causes dependency to recalculate to being cyclic conn.set(&a, 2); // This causes a cyclic update conn.set(&a, 3); println!("{}", conn.get(&e)); }