use std::collections::HashMap;
use panproto_gat::Name;
use serde::{Deserialize, Serialize};
use crate::value::{FieldPresence, Value};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Node {
pub id: u32,
pub anchor: Name,
pub value: Option<FieldPresence>,
pub discriminator: Option<Name>,
pub extra_fields: HashMap<String, Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub position: Option<u32>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub annotations: HashMap<String, Value>,
}
impl Node {
#[must_use]
pub fn new(id: u32, anchor: impl Into<Name>) -> Self {
Self {
id,
anchor: anchor.into(),
value: None,
discriminator: None,
extra_fields: HashMap::new(),
position: None,
annotations: HashMap::new(),
}
}
#[must_use]
pub fn with_value(mut self, value: FieldPresence) -> Self {
self.value = Some(value);
self
}
#[must_use]
pub fn with_discriminator(mut self, disc: impl Into<Name>) -> Self {
self.discriminator = Some(disc.into());
self
}
#[must_use]
pub fn with_extra_field(mut self, key: impl Into<String>, value: Value) -> Self {
self.extra_fields.insert(key.into(), value);
self
}
#[must_use]
pub fn has_value(&self) -> bool {
self.value.as_ref().is_some_and(FieldPresence::is_present)
}
#[must_use]
pub const fn is_leaf(&self) -> bool {
self.value.is_some()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn node_builder() {
let node = Node::new(0, "post:body.text")
.with_value(FieldPresence::Present(Value::Str("hello".into())))
.with_discriminator("string")
.with_extra_field("$lang", Value::Str("en".into()));
assert_eq!(node.id, 0);
assert_eq!(node.anchor, "post:body.text");
assert!(node.has_value());
assert!(node.is_leaf());
assert_eq!(node.discriminator.as_deref(), Some("string"));
assert_eq!(
node.extra_fields.get("$lang"),
Some(&Value::Str("en".into()))
);
}
#[test]
fn node_without_value() {
let node = Node::new(1, "post:body");
assert!(!node.has_value());
assert!(!node.is_leaf());
}
}