use deepsize::DeepSizeOf;
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, Immutable, IntoBytes};
pub type NodeId = u64;
pub type EdgeId = u64;
pub type LabelId = u32;
pub type TypeId = u32;
pub type PropKeyId = u32;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum Language {
English = 1,
Spanish = 2,
French = 3,
German = 4,
Italian = 5,
Portuguese = 6,
}
impl Default for Language {
fn default() -> Self {
Self::English
}
}
impl Language {
pub fn from_u8(val: u8) -> Self {
match val {
2 => Self::Spanish,
3 => Self::French,
4 => Self::German,
5 => Self::Italian,
6 => Self::Portuguese,
_ => Self::English,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
impl std::str::FromStr for Language {
type Err = crate::error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"english" => Ok(Self::English),
"spanish" => Ok(Self::Spanish),
"french" => Ok(Self::French),
"german" => Ok(Self::German),
"italian" => Ok(Self::Italian),
"portuguese" => Ok(Self::Portuguese),
other => Err(crate::error::Error::InvalidArgument(format!(
"unknown language '{other}' (expected one of: english, spanish, french, german, italian, portuguese)"
))),
}
}
}
#[derive(Clone, Copy, Debug, IntoBytes, FromBytes, Immutable)]
#[repr(C, packed)]
pub struct AdjEntry {
pub edge_type: TypeId, pub other: NodeId, pub edge_id: EdgeId, }
impl DeepSizeOf for AdjEntry {
fn deep_size_of_children(&self, _context: &mut deepsize::Context) -> usize {
0
}
}
#[derive(Debug, Clone, Serialize, Deserialize, DeepSizeOf)]
pub struct NodeRecord {
pub labels: Vec<LabelId>,
pub props: Vec<u8>, }
impl NodeRecord {
pub fn primary_label(&self) -> Option<LabelId> {
self.labels.first().copied()
}
pub fn has_label(&self, id: LabelId) -> bool {
self.labels.contains(&id)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, DeepSizeOf)]
pub struct EdgeRecord {
pub src: NodeId,
pub dst: NodeId,
pub edge_type: TypeId,
pub props: Vec<u8>, }
#[derive(Debug, Clone, PartialEq)]
pub struct NeighborEntry {
pub node: NodeId,
pub edge: EdgeId,
pub edge_type: TypeId,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DirectedNeighborEntry {
pub node: NodeId,
pub edge: EdgeId,
pub edge_type: TypeId,
pub outgoing: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct WeightedPath {
pub nodes: Vec<NodeId>,
pub total_weight: f64,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PropValue {
Bool(bool),
Int(i64),
Float(f64),
Str(String),
}
impl PropValue {
pub(crate) fn into_json(self) -> serde_json::Value {
match self {
PropValue::Bool(b) => serde_json::Value::Bool(b),
PropValue::Int(i) => serde_json::Value::Number(i.into()),
PropValue::Float(f) => serde_json::json!(f),
PropValue::Str(s) => serde_json::Value::String(s),
}
}
}
impl From<bool> for PropValue {
fn from(v: bool) -> Self {
PropValue::Bool(v)
}
}
impl From<i64> for PropValue {
fn from(v: i64) -> Self {
PropValue::Int(v)
}
}
impl From<f64> for PropValue {
fn from(v: f64) -> Self {
PropValue::Float(v)
}
}
impl From<String> for PropValue {
fn from(v: String) -> Self {
PropValue::Str(v)
}
}
impl<'a> From<&'a str> for PropValue {
fn from(v: &'a str) -> Self {
PropValue::Str(v.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn language_from_str_is_case_insensitive_and_rejects_unknown() {
assert_eq!("english".parse::<Language>().unwrap(), Language::English);
assert_eq!("German".parse::<Language>().unwrap(), Language::German);
assert_eq!(
"PORTUGUESE".parse::<Language>().unwrap(),
Language::Portuguese
);
assert!("klingon".parse::<Language>().is_err());
}
}