dynasty_rs/
lib.rs

1//! Dynasty: A powerful class inheritance system for Rust game engines
2
3pub mod error;
4pub mod registry;
5pub mod reflection;
6pub mod traits;
7
8// Re-export the proc macros
9pub use dynasty_macros::{Class, inherit};
10
11// Re-export core types
12pub use crate::registry::ClassInfo;
13pub use crate::traits::{Class as ClassTrait, Inherits, SafeDowncast};
14#[cfg(feature = "reflection")]
15pub use crate::reflection::{Reflect, ReflectionData};
16
17/// Prelude module containing commonly used types and traits
18pub mod prelude {
19    pub use crate::{Class, inherit};
20    pub use crate::traits::{Inherits, SafeDowncast};
21    pub use crate::registry::Registry;
22    
23    #[cfg(feature = "reflection")]
24    pub use crate::reflection::Reflect;
25}
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30    use std::any::{Any, TypeId};
31
32    // Basic test structs
33    #[derive(Class, Debug)]
34    struct Entity {
35        id: u64,
36        name: String,
37    }
38
39    #[inherit(Entity)]
40    #[derive(Debug)]
41    struct Character {
42        health: f32,
43        level: u32,
44    }
45
46    #[inherit(Character)]
47    #[derive(Debug)]
48    struct Player {
49        experience: u32,
50    }
51
52    // Test basic class creation and inheritance
53    #[test]
54    fn test_basic_inheritance() {
55        let entity = Entity {
56            id: 1,
57            name: "Test Entity".to_string(),
58        };
59
60        let character = Character {
61            base: Entity {
62                id: 2,
63                name: "Test Character".to_string(),
64            },
65            health: 100.0,
66            level: 1,
67        };
68
69        assert_eq!(entity.id, 1);
70        assert_eq!(character.base.id, 2);
71        assert_eq!(character.health, 100.0);
72    }
73
74    // Test multi-level inheritance
75    #[test]
76    fn test_multilevel_inheritance() {
77        let player = Player {
78            base: Character {
79                base: Entity {
80                    id: 3,
81                    name: "Test Player".to_string(),
82                },
83                health: 100.0,
84                level: 1,
85            },
86            experience: 0,
87        };
88
89        assert_eq!(player.base.base.id, 3);
90        assert_eq!(player.base.health, 100.0);
91        assert_eq!(player.experience, 0);
92    }
93
94    // Test class registry
95    #[test]
96    fn test_class_registry() {
97        let entity_info = Entity::class_info();
98        let character_info = Character::class_info();
99
100        assert_eq!(entity_info.name, "Entity");
101        assert_eq!(character_info.name, "Character");
102        assert!(character_info.parent.is_some());
103    }
104
105    // Test type checking and downcasting
106    #[test]
107    fn test_type_checking() {
108        let player = Player {
109            base: Character {
110                base: Entity {
111                    id: 4,
112                    name: "Test Player".to_string(),
113                },
114                health: 100.0,
115                level: 1,
116            },
117            experience: 0,
118        };
119
120        // Test inheritance relationships
121        assert_eq!(player.as_any().type_id(), TypeId::of::<Player>());
122        assert_eq!(player.base.as_any().type_id(), TypeId::of::<Character>());
123        assert_eq!(player.base.base.as_any().type_id(), TypeId::of::<Entity>());
124        
125        // Test safe downcasting
126        let as_character = player.base.as_any().downcast_ref::<Character>();
127        assert!(as_character.is_some());
128    }
129
130    // Test game patterns
131    #[test]
132    fn test_game_patterns() {
133        #[derive(Class)]
134        struct Transform {
135            position: (f32, f32, f32),
136        }
137
138        #[inherit(Entity)]
139        struct GameObject {
140            transform: Transform,
141        }
142
143        let game_object = GameObject {
144            base: Entity {
145                id: 6,
146                name: "Game Object".to_string(),
147            },
148            transform: Transform {
149                position: (0.0, 0.0, 0.0),
150            },
151        };
152
153        assert_eq!(game_object.transform.position, (0.0, 0.0, 0.0));
154    }
155
156    #[cfg(feature = "reflection")]
157    mod reflection_tests {
158        use super::*;
159        use crate::reflection::Reflect;
160
161        impl Reflect for Player {
162            fn get_field(&self, name: &str) -> Option<&dyn Any> {
163                match name {
164                    "experience" => Some(&self.experience),
165                    _ => None,
166                }
167            }
168
169            fn get_field_mut(&mut self, name: &str) -> Option<&mut dyn Any> {
170                match name {
171                    "experience" => Some(&mut self.experience),
172                    _ => None,
173                }
174            }
175
176            fn set_field(&mut self, name: &str, value: Box<dyn Any>) -> Result<(), error::DynastyError> {
177                match name {
178                    "experience" => {
179                        let type_id = value.type_id();
180                        match value.downcast::<u32>() {
181                            Ok(exp) => {
182                                self.experience = *exp;
183                                Ok(())
184                            }
185                            Err(_) => Err(error::DynastyError::TypeMismatch {
186                                expected: "u32".to_string(),
187                                found: format!("{:?}", type_id),
188                            })
189                        }
190                    }
191                    _ => Err(error::DynastyError::FieldNotFound(name.to_string())),
192                }
193            }
194        }
195
196        #[test]
197        fn test_reflection() {
198            let player = Player {
199                base: Character {
200                    base: Entity {
201                        id: 5,
202                        name: "Reflected Player".to_string(),
203                    },
204                    health: 100.0,
205                    level: 1,
206                },
207                experience: 100,
208            };
209
210            // Test field reflection
211            if let Some(exp_field) = player.get_field("experience") {
212                if let Some(exp_value) = exp_field.downcast_ref::<u32>() {
213                    assert_eq!(*exp_value, 100);
214                } else {
215                    panic!("Failed to downcast experience field to u32");
216                }
217            } else {
218                panic!("Failed to get experience field");
219            }
220
221            // Test non-existent field
222            assert!(player.get_field("nonexistent").is_none());
223        }
224    }
225}