#ifndef KEKS_ATOM_H
#define KEKS_ATOM_H

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

enum KEKSAtomType {
    KEKSAtomEOC = 0x00,
    KEKSAtomNIL = 0x01,
    KEKSAtomFalse = 0x02,
    KEKSAtomTrue = 0x03,
    KEKSAtomHexlet = 0x04,
    KEKSAtomList = 0x08,
    KEKSAtomMap = 0x09,
    KEKSAtomBlob = 0x0B,
    KEKSAtomPint = 0x0C,
    KEKSAtomNint = 0x0D,
    KEKSAtomFloatNaN = 0x10,
    KEKSAtomFloatPinf = 0x11,
    KEKSAtomFloatNinf = 0x12,
    KEKSAtomFloat = 0x13,
    KEKSAtomTAI64 = 0x18,
    KEKSAtomTAI64N = 0x19,
    KEKSAtomTAI64NA = 0x1A,
    KEKSAtomMagic = 0x4B,

    KEKSAtomStrings = 0x80,
    KEKSAtomIsUTF8 = 0x40,
};

// TEXINFO: KEKSItemType
// @deftp {Data type} {enum KEKSItemType}
// High-level type of the atom.
// @itemize
// @item KEKSItemInvalid -- invalid item value, uninitialised
// @item KEKSItemEOC
// @item KEKSItemNIL
// @item KEKSItemFalse
// @item KEKSItemTrue
// @item KEKSItemHexlet
// @item KEKSItemPint -- positive integer
// @item KEKSItemNint -- negative integer
// @item KEKSItemList
// @item KEKSItemMap
// @item KEKSItemBlob
// @item KEKSItemFloat
// @item KEKSItemTAI64
// @item KEKSItemBin
// @item KEKSItemStr
// @item KEKSItemRaw -- raw value, non-decodable by the library
// @end itemize
// @end deftp
enum KEKSItemType {
    KEKSItemInvalid = 0,
    KEKSItemEOC = 1,
    KEKSItemNIL,
    KEKSItemFalse,
    KEKSItemTrue,
    KEKSItemHexlet,
    KEKSItemPint,
    KEKSItemNint,
    KEKSItemList,
    KEKSItemMap,
    KEKSItemBlob,
    KEKSItemFloat,
    KEKSItemTAI64,
    KEKSItemMagic,
    KEKSItemBin,
    KEKSItemStr,
    KEKSItemRaw,
};

// TEXINFO: KEKSAtom
// @deftp {Data type} {struct KEKSAtom}
// Basic unit of the library, describing single TLV-like value.
// @table @code
// @item .typ
//     High level @ref{KEKSItemType, type} of the atom's value. As a rule
//     you should look solely on it.
// @item .v.pint
//     Value of the positive integer.
// @item .v.nint
//     Value of the negative integer.
// @item .v.fp
//     Value of the floating point.
// @item .v.list
//     That value is filled only when dealing with @ref{Items, items}
//     for lists and maps.
//     Its @code{.head} is the index in items list to the first element
//     inside the container. If equals to 0, then it is empty. Its
//     @code{.len} contains number of the items (key-values pairs in
//     case of map) inside it.
// @item .v.blob
//     That value is filled only when dealing with @ref{Items, items}.
//     @code{.chunkLen} is the length of the chunk. @code{.chunks} is
//     the number of chunks, including the terminating binary string.
// @item .v.str
//     @code{.ptr} points to the start of the binary/UTF-8/TAI64*/Magic/hexlet
//     string. @code{.len} is its length in bytes.
//     Raw values use it as a payload.
// @end table
// @end deftp
struct KEKSAtom {
    union {
        uint64_t pint;
        int64_t nint;
        double fp;
        struct {
            size_t head;
            size_t len;
        } list;
        struct {
            size_t chunkLen;
            size_t chunks;
        } blob;
        struct {
            const unsigned char *ptr;
            size_t len;
        } str;
    } v;
    enum KEKSItemType typ;
    char _pad[4];
};

#endif // KEKS_ATOM_H
