use crate::hash::xxh3_64;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct UrlKey(pub u64);
impl UrlKey {
#[must_use]
pub fn of(canonical_url: &str) -> Self {
Self(xxh3_64(canonical_url.as_bytes()))
}
#[must_use]
pub fn raw(self) -> u64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SegKey(pub u64);
impl SegKey {
#[must_use]
pub fn derive(owner: UrlKey, heading_path: &str) -> Self {
let mut buf = Vec::with_capacity(8 + 1 + heading_path.len());
buf.extend_from_slice(&owner.0.to_le_bytes());
buf.push(0);
buf.extend_from_slice(heading_path.as_bytes());
Self(xxh3_64(&buf))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NodeId(pub u32);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum EdgeType {
Link,
Related,
Redirect,
Contains,
Derives,
Conditions,
Unknown(u8),
}
impl EdgeType {
#[must_use]
pub fn as_tag(self) -> u8 {
match self {
Self::Link => 0,
Self::Related => 2,
Self::Redirect => 3,
Self::Contains => 4,
Self::Derives => 5,
Self::Conditions => 6,
Self::Unknown(t) => t,
}
}
#[must_use]
pub fn from_tag(tag: u8) -> Self {
match tag {
0 => Self::Link,
2 => Self::Related,
3 => Self::Redirect,
4 => Self::Contains,
5 => Self::Derives,
6 => Self::Conditions,
t => Self::Unknown(t),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn url_key_matches_xxh3_of_string() {
let k = UrlKey::of("https://example.com/a");
assert_eq!(k.raw(), xxh3_64(b"https://example.com/a"));
}
#[test]
fn seg_key_is_stable_and_distinct() {
let owner = UrlKey::of("https://example.com/a");
let a = SegKey::derive(owner, "Install > Linux");
let b = SegKey::derive(owner, "Install > Linux");
let c = SegKey::derive(owner, "Install > macOS");
assert_eq!(a, b);
assert_ne!(a, c);
assert_ne!(a, SegKey::derive(UrlKey::of("https://example.com/b"), "Install > Linux"));
}
#[test]
fn edge_type_tags_round_trip() {
for t in [EdgeType::Link, EdgeType::Related, EdgeType::Redirect, EdgeType::Unknown(9)] {
assert_eq!(EdgeType::from_tag(t.as_tag()), t);
}
}
}