honeycomb-core 0.11.0

Core structure implementation for combinatorial maps
Documentation
//! Attribute operations implementation
//!
//! This module contains code used to implement operations on the embedded data associated to the
//! map. This includes operations regarding vertices as well as (in the future) user-defined
//! generic attributes

use crate::attributes::{
    AttributeBind, AttributeStorage, AttributeUpdate, UnknownAttributeStorage,
};
use crate::cmap::{CMap3, VertexIdType};
use crate::geometry::{CoordsFloat, Vertex3};
use crate::stm::{StmClosureResult, Transaction, atomically};

/// ## **Built-in vertex-related methods**
impl<T: CoordsFloat> CMap3<T> {
    /// Return the current number of vertices.
    #[must_use = "unused return value"]
    pub fn n_vertices(&self) -> usize {
        self.vertices.n_attributes()
    }

    #[allow(clippy::missing_errors_doc)]
    /// Return the vertex associated to a given identifier.
    ///
    /// # Return / Errors
    ///
    /// This method is meant to be called in a context where the returned `Result` is used to
    /// validate the transaction passed as argument. Errors should not be processed manually,
    /// only processed via the `?` operator.
    ///
    /// This method return a `Option` taking the following values:
    /// - `Some(v: Vertex3)` if there is a vertex associated to this ID,
    /// - `None` otherwise.
    ///
    /// # Panics
    ///
    /// The method may panic if:
    /// - the index lands out of bounds,
    /// - the index cannot be converted to `usize`.
    #[must_use = "unused return value"]
    pub fn read_vertex_tx(
        &self,
        t: &mut Transaction,
        vertex_id: VertexIdType,
    ) -> StmClosureResult<Option<Vertex3<T>>> {
        self.vertices.read(t, vertex_id)
    }

    #[allow(clippy::missing_errors_doc)]
    /// Replace the vertex associated to a given identifier and return its old value.
    ///
    /// # Arguments
    ///
    /// - `vertex_id: VertexIdentifier` -- Identifier of the vertex to replace.
    /// - `vertex: impl Into<Vertex3>` -- New [`Vertex3`] value.
    ///
    /// # Return / Errors
    ///
    /// This method is meant to be called in a context where the returned `Result` is used to
    /// validate the transaction passed as argument. Errors should not be processed manually,
    /// only processed via the `?` operator.
    ///
    /// The result contains an `Option` taking the following values:
    /// - `Some(v: Vertex3)` if there was an old value,
    /// - `None` otherwise.
    ///
    /// # Panics
    ///
    /// The method may panic if:
    /// - the index lands out of bounds,
    /// - the index cannot be converted to `usize`.
    pub fn write_vertex_tx(
        &self,
        t: &mut Transaction,
        vertex_id: VertexIdType,
        vertex: impl Into<Vertex3<T>>,
    ) -> StmClosureResult<Option<Vertex3<T>>> {
        self.vertices.write(t, vertex_id, vertex.into())
    }

    #[allow(clippy::missing_errors_doc)]
    /// Remove the vertex associated to a given identifier and return it.
    ///
    /// # Return / Errors
    ///
    /// This method is meant to be called in a context where the returned `Result` is used to
    /// validate the transaction passed as argument. Errors should not be processed manually,
    /// only processed via the `?` operator.
    ///
    /// The result contains an `Option` taking the following values:
    /// - `Some(v: Vertex3)` if there was a value,
    /// - `None` otherwise.
    ///
    /// # Panics
    ///
    /// The method may panic if:
    /// - the index lands out of bounds,
    /// - the index cannot be converted to `usize`.
    pub fn remove_vertex_tx(
        &self,
        t: &mut Transaction,
        vertex_id: VertexIdType,
    ) -> StmClosureResult<Option<Vertex3<T>>> {
        self.vertices.remove(t, vertex_id)
    }

    /// Read the vertex associated to a given identifier.
    ///
    /// This variant is equivalent to `read_vertex`, but internally uses a transaction that will be
    /// retried until validated.
    #[must_use = "unused return value"]
    pub fn read_vertex(&self, vertex_id: VertexIdType) -> Option<Vertex3<T>> {
        atomically(|t| self.vertices.read(t, vertex_id))
    }

    /// Write a vertex to a given identifier, and return its old value.
    ///
    /// This variant is equivalent to `write_vertex`, but internally uses a transaction that will be
    /// retried until validated.
    pub fn write_vertex(
        &self,
        vertex_id: VertexIdType,
        vertex: impl Into<Vertex3<T>>,
    ) -> Option<Vertex3<T>> {
        let tmp = vertex.into();
        atomically(|t| self.vertices.write(t, vertex_id, tmp))
    }

    #[allow(clippy::must_use_candidate)]
    /// Remove the vertex associated to a given identifier and return it.
    ///
    /// This variant is equivalent to `remove_vertex`, but internally uses a transaction that will
    /// be retried until validated.
    pub fn remove_vertex(&self, vertex_id: VertexIdType) -> Option<Vertex3<T>> {
        atomically(|t| self.vertices.remove(t, vertex_id))
    }
}

