Files

194 lines
6.5 KiB
C

/**
* @file
* Compiled native readers and archive roots generated by Rust.
*
* DatType supplies storage sizes, identity and callbacks. Field layouts,
* annotations and expressions are compiled into the callbacks; this
* interface contains no DWARF members or expression operator tree.
*/
#ifndef DAT_SCHEMA_H
#define DAT_SCHEMA_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/// No type and no name: index 0 of DatSchema::types and DatSchema::names.
#define DAT_NONE 0
typedef enum DatKind {
/// `void`, functions, and types without a definition: nothing to read.
DAT_KIND_VOID,
/// Integers, characters, booleans and enumerations.
DAT_KIND_INT,
DAT_KIND_FLOAT,
DAT_KIND_POINTER,
DAT_KIND_STRUCT,
DAT_KIND_UNION,
DAT_KIND_ARRAY,
} DatKind;
struct DatArchive;
struct DatContext;
struct DatParent;
struct DatScope;
struct DatVerify;
/// A compiled expression. Rust emits its evaluator as ordinary C.
typedef struct DatExpr {
/// Return 1 with a value, or 0 for unresolved/undefined operations.
/// Arithmetic wraps at 64 bits. Depth counts macro expansion only.
int (*evaluate)(const struct DatArchive*, const struct DatContext*,
unsigned, uint64_t*);
} DatExpr;
/// Names bound by a loader or DAT_BIND. Generated readers own their storage.
typedef struct DatScope {
int32_t name;
uint64_t value;
const struct DatScope* outer;
} DatScope;
/// An element's compiled binding function, using caller-provided storage.
typedef const DatScope* (*DatBinding)(struct DatArchive*, const DatScope*,
const struct DatParent*, uint64_t,
DatScope*);
/// Command lengths for `DAT_SCRIPT` and `DAT_BYTE_SCRIPT`.
typedef struct DatScript {
/// Word-script lengths in words, starting at opcode 10.
const uint8_t* table;
uint32_t table_size;
/// Length expression, using the command's first word or byte as
/// `_command`.
const DatExpr* length;
/// Set for byte scripts: lengths are in bytes and all commands use
/// `length`.
uint8_t bytes;
} DatScript;
/// Generated storage/read callbacks include no-ops for inapplicable
/// operations. Verification is test-only. Layout changes belong in Rust
/// codegen.
typedef struct DatType {
/// Apply this type's annotations and read at the archive offset. Native
/// may be NULL when only traversing; parent supplies union context.
void (*read)(struct DatArchive*, uint32_t, void*, const struct DatParent*);
/// Convert the resolved plain layout into non-NULL native storage.
void (*convert)(struct DatArchive*, uint32_t, void*);
/// Check relocation compatibility for the resolved layout.
int (*fits)(const struct DatArchive*, uint32_t);
/// Resolve a field name at a record's archive base; return 0 if absent.
int (*field)(const struct DatArchive*, uint32_t, int32_t, uint64_t*);
/// Search union members' fields in declaration order, for conditions.
int (*union_field)(const struct DatArchive*, uint32_t, int32_t, uint64_t*);
/// Resolved native storage size, including a bounded flexible tail.
size_t (*allocation_size)(struct DatArchive*, uint32_t);
#ifdef DAT_NATIVE_TESTING
/// Compare the resolved native layout with archive bytes.
void (*verify)(struct DatVerify*, uint32_t, const void*, int);
#endif
uint8_t conditioned;
/// The type's name, for traces.
const char* name;
/// The generator's id for it, which traces print.
uint32_t id;
uint8_t kind;
#ifdef DAT_NATIVE_TESTING
/// Readback widening and coverage exclusion.
uint8_t is_signed, raw;
#endif
/// Precomputed through typedefs/qualifiers: keep serialized bytes.
uint8_t opaque;
/// Whether any part of it is a pointer, not looking through pointers.
uint8_t has_pointers;
/// A struct whose last member is a `DAT_EXTENT` array.
uint8_t has_extent;
/// An array with a dimension without a bound.
uint8_t unbounded;
/// Its size in the archive.
uint32_t size;
/// Its size natively; 0 where the generator couldn't spell it.
uint32_t native_size;
/// Pointers: the type pointed to, `DAT_NONE` for `void`. Typedefs and
/// qualifiers: the type named. Arrays: the element type.
int32_t target;
/// Through typedefs and qualifiers: the type it is.
int32_t resolved;
/// Arrays: the number of elements, every dimension's together; a
/// dimension without a bound counts as one.
uint32_t count;
} DatType;
typedef enum DatCount {
DAT_COUNT_ONE,
DAT_COUNT_EXACTLY,
/// As many as fit before the next public symbol or pointer target.
DAT_COUNT_EXTENT,
/// Up to and including the first element whose first word (or whole
/// value, if smaller) is `n` and not a relocated pointer.
DAT_COUNT_TERMINATED,
} DatCount;
/// A root of an archive: a public symbol by name, or an alias at an
/// address.
typedef struct DatRoot {
const char* name;
/// For an alias: where it is in the first archive of the file.
uint8_t alias;
uint32_t address;
int32_t type;
uint8_t count_kind;
uint64_t count;
/// A command script nothing points to, for an alias; `NULL` otherwise.
const DatScript* script;
const DatScope* env;
} DatRoot;
/// The roots of one archive of a file, as `melee-dat` types them.
typedef struct DatFileRoots {
/// The file, relative to the game's files, e.g. `PlCo.dat`.
const char* file;
/// Which archive of the file, for files that pack several.
uint32_t archive;
/// Public symbols, then aliases.
const DatRoot* roots;
uint32_t nroots;
} DatFileRoots;
/// The files of a module, the first two letters of their names: `Pl`, `Gr`.
typedef struct DatModule {
const DatFileRoots* files;
uint32_t nfiles;
} DatModule;
typedef struct DatSchema {
/// By index; the first, `DAT_NONE`, is `NULL`.
const DatType* const* types;
uint32_t ntypes;
/// The names members and expressions refer to; the first, `DAT_NONE`,
/// is `NULL`.
const char* const* names;
uint32_t nnames;
const DatModule* modules;
uint32_t nmodules;
} DatSchema;
/* --- Writing descriptors --------------------------------------------------
*/
#define DAT_COUNTOF(array) (sizeof(array) / sizeof *(array))
/// A file's roots and a module's files.
#define DAT_FILE_ROOTS(array) .roots = (array), .nroots = DAT_COUNTOF(array)
#define DAT_MODULE(array) { .files = (array), .nfiles = DAT_COUNTOF(array) }
#ifdef __cplusplus
}
#endif
#endif