//! Identifier and value primitives.
//!
//! `EntityId` and `AttrId` are `SmolStr`-backed newtypes; `Value` is a small
//! exhaustive enum covering the literal types triples can carry. The enum
//! variant set grows with later gates (e.g. timestamps, big integers); G4
//! lands the minimal subset needed to drive the EAV store.

use serde::{Deserialize, Serialize};
use smol_str::SmolStr;

/// Identifier of a logical entity within a project.
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct EntityId(pub SmolStr);

impl EntityId {
    /// Construct from any string-like value.
    pub fn new(s: impl Into<SmolStr>) -> Self {
        Self(s.into())
    }

    /// Borrow the underlying string.
    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }
}

/// Identifier of an attribute name (e.g. "name", "color").
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct AttrId(pub SmolStr);

impl AttrId {
    /// Construct from any string-like value.
    pub fn new(s: impl Into<SmolStr>) -> Self {
        Self(s.into())
    }

    /// Borrow the underlying string.
    pub fn as_str(&self) -> &str {
        self.0.as_str()
    }
}

/// Attribute value — the literal payload of a triple.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(tag = "type", content = "val", rename_all = "snake_case")]
pub enum Value {
    /// Explicit absent value.
    Null,
    /// Boolean.
    Bool(bool),
    /// 64-bit signed integer.
    Int(i64),
    /// UTF-8 string.
    Str(SmolStr),
    /// Reference to another entity.
    Ref(EntityId),
}
