Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Generic attribute system

This content has been copy-pasted from the previous guide. It is up-to-date but should be improved at some point.


The attributes module of the core crate provides the necessary tools for to add custom attributes to given orbits of the map. Each attribute should be uniquely typed (i.e. to type aliases) as the maps’ internal storages use std::any::TypeId for identification.

An attribute struct should implement both AttributeBind and AttributeUpdate. It can then be added to the map using the dedicated CMapBuilder method. This is showcased in n example below, where we add

Implementation example

#![allow(unused)]
fn main() {
use honeycomb_core::{
    attributes::{AttrSparseVec, AttributeBind, AttributeError, AttributeUpdate},
    cmap::{OrbitPolicy, VertexIdType},
};

#[derive(Debug, Clone, Copy, Default, PartialEq)]
struct Weight(pub u32);

impl AttributeUpdate for Weight {
    // when merging two weights, we add them
    fn merge(attr1: Self, attr2: Self) -> Result<Self, AttributeError> {
        Ok(Self(attr1.0 + attr2.0))
    }

    // when splitting, we do an approximate 50/50
    fn split(attr: Self) -> Result<(Self, Self), AttributeError> {
        // adding the % to keep things conservative
        Ok((Self(attr.0 / 2 + attr.0 % 2), Self(attr.0 / 2)))
    }

    // if we have to merge from a single value, we assume the "other" is 0
    fn merge_incomplete(attr: Self) -> Result<Self, AttributeError> {
        Ok(attr)
    }
}

impl AttributeBind for Weight {
    // Weight values will be stored in an `AttrSparseVec`
    type StorageType = AttrSparseVec<Self>;
    // Weights bind to vertices
    type IdentifierType = VertexIdType;
    const BIND_POLICY: OrbitPolicy = OrbitPolicy::Vertex;
}
}

Usage example

use honeycomb_core::cmap::{CMap2, CMapBuilder};

fn main() {
    let map: CMap2<_> = CMapBuilder::<2, f64>::from_n_darts(4)
        .add_attribute::<Weight>()
        .build()
        .unwrap();

    let _ = map.link::<2>(1, 2);
    let _ = map.link::<2>(3, 4);
    map.write_vertex(2, (0.0, 1.0));
    map.write_vertex(3, (1.0, 1.0));
    map.write_attribute::<Weight>(2, Weight(5));
    map.write_attribute::<Weight>(3, Weight(6));

    let _ = map.sew::<1>(1, 3);

    assert_eq!(map.read_attribute::<Weight>(2), Some(Weight(11)));

    let _ = map.unsew::<1>(1);

    assert_eq!(map.read_attribute::<Weight>(2), Some(Weight(6)));
    assert_eq!(map.read_attribute::<Weight>(3), Some(Weight(5)));
}