Column

A Column (opens in a new tab) is a collection of items indexed by auto-incrementing u32 keys. This might sound similar to a relational database table; in fact, it is a good analogy.

A Column (opens in a new tab) makes it efficient to push items to it and access the last element.

💡

It should be noted that in a future version indexing will start at 1, not 0.

This change will also break existing contracts that rely on the current Column implementation!

Examples

Storing a message log

Let's say you want to store a log of messages. You can do this with a Column<String>.

use cw_storey::containers::Column;
use cw_storey::CwStorage;
 
const MESSAGES_IX: u8 = 1;
 
let messages: Column<String> = Column::new(MESSAGES_IX);
let mut cw_storage = CwStorage(&mut storage);
let mut access = messages.access(&mut cw_storage);
 
access.push(&"Hello, world!".to_string()).unwrap();
 
assert_eq!(access.get(0).unwrap(), Some("Hello, world!".to_string()));
  • line 6: Here we construct the Column facade. The constructor takes a key, which is the prefix of the keys in the underlying storage backend.
  • line 8: The access (opens in a new tab) method returns a ColumnAccess (opens in a new tab) entity, which allows manipulating the column.
  • line 10: Here we push a message to the column.
  • line 12: We check that the message is stored correctly.

Iterating over the messages

As with Map (opens in a new tab), we can iterate over all messages.

use cw_storey::containers::{Column, Item};
use cw_storey::CwStorage;
 
use storey::containers::IterableAccessor as _;
 
const MESSAGES_IX: u8 = 1;
 
let messages: Column<String> = Column::new(MESSAGES_IX);
let mut cw_storage = CwStorage(&mut storage);
let mut access = messages.access(&mut cw_storage);
 
// populate the column
access.push(&"Hello, world!".to_string()).unwrap();
access.push(&"My name is Bob.".to_string()).unwrap();
access.push(&"Hell is empty and all the devils are here.".to_string()).unwrap();
 
let messages: Vec<_> = access.pairs().collect::<Result<_, _>>().unwrap();
 
assert_eq!(messages, vec![
    (0, "Hello, world!".to_string()),
    (1, "My name is Bob.".to_string()),
    (2, "Hell is empty and all the devils are here.".to_string()),
]);
  • line 4: We import the IterableAccessor trait to use iteration methods.
  • line 17: The pairs method produces an iterator over tuples of (index, value). In this case, we collect the iterator into a Vec for ease of making our assertion later.

Similarly to Map (opens in a new tab), you can use the keys (opens in a new tab), values (opens in a new tab), and pairs (opens in a new tab) methods to iterate over the items.

Bounded iteration

If you want to perform bounded iteration, it is possible. This time you need the BoundedIterableAccessor (opens in a new tab) trait, and the relevant methods are bounded_pairs (opens in a new tab), bounded_keys (opens in a new tab), and bounded_values (opens in a new tab).

The following example is the same as the previous one except for the bounds found in line 17, and the limited results.

💡

Currently, the lower bound is inclusive, and the upper bound is exclusive.

This will change in a future version, where you'll be able to choose between inclusive and exclusive bounds as suits you.

use cw_storey::containers::{Column, Item};
use cw_storey::CwStorage;
 
use storey::containers::BoundedIterableAccessor as _;
 
const MESSAGES_IX: u8 = 1;
 
let messages: Column<String> = Column::new(MESSAGES_IX);
let mut cw_storage = CwStorage(&mut storage);
let mut access = messages.access(&mut cw_storage);
 
// populate the column
access.push(&"Hello, world!".to_string()).unwrap();
access.push(&"My name is Bob.".to_string()).unwrap();
access.push(&"Hell is empty and all the devils are here.".to_string()).unwrap();
 
let messages: Vec<_> = access.bounded_pairs(Some(0), Some(2)).collect::<Result<_, _>>().unwrap();
 
assert_eq!(messages, vec![
    (0, "Hello, world!".to_string()),
    (1, "My name is Bob.".to_string()),
]);