Column

A Column 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 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 method returns a ColumnAccess 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, 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, you can use the keys, values, and pairs methods to iterate over the items.

Bounded iteration

If you want to perform bounded iteration, it is possible. This time you need the BoundedIterableAccessor trait, and the relevant methods are bounded_pairs, bounded_keys, and bounded_values.

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()),
]);