diff --git a/src/runtime2/runtime.rs b/src/runtime2/runtime.rs index 621b50e17daa9b070687640d9e6baab332fe03f5..4255058472a74d8a9f8ce05a1720bc0169d71cf7 100644 --- a/src/runtime2/runtime.rs +++ b/src/runtime2/runtime.rs @@ -59,24 +59,48 @@ pub(crate) struct CompPublic { /// Handle to public part of a component. Would be nice if we could /// automagically manage the `num_handles` counter. But when it reaches zero we -/// need to manually remove the handle from the runtime. So be careful. +/// need to manually remove the handle from the runtime. So we just have debug +/// code to make sure this actually happens. pub(crate) struct CompHandle { target: *const CompPublic, + #[cfg(debug_assertions)] decremented: bool, } impl CompHandle { - pub(crate) fn increment_users(&self) { + fn new(public: &CompPublic) -> CompHandle { + let handle = CompHandle{ + target: public, + #[cfg(debug_assertions)] decremented: false, + }; + handle.increment_users(); + return handle; + } + + fn increment_users(&self) { let old_count = self.num_handles.fetch_add(1, Ordering::AcqRel); debug_assert!(old_count > 0); // because we should never be able to retrieve a handle when the component is (being) destroyed } /// Returns true if the component should be destroyed - pub(crate) fn decrement_users(&self) -> bool { + pub(crate) fn decrement_users(&mut self) -> bool { + debug_assert!(!self.decremented, "illegal to 'decrement_users' twice"); + dbg_code!(self.decremented = true); let old_count = self.num_handles.fetch_sub(1, Ordering::AcqRel); return old_count == 1; } } +impl Clone for CompHandle { + fn clone(&self) -> Self { + debug_assert!(!self.decremented, "illegal to clone after 'decrement_users'"); + self.increment_users(); + return CompHandle{ + target: self.target, + #[cfg(debug_assertions)] decremented: false, + }; + } +} + impl std::ops::Deref for CompHandle { type Target = CompPublic; @@ -85,6 +109,12 @@ impl std::ops::Deref for CompHandle { } } +impl Drop for CompHandle { + fn drop(&mut self) { + debug_assert!(self.decremented, "need call to 'decrement_users' before dropping"); + } +} + // ----------------------------------------------------------------------------- // Runtime // ----------------------------------------------------------------------------- @@ -165,7 +195,7 @@ impl Runtime { pub(crate) fn get_component_public(&self, id: CompId) -> CompHandle { let component = self.components.get(id.0); - return CompHandle{ target: &component.public }; + return CompHandle::new(&component.public); } pub(crate) fn destroy_component(&self, key: CompKey) {