Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rbx_reflection: Superclass Iterator #448

Merged
merged 11 commits into from
Sep 30, 2024
1 change: 1 addition & 0 deletions rbx_reflection/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# rbx_reflection Changelog

## Unreleased Changes
* Added `ReflectionDatabase::superclasses_iter`

## 4.7.0 (2024-08-22)
* Update to rbx_types 1.10
Expand Down
27 changes: 27 additions & 0 deletions rbx_reflection/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ pub struct ReflectionDatabase<'a> {
pub enums: HashMap<Cow<'a, str>, EnumDescriptor<'a>>,
}

pub struct SuperClassIter<'a> {
database: &'a ReflectionDatabase<'a>,
descriptor: Option<&'a ClassDescriptor<'a>>,
}
impl<'a> SuperClassIter<'a> {
fn next_descriptor(&self) -> Option<&'a ClassDescriptor<'a>> {
let superclass = self.descriptor?.superclass.as_ref()?;
self.database.classes.get(superclass)
}
}
impl<'a> Iterator for SuperClassIter<'a> {
type Item = &'a ClassDescriptor<'a>;
fn next(&mut self) -> Option<Self::Item> {
let next_descriptor = self.next_descriptor();
std::mem::replace(&mut self.descriptor, next_descriptor)
}
}

impl<'a> ReflectionDatabase<'a> {
/// Creates an empty `ReflectionDatabase` with a version number of 0.0.0.0.
pub fn new() -> Self {
Expand Down Expand Up @@ -59,6 +77,15 @@ impl<'a> ReflectionDatabase<'a> {
Some(list)
}

/// Returns an iterator of superclasses for the provided ClassDescriptor. This
/// iterator will start with the provided class and end with `Instance`.
pub fn superclasses_iter(&'a self, descriptor: &'a ClassDescriptor<'a>) -> SuperClassIter {
SuperClassIter {
database: self,
descriptor: Some(descriptor),
}
krakow10 marked this conversation as resolved.
Show resolved Hide resolved
}

/// Finds the default value of a property given its name and a class that
/// contains or inherits the property. Returns `Some(&Variant)` if a default
/// value exists, None otherwise.
Expand Down
23 changes: 23 additions & 0 deletions rbx_reflection_database/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,33 @@ pub fn get() -> &'static ReflectionDatabase<'static> {

#[cfg(test)]
mod test {
use rbx_reflection::ClassDescriptor;

use super::*;

#[test]
fn smoke_test() {
let _database = get();
}

#[test]
fn superclasses_iter_test() {
let database = get();
let part_class_descriptor = database.classes.get("Part");
let mut iter = database.superclasses_iter(part_class_descriptor.unwrap());
fn class_descriptor_eq(lhs: Option<&ClassDescriptor>, rhs: Option<&ClassDescriptor>) {
let eq = match (lhs, rhs) {
(Some(lhs), Some(rhs)) => lhs.name == rhs.name,
(None, None) => true,
_ => false,
};
assert!(eq, "{:?} != {:?}", lhs, rhs);
}
class_descriptor_eq(iter.next(), part_class_descriptor);
class_descriptor_eq(iter.next(), database.classes.get("FormFactorPart"));
class_descriptor_eq(iter.next(), database.classes.get("BasePart"));
class_descriptor_eq(iter.next(), database.classes.get("PVInstance"));
class_descriptor_eq(iter.next(), database.classes.get("Instance"));
class_descriptor_eq(iter.next(), None);
}
}