blob: 7cc62771beac2ed4067288a41ef30145a400a30c [file] [log] [blame]
use core::{borrow::Borrow, fmt::Display};
use numi::borrow::Moo;
use petgraph_core::{Edge, GraphStorage};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Cost<T>(T);
impl<T> Cost<T> {
pub const fn new(value: T) -> Self {
Self(value)
}
pub const fn value(&self) -> &T {
&self.0
}
pub fn into_value(self) -> T {
self.0
}
}
// ensure that all traits have been implemented
// see: https://rust-lang.github.io/api-guidelines/interoperability.html
#[cfg(test)]
static_assertions::assert_impl_all!(Cost<&'static str>: core::fmt::Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, core::hash::Hash, Send, Sync, From<&'static str>, AsRef<&'static str>, Borrow<&'static str>);
impl<T> Display for Cost<T>
where
T: Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<T> From<T> for Cost<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl<T> AsRef<T> for Cost<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> Borrow<T> for Cost<T> {
fn borrow(&self) -> &T {
&self.0
}
}
pub struct DefaultCost;
pub trait GraphCost<S>
where
S: GraphStorage,
{
type Value;
fn cost<'graph>(&self, edge: Edge<'graph, S>) -> Moo<'graph, Self::Value>;
}
impl<S, F, T> GraphCost<S> for F
where
S: GraphStorage,
F: Fn(Edge<S>) -> Moo<T>,
{
type Value = T;
fn cost<'graph>(&self, edge: Edge<'graph, S>) -> Moo<'graph, T> {
self(edge)
}
}
impl<S> GraphCost<S> for DefaultCost
where
S: GraphStorage,
{
type Value = S::EdgeWeight;
fn cost<'graph>(&self, edge: Edge<'graph, S>) -> Moo<'graph, S::EdgeWeight> {
Moo::Borrowed(edge.weight())
}
}
#[cfg(test)]
mod tests {
use numi::borrow::Moo;
use petgraph_core::{edge::marker::Directed, Edge, GraphStorage};
use petgraph_dino::DinoStorage;
use crate::shortest_paths::common::cost::{DefaultCost, GraphCost};
fn needs_cost_fn<S, F, T>(_: F)
where
S: GraphStorage,
F: GraphCost<S, Value = T>,
{
}
fn maybe_edge_cost<S>(edge: Edge<S>) -> Moo<'_, usize>
where
S: GraphStorage,
S::EdgeWeight: AsRef<[u8]>,
{
edge.weight().as_ref().len().into()
}
#[test]
fn trait_impl() {
type StrStorage = DinoStorage<&'static str, &'static str, Directed>;
type UsizeStorage = DinoStorage<usize, usize, Directed>;
needs_cost_fn::<StrStorage, _, usize>(maybe_edge_cost);
needs_cost_fn::<UsizeStorage, _, usize>(DefaultCost);
}
}