use std::sync::Arc; use objects::{ CodeLayout, EndorCode, EndorCodeObject, EndorFunctionObject, Instruction, ObjectStore, Opcode, Value, VmError, }; #[test] fn standalone_storage_preserves_identity_validates_edges_and_collects_cycles() { let mut store = ObjectStore::new().unwrap(); let mut other = ObjectStore::new().unwrap(); let dictionary = store.new_dict().unwrap(); let cell = store.new_cell(Some(Value::Object(dictionary))).unwrap(); let foreign = other.new_object().unwrap(); let address = store.object(dictionary).unwrap() as *const _; let key = Value::Text("cell".into()); store .dict_set(dictionary, key.clone(), Value::Object(cell)) .unwrap(); assert_eq!(store.object(dictionary).unwrap() as *const _, address); assert_eq!( store.dict_set(dictionary, key.clone(), Value::Object(foreign)), Err(VmError::ForeignHandle) ); assert_eq!( store.dict_get(dictionary, &key).unwrap(), Some(Value::Object(cell)) ); assert_eq!(store.ref_count(cell).unwrap(), 2); store.release(dictionary).unwrap(); store.release(cell).unwrap(); assert_eq!(store.collect_cycles(), 2); assert_eq!(store.object_count(), 0); assert!(matches!(store.object(cell), Err(VmError::InvalidHandle))); other.release(foreign).unwrap(); } #[test] fn standalone_function_factories_validate_and_own_shared_executable_data() { let mut store = ObjectStore::new().unwrap(); let constant = store.new_string("kept by code").unwrap(); let globals = store.new_dict().unwrap(); let code = EndorCode::from_instructions( &[ Instruction::new(Opcode::LoadConst, 0), Instruction::simple(Opcode::ReturnValue), ], vec![Value::Object(constant)], CodeLayout::default(), ) .unwrap(); let code = store.new_code(code).unwrap(); let before = store.object_count(); assert_eq!( store.new_function("bad", code, globals, vec![Value::Nil], vec![]), Err(VmError::InvalidArgument( "function defaults or closure do not match code" )) ); assert_eq!(store.object_count(), before); assert_eq!(store.ref_count(code).unwrap(), 1); let first = store .new_function("first", code, globals, vec![], vec![]) .unwrap(); let second = store .new_function("second", code, globals, vec![], vec![]) .unwrap(); let first_code = store .payload::(first, "function") .unwrap() .code(); let second_code = store .payload::(second, "function") .unwrap() .code(); let first_executable = store .payload::(first_code, "code") .unwrap() .shared_code(); let second_executable = store .payload::(second_code, "code") .unwrap() .shared_code(); assert!(Arc::ptr_eq(&first_executable, &second_executable)); drop(first_executable); drop(second_executable); store.release(constant).unwrap(); store.release(code).unwrap(); store.release(globals).unwrap(); assert_eq!(store.str(constant).unwrap(), "kept by code"); store.release(first).unwrap(); assert_eq!(store.ref_count(code).unwrap(), 1); store.release(second).unwrap(); assert_eq!(store.object_count(), 0); }