Day 24: Everything in it’s right place
Due to the holidays, now we begin the truly short posts!
The TUI is hooked up and displays correctly, at least in that it can display the loading status of the feed URLs. We haven’t yet started loading the actual episodes (called items, in RSS terminology), so lets do that!
Well, not quite. Before we can start loading the episodes we have to figure out how we want to store them. Regular readers will remember that I have an aesthetic objection to unnecessary memory allocations. I have a faulty mental model that calling into the memory allocator is the performance equivalent of reading from magnetic tape. This isn’t true, but what are the holidays for if not doing what makes you feel cozy?
As designed, we have a fixed maximum number of items per channel. Currently I have this set as a global constant,
though eventually it will likely need to be configurable for channel individually. But now isn’t eventually! So
for now, we can take advantage of this fixed size and pre-allocate a single Vec<Item> with size
item_count * ITEMS_PER_CHANNEL. This has the bonus of neatly assigning a fixed ID to each item (its index) which
we can use to refer to it when sending out HTTP requests. Here’s what this looks like:
#[derive(Debug, Clone, PartialEq, Eq)]
enum Item {
Unset,
Broken,
Loading {
title: String
},
Loaded {
title: String
}
}
// When the config is loaded
self.items.resize(channel_count * ITEMS_PER_CHANNEL, Item::Unset);
// After the HTTP request for a feed comes back
for (index_in_channel, item) in channel.items.into_iter().enumerate() {
// TODO: Actually start loading the item
self.items[channel_index as usize + index_in_channel] = Item::Loading {
title: item.title
};
}
We can now look up the items for a channel as follows:
&self.items[
(channel_index * ITEMS_PER_CHANNEL)
..
(channel_index * ITEMS_PER_CHANNEL) + ITEMS_PER_CHANNEL
];
This is somewhat like the methods prescribed by
data-oriented design, though not really because
in that case we would want separate Vecs for each state (so we don’t bloat the size of the enum
with data we don’t need). The true spirit of data-oriented design, though, is to design your data based
on how you access it, and I don’t yet have a perfect view of how I will.
In the future when we don’t have a fixed number of items across all channels I could instead store the count + offset
alongside each channel, or perhaps in different Vecs.