pub struct Packo<const S: IDX, T, const C: CATS = 1> { /* private fields */ }Expand description
Create a packed structure Packo (array of Ts) with self referential
indexes.
T will be always be zero initialized in memory without calling any
default or constructor. T must be safe to be zero-initializable.
The total size of the Packo is scaled by S + 1 + the used array:
S must be greater than 1 as the 0th element is used as an always zeroed
sentinel value. And the extra
element is used for dirty writes when indexing out of the valid elements.
Each element will also have a few indexes, at least 4: next, prev, child,
parent. In case of C > 1 then the child index will repeat C times for
each category. These indexes will add to the size of each node. Each index
is of size of IDX.
When indexing the elements, the first element (Packo[0]) will always be
a nil value (zeroed T). The 0th element is an invalid element and used as
sentinel value. Writing to the 0th element will have also no effect.
If the index is out of the Packo bounds the 0th element will be returned.
Every item in Packo can connect as a list and/or a tree depending of the internal indexing capability. Because the internal indexing follows linked list principles, iterating into sub-lists will be linear time, but accessing a single item by index (id) will be constant instead.
Types:
- S: Size. How many elements are preallocated. One element is reserved for the sentinel value, S must be > 1.
- C: Categories. How many nesting categories are available per node. Each category will have its own separate child+parent indexing allowing for tree data structures based on the category index. Categories is defaulted to 1 and only if used the variant methods with suffix ‘c’ will select a specific category.
- T: The type contained per each node.
After calling Packo::insert a few times for 1, 2, 3, 4, the collection will contain a number of disconnected root nodes that can be iterated through Packo::roots:
use packo::*;
let mut p = Packo::<20, u8>::default();
p.insert(1);
p.insert(2);
p.insert(3);
p.insert(4);V IDX CHILD PARENT PREV NEXT
1 1 0 0 0 0
2 2 0 0 0 0
3 3 0 0 0 0
4 4 0 0 0 0|1| |2| |3| |4|If called differently by appending to each returned ixd, then the elements will be connected together in a linked list that later can be queried with Packo::next and iterated with Packo::siblings given the starting point (linked lists are circular).
use packo::*;
let mut p = Packo::<20, u8>::default();
let p1 = p.insert(1);
let p2 = p.append(p1,2);
let p3 = p.append(p2, 3);
p.append(p3, 4);V IDX CHILD PARENT PREV NEXT
1 1 0 0 4 2
2 2 0 0 1 3
3 3 0 0 2 4
4 4 0 0 3 1|1| <> |2| <> |3| <> |4|In this other example 1, 2 are roots and 3, 4 are a sublist of 1. Using Packo::nest the first element that calls that will spawn under the idx as a tree child. Children can later be checked with Packo::child to get the first child idx of a parent, or Packo::childs to iterate on all the childs of that parent.
use packo::*;
let mut p = Packo::<20, u8>::default();
let p1 = p.insert(1);
let p2 = p.append(p1, 2);
let p3 = p.nest(p1, 3);
p.append(p3, 4);V IDX CHILD PARENT PREV NEXT
1 1 3 0 2 2
2 2 0 0 1 1
3 3 0 1 4 4
4 4 0 1 3 3|1| <> |2|
|
|3| <> |4|When declaring Packo with a generic C for a number of categories
greater than the default (1), then the children can be split into subtree
by each category.
The method variants ending with ‘c’ will use the cateogry identifier to
select for which category to nest into or check childs for.
use packo::*;
let mut p = Packo::<20, u8, 2>::default();
let p1 = p.insert(1);
let p2 = p.append(p1, 2);
let p3 = p.nestc(p1, 3, 0);
p.append(p3, 4);
let p5 = p.nestc(p1, 5, 1);
p.append(p5, 6);V IDX CHILD[0] CHILD[1] PARENT PREV NEXT
1 1 3 5 0 2 2
2 2 0 0 0 1 1
3 3 0 0 1 4 4
4 4 0 0 1 3 3
5 5 0 0 1 6 6
6 6 0 0 1 5 5 |1| <> |2|
/ \
/ \
| | (via C=1)
| |
| |5| <> |6|
|
| (via C=0)
|
|3| <> |4| Implementations§
Source§impl<const S: IDX, T, const C: CATS> Packo<S, T, C>
impl<const S: IDX, T, const C: CATS> Packo<S, T, C>
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Delete all items, sets all to unused.
Examples found in repository?
144fn game_reset(e: &mut Entities) -> IDX {
145 e.reset();
146
147 let p = e.insert(Entity {
148 components: Component::Player + Component::Spatial + Component::Life.into(),
149 life: 100,
150 ..Default::default()
151 });
152 e[p].id = p;
153
154 let potion = e.nestc(
155 p,
156 CAT_INVENTORY,
157 Entity {
158 components: Component::Life + Component::Consume,
159 life: 50,
160 ..Default::default()
161 },
162 );
163 e[potion].id = potion;
164
165 let firebolt = e.nestc(
166 p,
167 CAT_SPELLS,
168 Entity {
169 components: Component::Damage + Component::Cost,
170 damage: 10,
171 cost: 5,
172 ..Default::default()
173 },
174 );
175 e[firebolt].id = firebolt;
176
177 let heal = e.nestc(
178 p,
179 CAT_SPELLS,
180 Entity {
181 components: Component::Life + Component::Cost,
182 life: 10,
183 cost: 5,
184 ..Default::default()
185 },
186 );
187 e[heal].id = heal;
188
189 p
190}Sourcepub fn next(&self, i: IDX) -> IDX
pub fn next(&self, i: IDX) -> IDX
Gets the next index, if this item is part of a list. Failure returns idx 0.
Examples found in repository?
23fn print(d: &Document, i: IDX) {
24 print!("<{}>", d[i].name);
25 let s = d.child(i);
26 let mut c = s;
27 while c != 0 {
28 print(d, c);
29 c = d.next(c);
30 if c == s {
31 break;
32 }
33 }
34 print!("{}", d[i].text);
35 print!("</{}>", d[i].name);
36}Sourcepub fn prev(&self, i: IDX) -> IDX
pub fn prev(&self, i: IDX) -> IDX
Gets the previous index, if this item is part of a list. Failure returns idx 0.
Sourcepub fn parent(&self, i: IDX) -> IDX
pub fn parent(&self, i: IDX) -> IDX
Gets the index of the parent of the given i.
Failure returns idx 0.
Sourcepub fn child(&self, i: IDX) -> IDX
pub fn child(&self, i: IDX) -> IDX
Gets the index of the first child, or 0 if no childs are present. Failure returns idx 0.
Examples found in repository?
23fn print(d: &Document, i: IDX) {
24 print!("<{}>", d[i].name);
25 let s = d.child(i);
26 let mut c = s;
27 while c != 0 {
28 print(d, c);
29 c = d.next(c);
30 if c == s {
31 break;
32 }
33 }
34 print!("{}", d[i].text);
35 print!("</{}>", d[i].name);
36}Sourcepub fn childc(&self, i: IDX, c: CATS) -> IDX
pub fn childc(&self, i: IDX, c: CATS) -> IDX
Gets the index of the first child, or 0 if no childs are present.
This retrieves the children for the category c if categories C>1,
otherwise use the basic variant Packo::child.
Failure returns idx 0.
Sourcepub fn insert(&mut self, t: T) -> IDX
pub fn insert(&mut self, t: T) -> IDX
Adds the T as a standalone node in the items. This element will only be found when using the basic iterator. It has no childs and no parent. Failure returns idx 0.
Examples found in repository?
More examples
144fn game_reset(e: &mut Entities) -> IDX {
145 e.reset();
146
147 let p = e.insert(Entity {
148 components: Component::Player + Component::Spatial + Component::Life.into(),
149 life: 100,
150 ..Default::default()
151 });
152 e[p].id = p;
153
154 let potion = e.nestc(
155 p,
156 CAT_INVENTORY,
157 Entity {
158 components: Component::Life + Component::Consume,
159 life: 50,
160 ..Default::default()
161 },
162 );
163 e[potion].id = potion;
164
165 let firebolt = e.nestc(
166 p,
167 CAT_SPELLS,
168 Entity {
169 components: Component::Damage + Component::Cost,
170 damage: 10,
171 cost: 5,
172 ..Default::default()
173 },
174 );
175 e[firebolt].id = firebolt;
176
177 let heal = e.nestc(
178 p,
179 CAT_SPELLS,
180 Entity {
181 components: Component::Life + Component::Cost,
182 life: 10,
183 cost: 5,
184 ..Default::default()
185 },
186 );
187 e[heal].id = heal;
188
189 p
190}Sourcepub fn nest(&mut self, i: IDX, t: T) -> IDX
pub fn nest(&mut self, i: IDX, t: T) -> IDX
Appends this item as a child of the given i.
If there were already children, append to the last of them, otherwise
this new element will be the only children.
Failure returns idx 0.
Sourcepub fn nestc(&mut self, i: IDX, c: CATS, t: T) -> IDX
pub fn nestc(&mut self, i: IDX, c: CATS, t: T) -> IDX
Nests based on category index. If default C=1 of category sizes, then use Packo::nest. Failure returns idx 0.
Examples found in repository?
144fn game_reset(e: &mut Entities) -> IDX {
145 e.reset();
146
147 let p = e.insert(Entity {
148 components: Component::Player + Component::Spatial + Component::Life.into(),
149 life: 100,
150 ..Default::default()
151 });
152 e[p].id = p;
153
154 let potion = e.nestc(
155 p,
156 CAT_INVENTORY,
157 Entity {
158 components: Component::Life + Component::Consume,
159 life: 50,
160 ..Default::default()
161 },
162 );
163 e[potion].id = potion;
164
165 let firebolt = e.nestc(
166 p,
167 CAT_SPELLS,
168 Entity {
169 components: Component::Damage + Component::Cost,
170 damage: 10,
171 cost: 5,
172 ..Default::default()
173 },
174 );
175 e[firebolt].id = firebolt;
176
177 let heal = e.nestc(
178 p,
179 CAT_SPELLS,
180 Entity {
181 components: Component::Life + Component::Cost,
182 life: 10,
183 cost: 5,
184 ..Default::default()
185 },
186 );
187 e[heal].id = heal;
188
189 p
190}Sourcepub fn append(&mut self, i: IDX, t: T) -> IDX
pub fn append(&mut self, i: IDX, t: T) -> IDX
Appends this element as a sibling after the given i.
i can be at any hierarchy but must be a valid used node.
Failure returns idx 0.
Sourcepub fn remove(&mut self, i: IDX) -> T
pub fn remove(&mut self, i: IDX) -> T
Remove this item from the list (sets it to unused). If an item has this one as a parent, its parent becomes 0/nil. If this item was part of a list, cut out its circular refs.
Sourcepub fn all(&self) -> impl Iterator<Item = &T>
pub fn all(&self) -> impl Iterator<Item = &T>
Iterates on all the elements regardless of their relation or hierarchy. Only used elements are returned.
Sourcepub fn roots(&self) -> impl Iterator<Item = &T>
pub fn roots(&self) -> impl Iterator<Item = &T>
Iterates only on the root nodes, nodes that have no parent.
Sourcepub fn siblings(&self, i: IDX) -> impl Iterator<Item = &T>
pub fn siblings(&self, i: IDX) -> impl Iterator<Item = &T>
Iterates on the linked list which this item is the first element of
Sourcepub fn childs(&self, i: IDX) -> impl Iterator<Item = &T>
pub fn childs(&self, i: IDX) -> impl Iterator<Item = &T>
Iterates on the siblings childs of this node.
Basically only one level of the tree given i being the parent idx.
Sourcepub fn childsc(&self, i: IDX, c: CATS) -> impl Iterator<Item = &T>
pub fn childsc(&self, i: IDX, c: CATS) -> impl Iterator<Item = &T>
Iterates on the siblings childs of this node.
Basically only one level of the tree given i being the parent idx.
This variant uses the category selector. For a simple version of C=1
use Packo::childs.
Examples found in repository?
192fn main() {
193 let mut e = Entities::default();
194 let p = game_reset(&mut e);
195
196 println!("Player: {}", e[p]);
197 for e in e.childsc(p, CAT_INVENTORY) {
198 println!("Item: {e}");
199 }
200 for e in e.childsc(p, CAT_SPELLS) {
201 println!("Spell: {e}");
202 }
203}