use crate::object_model::{ObjectError, ObjectHandle};
#[derive(Debug, Clone)]
pub struct RegistryEntry<T> {
pub handle: ObjectHandle,
pub object: T,
}
impl<T> RegistryEntry<T> {
pub fn new(handle: ObjectHandle, object: T) -> Self {
Self { handle, object }
}
#[inline]
pub fn handle(&self) -> ObjectHandle {
self.handle
}
#[inline]
pub fn object(&self) -> &T {
&self.object
}
#[inline]
pub fn object_mut(&mut self) -> &mut T {
&mut self.object
}
#[inline]
pub fn into_object(self) -> T {
self.object
}
#[inline]
pub fn is_valid(&self, current_generation: u32) -> bool {
self.handle.is_valid(current_generation)
}
}
pub trait ObjectRegistry<T> {
fn register(&mut self, object: T) -> ObjectHandle;
fn unregister(&mut self, handle: ObjectHandle) -> Result<T, ObjectError>;
fn get(&self, handle: ObjectHandle) -> Result<&T, ObjectError>;
fn get_mut(&mut self, handle: ObjectHandle) -> Result<&mut T, ObjectError>;
fn get_by_id(&self, id: u64) -> Option<&T>;
fn next_id(&mut self) -> u64;
fn increment_generation(&mut self, id: u64);
fn current_generation(&self, id: u64) -> u32;
fn is_valid(&self, handle: ObjectHandle) -> bool {
let current_gen = self.current_generation(handle.id());
handle.is_valid(current_gen) && self.get_by_id(handle.id()).is_some()
}
fn all_ids(&self) -> Vec<u64>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn get_parent(&self, handle: &ObjectHandle) -> Result<Option<ObjectHandle>, ObjectError>;
fn get_children(&self, handle: &ObjectHandle) -> Result<Vec<ObjectHandle>, ObjectError>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::object_model::handle::ObjectType;
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq)]
struct TestObject {
name: String,
value: i32,
}
struct TestRegistry {
objects: HashMap<u64, RegistryEntry<TestObject>>,
next_id_counter: u64,
generations: HashMap<u64, u32>,
parents: HashMap<u64, ObjectHandle>,
children: HashMap<u64, Vec<ObjectHandle>>,
}
impl TestRegistry {
fn new() -> Self {
Self {
objects: HashMap::new(),
next_id_counter: 1,
generations: HashMap::new(),
parents: HashMap::new(),
children: HashMap::new(),
}
}
fn set_parent(&mut self, child: ObjectHandle, parent: ObjectHandle) {
self.parents.insert(child.id(), parent);
self.children
.entry(parent.id())
.or_insert_with(Vec::new)
.push(child);
}
}
impl ObjectRegistry<TestObject> for TestRegistry {
fn register(&mut self, object: TestObject) -> ObjectHandle {
let id = self.next_id();
let generation = self.current_generation(id);
let handle = ObjectHandle::new(ObjectType::Window, id, generation);
self.objects.insert(id, RegistryEntry::new(handle, object));
handle
}
fn unregister(&mut self, handle: ObjectHandle) -> Result<TestObject, ObjectError> {
let current_gen = self.current_generation(handle.id());
if !handle.is_valid(current_gen) {
return Err(ObjectError::stale_handle(handle, current_gen));
}
self.increment_generation(handle.id());
self.objects
.remove(&handle.id())
.map(|entry| entry.into_object())
.ok_or_else(|| ObjectError::not_found(handle))
}
fn get(&self, handle: ObjectHandle) -> Result<&TestObject, ObjectError> {
let current_gen = self.current_generation(handle.id());
if !handle.is_valid(current_gen) {
return Err(ObjectError::stale_handle(handle, current_gen));
}
self.objects
.get(&handle.id())
.map(|entry| entry.object())
.ok_or_else(|| ObjectError::not_found(handle))
}
fn get_mut(&mut self, handle: ObjectHandle) -> Result<&mut TestObject, ObjectError> {
let current_gen = self.current_generation(handle.id());
if !handle.is_valid(current_gen) {
return Err(ObjectError::stale_handle(handle, current_gen));
}
self.objects
.get_mut(&handle.id())
.map(|entry| entry.object_mut())
.ok_or_else(|| ObjectError::not_found(handle))
}
fn get_by_id(&self, id: u64) -> Option<&TestObject> {
self.objects.get(&id).map(|entry| entry.object())
}
fn next_id(&mut self) -> u64 {
let id = self.next_id_counter;
self.next_id_counter += 1;
id
}
fn increment_generation(&mut self, id: u64) {
let gen = self.generations.entry(id).or_insert(0);
*gen = gen.wrapping_add(1);
}
fn current_generation(&self, id: u64) -> u32 {
self.generations.get(&id).copied().unwrap_or(0)
}
fn all_ids(&self) -> Vec<u64> {
self.objects.keys().copied().collect()
}
fn len(&self) -> usize {
self.objects.len()
}
fn get_parent(&self, handle: &ObjectHandle) -> Result<Option<ObjectHandle>, ObjectError> {
let current_gen = self.current_generation(handle.id());
if !handle.is_valid(current_gen) {
return Err(ObjectError::stale_handle(*handle, current_gen));
}
if !self.objects.contains_key(&handle.id()) {
return Err(ObjectError::not_found(*handle));
}
Ok(self.parents.get(&handle.id()).copied())
}
fn get_children(&self, handle: &ObjectHandle) -> Result<Vec<ObjectHandle>, ObjectError> {
let current_gen = self.current_generation(handle.id());
if !handle.is_valid(current_gen) {
return Err(ObjectError::stale_handle(*handle, current_gen));
}
if !self.objects.contains_key(&handle.id()) {
return Err(ObjectError::not_found(*handle));
}
Ok(self
.children
.get(&handle.id())
.cloned()
.unwrap_or_else(Vec::new))
}
}
#[test]
fn test_registry_entry_creation() {
let handle = ObjectHandle::new(ObjectType::Window, 1, 0);
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let entry = RegistryEntry::new(handle, obj.clone());
assert_eq!(entry.handle(), handle);
assert_eq!(entry.object(), &obj);
}
#[test]
fn test_registry_entry_mutability() {
let handle = ObjectHandle::new(ObjectType::Window, 1, 0);
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let mut entry = RegistryEntry::new(handle, obj);
entry.object_mut().value = 100;
assert_eq!(entry.object().value, 100);
}
#[test]
fn test_register_and_get() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let handle = registry.register(obj.clone());
let retrieved = registry.get(handle).unwrap();
assert_eq!(retrieved, &obj);
}
#[test]
fn test_unregister() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let handle = registry.register(obj.clone());
assert_eq!(registry.len(), 1);
let removed = registry.unregister(handle).unwrap();
assert_eq!(removed, obj);
assert_eq!(registry.len(), 0);
}
#[test]
fn test_stale_handle_after_unregister() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let handle = registry.register(obj.clone());
registry.unregister(handle).unwrap();
let result = registry.get(handle);
assert!(matches!(result, Err(ObjectError::StaleHandle { .. })));
}
#[test]
fn test_generation_increment() {
let mut registry = TestRegistry::new();
let obj1 = TestObject {
name: "first".to_string(),
value: 1,
};
let obj2 = TestObject {
name: "second".to_string(),
value: 2,
};
let handle1 = registry.register(obj1);
let id = handle1.id();
registry.unregister(handle1).unwrap();
assert_eq!(registry.current_generation(id), 1);
let handle2 = registry.register(obj2);
assert_ne!(handle2.id(), id);
assert_eq!(handle2.generation(), 0); }
#[test]
fn test_get_by_id() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let handle = registry.register(obj.clone());
let retrieved = registry.get_by_id(handle.id()).unwrap();
assert_eq!(retrieved, &obj);
}
#[test]
fn test_is_valid() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let handle = registry.register(obj);
assert!(registry.is_valid(handle));
registry.unregister(handle).unwrap();
assert!(!registry.is_valid(handle));
}
#[test]
fn test_all_ids() {
let mut registry = TestRegistry::new();
let h1 = registry.register(TestObject {
name: "one".to_string(),
value: 1,
});
let h2 = registry.register(TestObject {
name: "two".to_string(),
value: 2,
});
let mut ids = registry.all_ids();
ids.sort();
assert_eq!(ids.len(), 2);
assert!(ids.contains(&h1.id()));
assert!(ids.contains(&h2.id()));
}
#[test]
fn test_len_and_is_empty() {
let mut registry = TestRegistry::new();
assert!(registry.is_empty());
assert_eq!(registry.len(), 0);
let handle = registry.register(TestObject {
name: "test".to_string(),
value: 42,
});
assert!(!registry.is_empty());
assert_eq!(registry.len(), 1);
registry.unregister(handle).unwrap();
assert!(registry.is_empty());
assert_eq!(registry.len(), 0);
}
#[test]
fn test_get_mut() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let handle = registry.register(obj);
{
let obj_mut = registry.get_mut(handle).unwrap();
obj_mut.value = 100;
}
let obj = registry.get(handle).unwrap();
assert_eq!(obj.value, 100);
}
#[test]
fn test_get_parent_none() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "root".to_string(),
value: 1,
};
let handle = registry.register(obj);
let parent = registry.get_parent(&handle).unwrap();
assert!(parent.is_none());
}
#[test]
fn test_get_parent_some() {
let mut registry = TestRegistry::new();
let parent_obj = TestObject {
name: "parent".to_string(),
value: 1,
};
let child_obj = TestObject {
name: "child".to_string(),
value: 2,
};
let parent_handle = registry.register(parent_obj);
let child_handle = registry.register(child_obj);
registry.set_parent(child_handle, parent_handle);
let retrieved_parent = registry.get_parent(&child_handle).unwrap();
assert_eq!(retrieved_parent, Some(parent_handle));
}
#[test]
fn test_get_parent_stale_handle() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let handle = registry.register(obj);
registry.unregister(handle).unwrap();
let result = registry.get_parent(&handle);
assert!(matches!(result, Err(ObjectError::StaleHandle { .. })));
}
#[test]
fn test_get_children_empty() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "leaf".to_string(),
value: 1,
};
let handle = registry.register(obj);
let children = registry.get_children(&handle).unwrap();
assert!(children.is_empty());
}
#[test]
fn test_get_children_multiple() {
let mut registry = TestRegistry::new();
let parent_obj = TestObject {
name: "parent".to_string(),
value: 1,
};
let child1_obj = TestObject {
name: "child1".to_string(),
value: 2,
};
let child2_obj = TestObject {
name: "child2".to_string(),
value: 3,
};
let parent_handle = registry.register(parent_obj);
let child1_handle = registry.register(child1_obj);
let child2_handle = registry.register(child2_obj);
registry.set_parent(child1_handle, parent_handle);
registry.set_parent(child2_handle, parent_handle);
let children = registry.get_children(&parent_handle).unwrap();
assert_eq!(children.len(), 2);
assert!(children.contains(&child1_handle));
assert!(children.contains(&child2_handle));
}
#[test]
fn test_get_children_stale_handle() {
let mut registry = TestRegistry::new();
let obj = TestObject {
name: "test".to_string(),
value: 42,
};
let handle = registry.register(obj);
registry.unregister(handle).unwrap();
let result = registry.get_children(&handle);
assert!(matches!(result, Err(ObjectError::StaleHandle { .. })));
}
#[test]
fn test_navigation_hierarchy() {
let mut registry = TestRegistry::new();
let window_handle = registry.register(TestObject {
name: "window".to_string(),
value: 1,
});
let tab_handle = registry.register(TestObject {
name: "tab".to_string(),
value: 2,
});
let pane_handle = registry.register(TestObject {
name: "pane".to_string(),
value: 3,
});
registry.set_parent(tab_handle, window_handle);
registry.set_parent(pane_handle, tab_handle);
let pane_parent = registry.get_parent(&pane_handle).unwrap().unwrap();
assert_eq!(pane_parent, tab_handle);
let tab_parent = registry.get_parent(&tab_handle).unwrap().unwrap();
assert_eq!(tab_parent, window_handle);
let window_parent = registry.get_parent(&window_handle).unwrap();
assert!(window_parent.is_none());
let window_children = registry.get_children(&window_handle).unwrap();
assert_eq!(window_children.len(), 1);
assert_eq!(window_children[0], tab_handle);
let tab_children = registry.get_children(&tab_handle).unwrap();
assert_eq!(tab_children.len(), 1);
assert_eq!(tab_children[0], pane_handle);
}
}