lyra-engine/lyra-reflect/src/reflected_list.rs

147 lines
4.5 KiB
Rust

use std::any::TypeId;
use super::{Reflect, util};
pub trait List: Reflect {
fn get(&self, idx: usize) -> Option<&dyn Reflect>;
fn get_mut(&mut self, idx: usize) -> Option<&mut dyn Reflect>;
/// Push a value to the end of the List. If `item` is not the same type of the list,
/// it will be returned as [`Result::Err`].
fn push_back(&mut self, item: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
fn push_front(&mut self, item: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
/// Removes an item at `idx` from the List and returns the owned value.
fn remove_at(&mut self, idx: usize) -> Option<Box<dyn Reflect>>;
/// Removes the last element from the vector and returns it, `None` if it is empty.
fn pop_back(&mut self) -> Option<Box<dyn Reflect>>;
/// Removes the first element from the vector and returns it, `None` if it is empty.
///
/// Keep in mind this is slow if the List is not a `VecDeque`, or some other list type that is
/// optimized for removing from the front.
fn pop_front(&mut self) -> Option<Box<dyn Reflect>>;
/// Append a list to this list, removing the elements from `other`.
fn append(&mut self, other: &mut dyn List);
/// Reserves at least `additional` more space in the List. The spaces are not
/// initialized to anything.
fn reserve(&mut self, additional: usize);
/// Returns the length of the list
fn len(&self) -> usize;
/// Returns the total number of elements the list can hold without reallocating.
fn capacity(&self) -> usize;
/// Returns a boolean indicating if the list is empty.
fn is_empty(&self) -> bool;
/// Returns the TypeId of the elements in the list
fn elements_id(&self) -> TypeId;
fn apply_list(&mut self, other: &dyn List);
/// Creates a new, and empty list of the same type.
fn create_empty(&self) -> Box<dyn List>;
}
impl<T: Reflect + Clone> List for Vec<T> {
fn get(&self, idx: usize) -> Option<&dyn Reflect> {
if idx < self.len() {
Some(&self[idx])
} else {
None
}
}
fn get_mut(&mut self, idx: usize) -> Option<&mut dyn Reflect> {
if idx < self.len() {
Some(&mut self[idx])
} else {
None
}
}
fn push_back(&mut self, item: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
if item.is(TypeId::of::<T>()) {
let item = *(item as Box<dyn std::any::Any>).downcast::<T>()
.unwrap();
self.push(item);
Ok(())
} else {
Err(item)
}
}
fn push_front(&mut self, _item: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
unimplemented!("push_front for `List` trait implementation of a `Vec<T>`. Doing so is slow!")
}
fn remove_at(&mut self, idx: usize) -> Option<Box<dyn Reflect>> {
if idx < self.len() {
let removed = Box::new(self.remove(idx));
Some(removed)
} else {
None
}
}
fn pop_back(&mut self) -> Option<Box<dyn Reflect>> {
let popped = Box::new(self.pop());
Some(popped)
}
fn pop_front(&mut self) -> Option<Box<dyn Reflect>> {
unimplemented!("pop_front for `List` trait implementation of a `Vec<T>`. Doing so is slow!")
}
fn append(&mut self, other: &mut dyn List) {
assert!(self.elements_id() == other.elements_id(),
"Provided a List that contains elements that don't match what's in Self!");
self.reserve(other.len());
// pop_back and reverse later is probably the best to use here. I don't have iterators
// written for `List` yet, and an implementation of pop_front for a `Vec` would be slow.
let mut other_elements = vec![];
while let Some(el) = other.pop_back() {
let el = *(el as Box<dyn std::any::Any>).downcast::<T>()
.expect("msg");
other_elements.push(el);
}
other_elements.reverse();
self.append(&mut other_elements);
}
fn len(&self) -> usize {
self.len()
}
fn is_empty(&self) -> bool {
self.is_empty()
}
fn elements_id(&self) -> TypeId {
TypeId::of::<T>()
}
fn apply_list(&mut self, other: &dyn List) {
util::apply_list(self, other);
}
fn create_empty(&self) -> Box<dyn List> {
Box::new(Vec::<T>::new())
}
fn reserve(&mut self, additional: usize) {
self.reserve(additional);
}
fn capacity(&self) -> usize {
self.capacity()
}
}