/// ## **Generic attribute-related methods**
impl<T: CoordsFloat> CMap3<T> {
    #[allow(clippy::missing_errors_doc)]
    /// Return the attribute `A` value associated to a given identifier.
    ///
    /// The kind of cell `A` binds to is automatically deduced using its `AttributeBind`
    /// implementation.
    ///
    /// # Return / Errors
    ///
    /// This method is meant to be called in a context where the returned `Result` is used to
    /// validate the transaction passed as argument. Errors should not be processed manually,
    /// only processed via the `?` operator.
    ///
    /// This method return a `Option` taking the following values:
    /// - `Some(a: A)` if there is a value associated to this ID,
    /// - `None` otherwise, or if there is no storage for this kind of attribute in the map.
    ///
    /// # Panics
    ///
    /// The method may panic if:
    /// - the index lands out of bounds,
    /// - the index cannot be converted to `usize`.
    pub fn read_attribute_tx<A: AttributeBind + AttributeUpdate>(
        &self,
        t: &mut Transaction,
        id: A::IdentifierType,
    ) -> StmClosureResult<Option<A>> {
        self.attributes.read_attribute::<A>(t, id)
    }

    #[allow(clippy::missing_errors_doc)]
    /// Replace the attribute `A` value associated to a given identifier and return its old value.
    ///
    /// # Arguments
    ///
    /// - `id: A::IdentifierType` -- Identifier of the cell's value to replace.
    /// - `val: A` -- Attribute value.
    ///
    /// # Return / Errors
    ///
    /// This method is meant to be called in a context where the returned `Result` is used to
    /// validate the transaction passed as argument. Errors should not be processed manually,
    /// only processed via the `?` operator.
    ///
    /// The result contains an `Option` taking the following values:
    /// - `Some(a: A)` if there was an old value,
    /// - `None` otherwise, or if there is no storage for this kind of attribute in the map.
    ///
    /// # Panics
    ///
    /// The method may panic if:
    /// - the index lands out of bounds,
    /// - the index cannot be converted to `usize`.
    pub fn write_attribute_tx<A: AttributeBind + AttributeUpdate>(
        &self,
        t: &mut Transaction,
        id: A::IdentifierType,
        val: A,
    ) -> StmClosureResult<Option<A>> {
        self.attributes.write_attribute::<A>(t, id, val)
    }

    #[allow(clippy::missing_errors_doc)]
    /// Remove the attribute `A` value associated to a given identifier and return it.
    ///
    /// # Return / Errors
    ///
    /// This method is meant to be called in a context where the returned `Result` is used to
    /// validate the transaction passed as argument. Errors should not be processed manually,
    /// only processed via the `?` operator.
    ///
    /// The result contains an `Option` taking the following values:
    /// - `Some(a: A)` if there was a value,
    /// - `None` otherwise, or if there is no storage for this kind of attribute in the map.
    ///
    /// # Panics
    ///
    /// The method may panic if:
    /// - the index lands out of bounds,
    /// - the index cannot be converted to `usize`.
    pub fn remove_attribute_tx<A: AttributeBind + AttributeUpdate>(
        &self,
        t: &mut Transaction,
        id: A::IdentifierType,
    ) -> StmClosureResult<Option<A>> {
        self.attributes.remove_attribute::<A>(t, id)
    }

    /// Return the attribute `A` value associated to a given identifier.
    ///
    /// This variant is equivalent to `read_attribute`, but internally uses a transaction that will be
    /// retried until validated.
    #[allow(clippy::needless_pass_by_value)]
    pub fn read_attribute<A: AttributeBind + AttributeUpdate>(
        &self,
        id: A::IdentifierType,
    ) -> Option<A> {
        atomically(|t| self.attributes.read_attribute::<A>(t, id.clone()))
    }

    /// Replace the attribute `A` value associated to a given identifier and return its old value.
    ///
    /// This variant is equivalent to `write_attribute`, but internally uses a transaction that will be
    /// retried until validated.
    #[allow(clippy::needless_pass_by_value)]
    pub fn write_attribute<A: AttributeBind + AttributeUpdate>(
        &self,
        id: A::IdentifierType,
        val: A,
    ) -> Option<A> {
        atomically(|t| self.attributes.write_attribute::<A>(t, id.clone(), val))
    }

    /// Remove the attribute `A` value associated to a given identifier and return it.
    ///
    /// This variant is equivalent to `remove_attribute`, but internally uses a transaction that
    /// will be retried until validated.
    #[allow(clippy::needless_pass_by_value)]
    pub fn remove_attribute<A: AttributeBind + AttributeUpdate>(
        &self,
        id: A::IdentifierType,
    ) -> Option<A> {
        atomically(|t| self.attributes.remove_attribute::<A>(t, id.clone()))
    }
    // --- big guns

    /// Remove the attribute `A`'s storage from the map.
    ///
    /// This method is useful when implementing routines that use attributes to run; Those can
    /// then be removed before the final result is returned.
    pub fn remove_attribute_storage<A: AttributeBind + AttributeUpdate>(&mut self) {
        self.attributes.remove_storage::<A>();
    }

    /// Return a boolean indicating if the map contains the specified attribute.
    #[must_use = "unused return value"]
    pub fn contains_attribute<A: AttributeBind + AttributeUpdate>(&self) -> bool {
        self.attributes.contains_attribute::<A>()
    }
}