use super::input::input_node::parse_u64_strict;
use crate::iter::IntoDynBoxed;
use bytemuck::{Pod, Zeroable};
use itertools::Itertools;
use num_traits::ToPrimitive;
use serde::{Deserialize, Serialize};
use std::{
borrow::Cow,
fmt::{Debug, Display, Formatter},
iter,
};
pub mod edges;
pub mod layers;
pub mod properties;
use crate::core::entities::properties::prop::PropType;
pub use layers::*;
#[repr(transparent)]
#[derive(
Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize, Pod, Zeroable,
)]
pub struct VID(pub usize);
impl Default for VID {
fn default() -> Self {
VID(usize::MAX)
}
}
impl VID {
pub fn index(&self) -> usize {
self.0
}
pub fn as_u64(&self) -> u64 {
self.0 as u64
}
#[inline]
pub fn is_initialised(&self) -> bool {
self.0 != usize::MAX
}
#[inline]
pub fn or_init(self, init: impl FnOnce() -> VID) -> Self {
if self.is_initialised() {
self
} else {
init()
}
}
#[inline]
pub fn or_maybe_init(self, init: impl FnOnce() -> Option<VID>) -> Option<Self> {
if self.is_initialised() {
Some(self)
} else {
init()
}
}
#[inline]
pub fn into_option(self) -> Option<Self> {
self.is_initialised().then_some(self)
}
}
impl From<usize> for VID {
fn from(id: usize) -> Self {
VID(id)
}
}
impl From<VID> for usize {
fn from(id: VID) -> Self {
id.0
}
}
#[repr(transparent)]
#[derive(
Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize, Pod, Zeroable,
)]
pub struct EID(pub usize);
impl Default for EID {
fn default() -> Self {
EID(usize::MAX)
}
}
impl EID {
pub fn index(&self) -> usize {
self.0
}
pub fn as_u64(self) -> u64 {
self.0 as u64
}
pub fn with_layer(self, layer: LayerId) -> ELID {
ELID::new(self, layer)
}
pub fn with_layer_deletion(self, layer: LayerId) -> ELID {
ELID::new_deletion(self, layer)
}
}
impl From<EID> for usize {
fn from(id: EID) -> Self {
id.0
}
}
impl From<usize> for EID {
fn from(id: usize) -> Self {
EID(id)
}
}
impl EID {
pub fn from_u64(id: u64) -> Self {
EID(id as usize)
}
}
impl From<ELID> for EID {
fn from(elid: ELID) -> Self {
elid.eid()
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
pub struct ELID {
edge_and_deletion: EDID,
layer: LayerId,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
pub struct EDID(pub usize);
impl Debug for EDID {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EDID")
.field("edge", &self.eid())
.field("deletion", &self.is_deletion())
.finish()
}
}
impl EDID {
pub fn new(edge: EID) -> Self {
EDID(edge.0)
}
pub fn new_deletion(edge: EID) -> Self {
EDID(edge.0 | DELETION_FLAG)
}
pub fn eid(&self) -> EID {
EID(self.0 & !DELETION_FLAG)
}
pub fn is_deletion(&self) -> bool {
self.0 & DELETION_FLAG != 0
}
pub fn into_deletion(mut self) -> Self {
self.0 = self.0 | DELETION_FLAG;
self
}
}
impl Debug for ELID {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ELID")
.field("edge", &self.edge_and_deletion)
.field("layer", &self.layer())
.field("deletion", &self.is_deletion())
.finish()
}
}
const DELETION_FLAG: usize = 1usize.reverse_bits();
pub const MAX_EID: usize = usize::MAX & !DELETION_FLAG;
impl ELID {
pub fn new(edge: EID, layer: LayerId) -> Self {
ELID {
edge_and_deletion: EDID::new(edge),
layer,
}
}
pub fn new_flagged(edge_and_deletion: EDID, layer: LayerId) -> Self {
ELID {
edge_and_deletion,
layer,
}
}
pub fn new_deletion(edge: EID, layer: LayerId) -> Self {
ELID {
edge_and_deletion: EDID::new_deletion(edge),
layer,
}
}
pub fn layer(&self) -> LayerId {
self.layer
}
pub fn eid(&self) -> EID {
self.edge_and_deletion.eid()
}
pub fn eid_and_flag(&self) -> EDID {
self.edge_and_deletion
}
pub fn is_deletion(&self) -> bool {
self.edge_and_deletion.is_deletion()
}
pub fn into_deletion(mut self) -> Self {
self.edge_and_deletion = self.edge_and_deletion.into_deletion();
self
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub enum GID {
U64(u64),
Str(String),
}
impl PartialEq<str> for GID {
fn eq(&self, other: &str) -> bool {
match self {
GID::U64(_) => false,
GID::Str(id) => id == other,
}
}
}
impl PartialEq<String> for GID {
fn eq(&self, other: &String) -> bool {
match self {
GID::U64(_) => false,
GID::Str(id) => id == other,
}
}
}
impl PartialEq<u64> for GID {
fn eq(&self, other: &u64) -> bool {
match self {
GID::Str(_) => false,
GID::U64(id) => id == other,
}
}
}
impl Default for GID {
fn default() -> Self {
GID::U64(u64::MAX)
}
}
impl Display for GID {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
GID::U64(v) => write!(f, "{}", v),
GID::Str(v) => write!(f, "{}", v),
}
}
}
impl GID {
pub fn dtype(&self) -> GidType {
match self {
GID::U64(_) => GidType::U64,
GID::Str(_) => GidType::Str,
}
}
pub fn into_str(self) -> Option<String> {
match self {
GID::Str(v) => Some(v),
_ => None,
}
}
pub fn into_u64(self) -> Option<u64> {
match self {
GID::U64(v) => Some(v),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
GID::Str(v) => Some(v.as_str()),
_ => None,
}
}
pub fn as_u64(&self) -> Option<u64> {
match self {
GID::U64(v) => Some(*v),
_ => None,
}
}
pub fn to_str(&self) -> Cow<'_, str> {
match self {
GID::U64(v) => Cow::Owned(v.to_string()),
GID::Str(v) => Cow::Borrowed(v),
}
}
pub fn to_i64(&self) -> Option<i64> {
match self {
GID::U64(v) => v.to_i64(),
GID::Str(v) => parse_u64_strict(v)?.to_i64(),
}
}
pub fn to_u64(&self) -> Option<u64> {
match self {
GID::U64(v) => Some(*v),
GID::Str(v) => parse_u64_strict(v),
}
}
pub fn as_ref(&self) -> GidRef<'_> {
match self {
GID::U64(v) => GidRef::U64(*v),
GID::Str(v) => GidRef::Str(v),
}
}
}
impl From<u64> for GID {
fn from(id: u64) -> Self {
Self::U64(id)
}
}
impl From<&u64> for GID {
fn from(value: &u64) -> Self {
GID::U64(*value)
}
}
impl From<String> for GID {
fn from(id: String) -> Self {
Self::Str(id)
}
}
impl From<&str> for GID {
fn from(id: &str) -> Self {
Self::Str(id.to_string())
}
}
impl<'a> From<GidRef<'a>> for GID {
fn from(value: GidRef<'a>) -> Self {
match value {
GidRef::U64(v) => GID::U64(v),
GidRef::Str(v) => GID::Str(v.to_owned()),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum GidRef<'a> {
U64(u64),
Str(&'a str),
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub enum GidCow<'a> {
U64(u64),
Str(Cow<'a, str>),
}
impl<'a> From<GidRef<'a>> for GidCow<'a> {
fn from(value: GidRef<'a>) -> Self {
match value {
GidRef::U64(v) => Self::U64(v),
GidRef::Str(v) => Self::Str(Cow::Borrowed(v)),
}
}
}
impl<'a> GidCow<'a> {
pub fn as_ref<'b>(&'b self) -> GidRef<'b>
where
'a: 'b,
{
match self {
GidCow::U64(v) => GidRef::U64(*v),
GidCow::Str(v) => GidRef::Str(v),
}
}
pub fn into_owned(self) -> GID {
match self {
GidCow::U64(v) => GID::U64(v),
GidCow::Str(v) => GID::Str(v.into_owned()),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum GidType {
U64,
Str,
}
impl Display for GidType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
GidType::U64 => {
write!(f, "Numeric")
}
GidType::Str => {
write!(f, "String")
}
}
}
}
impl GidType {
pub fn from_prop_type(prop_type: &PropType) -> Option<Self> {
match prop_type {
PropType::Str => Some(GidType::Str),
PropType::U64 | PropType::U32 | PropType::I64 | PropType::I32 => Some(GidType::U64),
_ => None,
}
}
}
impl Display for GidRef<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
GidRef::U64(v) => write!(f, "{v}"),
GidRef::Str(v) => write!(f, "{v}"),
}
}
}
impl<'a> From<&'a GID> for GidRef<'a> {
fn from(value: &'a GID) -> Self {
match value {
GID::U64(v) => GidRef::U64(*v),
GID::Str(v) => GidRef::Str(v),
}
}
}
impl<'a> From<&'a str> for GidRef<'a> {
fn from(value: &'a str) -> Self {
GidRef::Str(value)
}
}
impl From<u64> for GidRef<'_> {
fn from(value: u64) -> Self {
GidRef::U64(value)
}
}
impl<'a> GidRef<'a> {
pub fn dtype(self) -> GidType {
match self {
GidRef::U64(_) => GidType::U64,
GidRef::Str(_) => GidType::Str,
}
}
pub fn as_str(self) -> Option<&'a str> {
match self {
GidRef::Str(s) => Some(s),
_ => None,
}
}
pub fn as_u64(self) -> Option<u64> {
match self {
GidRef::U64(v) => Some(v),
_ => None,
}
}
pub fn to_owned(self) -> GID {
match self {
GidRef::U64(v) => GID::U64(v),
GidRef::Str(v) => GID::Str(v.to_owned()),
}
}
pub fn to_str(self) -> Cow<'a, str> {
match self {
GidRef::U64(v) => Cow::Owned(v.to_string()),
GidRef::Str(v) => Cow::Borrowed(v),
}
}
pub fn to_i64(self) -> Option<i64> {
match self {
GidRef::U64(v) => v.to_i64(),
GidRef::Str(v) => parse_u64_strict(v)?.to_i64(),
}
}
pub fn to_u64(self) -> Option<u64> {
match self {
GidRef::U64(v) => Some(v),
GidRef::Str(v) => parse_u64_strict(v),
}
}
}
#[cfg(test)]
mod test {
use crate::core::entities::{LayerId, Multiple};
#[test]
fn empty_bit_multiple() {
let bm = super::Multiple::default();
let actual = bm.into_iter().collect::<Vec<_>>();
let expected: Vec<LayerId> = vec![];
assert_eq!(actual, expected);
}
#[test]
fn set_one() {
let bm: Multiple = [1].into_iter().collect();
let actual = bm.into_iter().collect::<Vec<_>>();
assert_eq!(actual, vec![1usize]);
}
#[test]
fn set_two() {
let bm: Multiple = [1, 67].into_iter().collect();
let actual = bm.into_iter().collect::<Vec<_>>();
assert_eq!(actual, vec![1usize, 67]);
}
}
impl LayerIds {
pub fn intersect(&self, other: &LayerIds) -> LayerIds {
match (self, other) {
(LayerIds::None, _) => LayerIds::None,
(_, LayerIds::None) => LayerIds::None,
(LayerIds::All, other) => other.clone(),
(this, LayerIds::All) => this.clone(),
(LayerIds::One(id), other) => {
if other.contains(id) {
LayerIds::One(*id)
} else {
LayerIds::None
}
}
(LayerIds::Multiple(ids), other) => {
let ids: Vec<_> = ids.iter().filter(|id| other.contains(id)).collect();
match ids.len() {
0 => LayerIds::None,
1 => LayerIds::One(ids[0]),
_ => LayerIds::Multiple(ids.into()),
}
}
}
}
pub fn union(&self, other: &LayerIds) -> LayerIds {
match (self, other) {
(LayerIds::All, _) | (_, LayerIds::All) => LayerIds::All,
(LayerIds::None, o) | (o, LayerIds::None) => o.clone(),
(LayerIds::One(id), LayerIds::One(other_id)) => {
if id == other_id {
LayerIds::One(*id)
} else {
LayerIds::Multiple([*id.min(other_id), *id.max(other_id)].into_iter().collect())
}
}
(LayerIds::Multiple(ids), LayerIds::Multiple(other_ids)) => {
LayerIds::Multiple(ids.iter().merge(other_ids.iter()).dedup().collect())
}
(LayerIds::One(id), LayerIds::Multiple(ids))
| (LayerIds::Multiple(ids), LayerIds::One(id)) => {
if ids.contains(*id) {
LayerIds::Multiple(ids.clone())
} else {
LayerIds::Multiple(ids.iter().merge(iter::once(*id)).collect())
}
}
}
}
pub fn contains(&self, layer_id: &LayerId) -> bool {
match self {
LayerIds::All => true,
LayerIds::One(id) => id == layer_id,
LayerIds::Multiple(ids) => ids.contains(*layer_id),
LayerIds::None => false,
}
}
pub fn is_none(&self) -> bool {
matches!(self, LayerIds::None)
}
pub fn is_single(&self) -> bool {
matches!(self, LayerIds::One(_))
}
pub fn is_all(&self) -> bool {
matches!(self, LayerIds::All)
}
pub fn iter(&self, num_layers: usize) -> impl Iterator<Item = LayerId> + use<'_> {
match self {
LayerIds::None => iter::empty().into_dyn_boxed(),
LayerIds::All => (0..num_layers).map(LayerId).into_dyn_boxed(),
LayerIds::One(id) => iter::once(*id).into_dyn_boxed(),
LayerIds::Multiple(ids) => ids.into_iter().into_dyn_boxed(),
}
}
pub fn into_iter(self, num_layers: usize) -> impl Iterator<Item = LayerId> {
match self {
LayerIds::None => iter::empty().into_dyn_boxed(),
LayerIds::All => (0..num_layers).map(LayerId).into_dyn_boxed(),
LayerIds::One(id) => iter::once(id).into_dyn_boxed(),
LayerIds::Multiple(ids) => ids.into_iter().into_dyn_boxed(),
}
}
}
impl From<Vec<usize>> for LayerIds {
fn from(v: Vec<usize>) -> Self {
match v.len() {
0 => LayerIds::All,
1 => LayerIds::One(LayerId(v[0])),
_ => LayerIds::Multiple(v.into()),
}
}
}
impl From<Vec<LayerId>> for LayerIds {
fn from(v: Vec<LayerId>) -> Self {
match v.len() {
0 => LayerIds::All,
1 => LayerIds::One(v[0]),
_ => LayerIds::Multiple(v.into()),
}
}
}
impl<const N: usize> From<[usize; N]> for LayerIds {
fn from(v: [usize; N]) -> Self {
match v.len() {
0 => LayerIds::All,
1 => LayerIds::One(LayerId(v[0])),
_ => LayerIds::Multiple(v.into_iter().collect()),
}
}
}
impl<const N: usize> From<[LayerId; N]> for LayerIds {
fn from(v: [LayerId; N]) -> Self {
match v.len() {
0 => LayerIds::All,
1 => LayerIds::One(v[0]),
_ => LayerIds::Multiple(v.into_iter().collect()),
}
}
}
impl From<usize> for LayerIds {
fn from(id: usize) -> Self {
LayerIds::One(LayerId(id))
}
}
impl From<LayerId> for LayerIds {
fn from(id: LayerId) -> Self {
LayerIds::One(id)
}
}
#[cfg(test)]
mod tests {
use std::hash::{Hash, Hasher};
use super::*;
use crate::core::entities::{LayerId, EID, MAX_EID};
use proptest::{prelude::*, prop_assert, prop_assert_eq, prop_oneof, proptest};
#[test]
fn test_elid_layer_proptest() {
proptest!(|(eid in 0..=MAX_EID, layer in 0..=usize::MAX)| {
let elid = EID(eid).with_layer(LayerId(layer));
prop_assert_eq!(elid.layer(), LayerId(layer));
prop_assert!(!elid.is_deletion());
let elid_deleted = elid.into_deletion();
prop_assert_eq!(elid_deleted.layer(), LayerId(layer));
prop_assert_eq!(elid_deleted.eid(), EID(eid));
prop_assert!(elid_deleted.is_deletion())
})
}
#[test]
fn test_elid_deletion_proptest() {
proptest!(|(eid in 0..=MAX_EID, layer in 0..=usize::MAX)| {
let elid = EID(eid).with_layer_deletion(LayerId(layer));
prop_assert_eq!(elid.layer(), LayerId(layer));
prop_assert!(elid.is_deletion());
prop_assert_eq!(elid, elid.into_deletion());
prop_assert_eq!(elid.eid().0, eid);
})
}
#[test]
fn gid_and_gid_ref_hash_to_the_same_thing() {
proptest!(|(gid in prop_oneof![any::<u64>().prop_map(GID::U64), ".*".prop_map(GID::Str)])| {
let gid_ref: GidRef<'_> = (&gid).into();
let mut gid_hasher = std::collections::hash_map::DefaultHasher::new();
let mut gid_ref_hasher = std::collections::hash_map::DefaultHasher::new();
gid.hash(&mut gid_hasher);
gid_ref.hash(&mut gid_ref_hasher);
prop_assert_eq!(gid_hasher.finish(), gid_ref_hasher.finish());
})
}
}