use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyDomain {
Node,
Edge,
Other,
}
impl KeyDomain {
fn parse(raw: Option<&str>) -> Self {
match raw {
Some("node") => Self::Node,
Some("edge") => Self::Edge,
_ => Self::Other,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyType {
Boolean,
Int,
Long,
Float,
Double,
String,
}
impl KeyType {
fn parse(raw: &str) -> Option<Self> {
Some(match raw {
"boolean" => Self::Boolean,
"int" => Self::Int,
"long" => Self::Long,
"float" => Self::Float,
"double" => Self::Double,
"string" => Self::String,
_ => return None,
})
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Boolean => "boolean",
Self::Int => "int",
Self::Long => "long",
Self::Float => "float",
Self::Double => "double",
Self::String => "string",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct KeyDecl {
pub(crate) name: String,
pub(crate) domain: KeyDomain,
pub(crate) attr_type: Option<KeyType>,
}
impl KeyDecl {
pub(crate) fn new(
id: &str,
name: Option<&str>,
domain: Option<&str>,
attr_type: Option<&str>,
) -> Self {
Self {
name: name.unwrap_or(id).to_owned(),
domain: KeyDomain::parse(domain),
attr_type: attr_type.and_then(KeyType::parse),
}
}
pub(crate) fn is_label(&self) -> bool {
let name = self.name.trim_start_matches(':');
name.eq_ignore_ascii_case("label") || name.eq_ignore_ascii_case("labels")
}
}
#[derive(Debug, Default)]
pub(crate) struct Keys {
decls: HashMap<String, KeyDecl>,
}
impl Keys {
pub(crate) fn insert(&mut self, id: String, decl: KeyDecl) {
self.decls.insert(id, decl);
}
pub(crate) fn get(&self, id: &str) -> Option<&KeyDecl> {
self.decls.get(id)
}
}
pub(crate) fn split_labels(raw: &str) -> Vec<String> {
raw.split([':', ';', ','])
.map(str::trim)
.filter(|label| !label.is_empty())
.map(str::to_owned)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn key_declarations_default_name_to_id_and_classify_labels() {
let key = KeyDecl::new("d0", None, Some("node"), Some("int"));
assert_eq!(key.name, "d0");
assert_eq!(key.domain, KeyDomain::Node);
assert_eq!(key.attr_type, Some(KeyType::Int));
assert!(!key.is_label());
assert!(KeyDecl::new("l", Some("labels"), Some("node"), None).is_label());
assert!(KeyDecl::new("l", Some(":LABEL"), None, None).is_label());
}
#[test]
fn labels_split_on_every_common_separator() {
assert_eq!(split_labels(":Person:Employee"), ["Person", "Employee"]);
assert_eq!(split_labels("Person; Employee"), ["Person", "Employee"]);
assert_eq!(split_labels("Person"), ["Person"]);
assert_eq!(split_labels("").len(), 0);
}
}