// Un valor que puede ser un entero, un decimal, una cadena o nada.
// La etiqueta kind dice qué variante de la union as está activa: lean solo esa.
//
// Quien usa el módulo sí ve los campos, porque hace switch sobre kind. Por eso Value no es
// un tipo opaco. La regla es de ustedes: creen un Value solo con estas funciones.
//
// Ownership: un Value de tipo VALUE_STRING posee su cadena. Asignar un Value a otro NO copia la
// cadena, solo su dirección: el owner pasa a ser la variable nueva, y la anterior ya no se
// usa ni se libera. Todo Value se libera una vez, con value_free.
#ifndef VALUE_H
#define VALUE_H

typedef enum { VALUE_NONE, VALUE_INT, VALUE_DOUBLE, VALUE_STRING } ValueKind;

typedef struct {
    ValueKind kind;
    union {
        int integer;   // VALUE_INT
        double number; // VALUE_DOUBLE
        char *text;    // VALUE_STRING: cadena en el heap, que posee este Value
    } as;
} Value;

// Devuelve un Value sin dato.
Value value_none(void);

// Devuelve un Value con ese entero.
Value value_int(int n);

// Devuelve un Value con ese decimal.
Value value_double(double x);

// Devuelve un Value con una COPIA de s, en memoria nueva: s puede cambiar o desaparecer
// después. s no puede ser NULL. Si no hay memoria, devuelve value_none().
Value value_string(const char *s);

// Convierte un campo de un archivo, según su forma:
//   vacío -> nada
//   solo dígitos, con un - inicial opcional -> entero, si está entre -2147483647 y 2147483647
//   dígitos, un punto y dígitos, con un - opcional, hasta 64 caracteres -> decimal
//   cualquier otra cosa -> cadena
Value value_parse(const char *field);

// Escribe el valor en la salida, sin salto de línea:
//   nada: (nada)     entero: 42     decimal: con dos decimales, 2.50     cadena: "Callao", con comillas
void value_print(const Value *v);

// Devuelve 1 si son la misma variante con el mismo contenido, y 0 si no.
// Dos nada son iguales. Un entero nunca es igual a un decimal: 3 y 3.00 son distintos.
// Las cadenas se comparan por su contenido, no por su dirección.
int value_equal(const Value *a, const Value *b);

// Libera lo que el valor posee y lo deja como nada. Sirve para cualquier variante.
void value_free(Value *v);

#endif
