diff --git a/.gitignore b/.gitignore index 3ca43ae..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1 @@ -# ---> Rust -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb - +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..33508fa --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ecs" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..914c6d3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ecs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..dd0c22c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,91 @@ +use std::fmt; + +// Error type +struct SparseSetError; + +#[derive(Debug, Copy, Clone)] +struct DenseItem { + index: usize, + value: T +} + +// TODO: Use arrays+slices instead of vecs +#[derive(Debug)] +struct SparseSet { + sparse: Vec>, + dense: Vec> +} + +impl SparseSet { + pub fn new() -> SparseSet { + SparseSet { + sparse: vec![], + dense: vec![] + } + } + + // Add an item to the dense vector and record its index in the sparse vector + fn insert(&mut self, value: T) { + let item = DenseItem { + index: self.dense.len(), + value: value + }; + self.dense.push(item); + let dense_index = self.dense.len() - 1; + self.sparse.push(Some(dense_index)); + } + + // Remove an item at the supplied target index from the set + // Replaces the selected target with the last item in the dense vector + fn remove(&mut self, target_sparse_index: usize) -> Result<(), SparseSetError> { + // Find the dense index of the target (need to decide what to do from there) + let target_dense_index = self.sparse[target_sparse_index].unwrap(); + + // If the target points to the last item in the dense set, this'll be easier + if target_dense_index + 1 == self.dense.len() { + // Remove the target from the dense set + self.dense.pop(); + + // Overwrite the target's sparse index + self.sparse[target_sparse_index] = None; + } else { + // Get the last item in the dense set as a source to switch with + // Change its index to the target sparse index, as it's replacing the target + let source_item = match self.dense.pop() { + Some(item) => { item }, + None => { return Err(SparseSetError) } + }; + + // Redirect the source item's sparse index to replace the target sparse index + self.sparse[source_item.index] = Some(target_sparse_index); + + // Assign the source item to the target's place in the dense set + self.dense[target_dense_index] = source_item; + + // Overwrite the target's sparse index + self.sparse[target_dense_index] = None; + } + + Ok(()) + } +} + +fn main() { + let mut test_set: SparseSet = SparseSet::new(); + test_set.insert(69.0); + test_set.insert(420.0); + test_set.insert(9001.0); + println!("{:?}", test_set); + test_set.remove(1); + println!("{:?}", test_set); + + // Create a mutable array (contiguous memory!) + let mut array: [Option>; 8] = [None; 8]; + + // Create a mutable slice of that whole array + let slice: &[Option>] = &mut array[..]; + + for item in slice { + println!("{:?}", item); + } +}