//! `Cell` — a type-erased 64-bit word holding one scalar value with its kind
//! stripped away (C7). The type lives in the schema / column / port, never in
//! the value, so a cell is read back only by naming its type via a typed
//! accessor. `Scalar` is built on top of this; `Cell` itself knows nothing of
//! `Scalar` or `ScalarKind`.

use crate::scalar::Timestamp;

/// A type-erased 64-bit cell: the raw storage of one scalar value with its kind
/// stripped away. The bits are meaningless on their own — the type lives in the
/// schema/column/port, not in the value (C7), so the word is recovered **only**
/// by naming the type at the call site via a typed accessor ([`Cell::i64`],
/// [`Cell::f64`], [`Cell::bool`], [`Cell::ts`]). Each reinterprets the word with
/// no tag to check and therefore no branch — the caller's choice of accessor
/// *is* the type context the hot path already holds. The inner word is private;
/// there is no kind-free way to read it.
///
/// All four base types fit one 64-bit word: `i64`/`Timestamp`/`bool` reuse the
/// same integer word, `f64` via its IEEE-754 bit pattern. `Eq`/`Hash` are
/// bit-exact (so `+0.0`/`-0.0` differ and a `NaN` bit pattern equals itself) —
/// the semantics of a raw word, not of a number.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Cell(u64);

impl Cell {
    /// Store an `i64` (identity bit-cast).
    pub fn from_i64(v: i64) -> Self {
        Cell(v as u64)
    }
    /// Store an `f64` as its IEEE-754 bit pattern.
    pub fn from_f64(v: f64) -> Self {
        Cell(v.to_bits())
    }
    /// Store a `bool` as `0`/`1`.
    pub fn from_bool(v: bool) -> Self {
        Cell(v as u64)
    }
    /// Store a [`Timestamp`] (its `i64` epoch-ns, bit-cast).
    pub fn from_ts(v: Timestamp) -> Self {
        Cell(v.0 as u64)
    }

    /// Read the word as `i64` (identity bit-cast). The caller asserts the type
    /// by choosing this accessor; there is no tag to check, hence no branch.
    pub fn i64(self) -> i64 {
        self.0 as i64
    }
    /// Read the word as `f64` from its IEEE-754 bit pattern. Branch-free.
    pub fn f64(self) -> f64 {
        f64::from_bits(self.0)
    }
    /// Read the word as `bool` (any non-zero word is `true`). Branch-free.
    pub fn bool(self) -> bool {
        self.0 != 0
    }
    /// Read the word as a [`Timestamp`] (identity bit-cast). Branch-free.
    pub fn ts(self) -> Timestamp {
        Timestamp(self.0 as i64)
    }
}
