blob: 07b75c91810fc9010777a3b9f5da5f7edb1cc810 [file] [log] [blame]
//! Attributes for graph elements.
//!
//! This module is used for types that are used to describe the attributes of a graph element on
//! insertion.
//!
//! A consumer is not expected to use this module directly, but instead use the [`From`]
//! implementations for [`Attributes`].
//!
//! This module is exposed to allow for people who like to use a more explicit style to do so and
//! for the [`NoValue`] type, which cannot be created[^1] and is used to signal that an identifier
//! is managed by the storage implementation.
//!
//! [^1]: See source code for [`NoValue`] if you _really really really_ need to construct it.
//!
//! [`GraphStorage::next_node_id`]: crate::storage::GraphStorage::next_node_id
//! [`GraphStorage::next_edge_id`]: crate::storage::GraphStorage::next_edge_id
use crate::id::ArbitraryGraphId;
/// Marker type for `GraphId` which are managed by the graph.
///
/// This type is used to represent an `id` on insertion and deletion that is unused.
/// You normally do not need to construct this value directly, as [`Graph::insert_node`] and
/// [`Graph::insert_edge`] use `Attributes`.
///
/// # Implementation Details
///
/// The existence of this type is under stability guarantee, meaning that it will only be removed or
/// renamed according to `SemVer`, but the internals, such as layout or size, are not.
/// This includes the construction method.
///
/// [`Graph::insert_node`]: crate::graph::Graph::insert_node
/// [`Graph::insert_edge`]: crate::graph::Graph::insert_edge
pub struct NoValue(());
impl NoValue {
/// Construct a new `NoValue`.
///
/// This is only available for testing purposes.
#[doc(hidden)]
#[must_use]
pub const fn new() -> Self {
Self(())
}
}
/// Attributes for graph elements.
///
/// This type is used to represent the attributes of a graph element on insertion.
///
/// This type is completely opaque and is only used internally in the [`Graph`] implementation to
/// allow for transparent insertion using [`From`] implementations for elements that require either
/// of the types of `id`: [`ManagedGraphId`] or [`ArbitraryGraphId`].
///
/// You shouldn't need to construct this type directly, but instead simply use the [`From`]
/// implementation via `graph.insert_node(<weight>)` or `graph.insert_node((<weight>,))` for a
/// [`ManagedGraphId`] or `graph.insert_node((<id>, <weight>))` for an [`ArbitraryGraphId`].
/// This also applies for `insert_edge`.
///
/// [`Graph`]: crate::graph::Graph
/// [`ManagedGraphId`]: crate::id::ManagedGraphId
pub struct Attributes<I, W> {
pub(crate) id: I,
pub(crate) weight: W,
}
impl<W> Attributes<NoValue, W> {
/// Construct a new `Attributes` with the given weight.
///
/// This will not set the `id` of the attributes, and can only be used for graphs where the `id`
/// of the element must be a [`ManagedGraphId`].
///
/// [`ManagedGraphId`]: crate::id::ManagedGraphId
pub const fn new(weight: W) -> Self {
Self {
id: NoValue(()),
weight,
}
}
}
impl<W> Attributes<NoValue, W> {
/// Set the `id` of the attributes.
///
/// This will return a new `Attributes` with the given `id`, converting it from attributes that
/// are only valid for elements that have a [`ManagedGraphId`] as their `id`, to ones that only
/// have an [`ArbitraryGraphId`].
///
/// [`ManagedGraphId`]: crate::id::ManagedGraphId
pub fn with_id<I>(self, id: impl Into<I>) -> Attributes<I, W>
where
I: ArbitraryGraphId,
{
Attributes {
id: id.into(),
weight: self.weight,
}
}
}
impl<I, J, W> From<(J, W)> for Attributes<I, W>
where
I: From<J> + ArbitraryGraphId,
{
fn from(value: (J, W)) -> Self {
Self {
id: I::from(value.0),
weight: value.1,
}
}
}
impl<W> From<(W,)> for Attributes<NoValue, W> {
fn from((weight,): (W,)) -> Self {
Self {
id: NoValue(()),
weight,
}
}
}
impl<W> From<W> for Attributes<NoValue, W> {
fn from(weight: W) -> Self {
Self {
id: NoValue(()),
weight,
}
}
}
#[cfg(test)]
mod tests {
use core::{fmt::Debug, marker::PhantomData};
use crate::{
attributes::{Attributes, NoValue},
ArbitraryGraphId, GraphId, ManagedGraphId,
};
#[derive(Debug, Copy, Clone, PartialEq)]
struct Managed(usize);
impl GraphId for Managed {
type AttributeIndex = NoValue;
}
impl ManagedGraphId for Managed {}
#[derive(Debug, Copy, Clone, PartialEq)]
struct Arbitrary<V>(V);
impl<V> GraphId for Arbitrary<V>
where
V: Debug + Copy + Clone + PartialEq,
{
type AttributeIndex = Self;
}
impl<V> ArbitraryGraphId for Arbitrary<V> where V: Debug + Copy + Clone + PartialEq {}
impl<T> From<T> for Arbitrary<T> {
fn from(value: T) -> Self {
Self(value)
}
}
struct Fake<T> {
_marker: PhantomData<T>,
}
impl<T> Fake<T>
where
T: GraphId,
{
fn invoke(attributes: impl Into<Attributes<T::AttributeIndex, usize>>) {
let _attr = attributes.into();
}
}
#[test]
fn from() {
Fake::<Managed>::invoke(2usize);
Fake::<Arbitrary<usize>>::invoke((2usize, 2usize));
}
}