// A FlatBuffer read and written with no generated code: the schema is a value, so a program can
// take one from a config. OFFICIAL below was built by Google's own Rust runtime, not by this plugin.
//
//   quillo run flatbuffers.qwe      then open http://localhost:8080/official, /write, /fields, /errors and /broken

use "flatbuffers.qwer"

let SCHEMA = {
    root: "Monster", file_identifier: "MONS",
    enums: { Color: { type: "ubyte", values: { Red: 0, Green: 1, Blue: 2 } } },
    structs: {
        Vec3: [{ name: "x", type: "float" }, { name: "y", type: "float" }, { name: "z", type: "float" }],
        Pair: [{ name: "a", type: "byte" }, { name: "b", type: "long" }, { name: "v", type: "Vec3" }],
    },
    unions: { Equip: ["Weapon", "Armor"] },
    tables: {
        Monster: [
            { name: "pos", type: "Vec3" }, { name: "mana", type: "short", default: 150 }, { name: "hp", type: "short", default: 100 },
            { name: "name", type: "string" }, { name: "friendly", type: "bool" }, { name: "inventory", type: "[ubyte]" },
            { name: "color", type: "Color", default: "Blue" }, { name: "weapons", type: "[Weapon]" }, { name: "equipped", type: "Equip" },
            { name: "path", type: "[Pair]" }, { name: "words", type: "[string]" }, { name: "big", type: "ulong" }, { name: "ratio", type: "double" },
        ],
        Weapon: [{ name: "name", type: "string" }, { name: "damage", type: "short" }],
        Armor: [{ name: "weight", type: "int" }],
    },
}

let OFFICIAL = "2c0000004d4f4e5300000000200040003400000032002c002b00240023001c0000000000000018000c00040020000000000000000000e03fffffffffffffffff000000002800000058000000000000013c0000000000000140000000000050000000803f00000040000040400200000014000000040000000600000068c3a96c6c6f00000200000068690000050000000001020304000000030000004f726300020000002400000004000000ecffffff0000050004000000030000004178650008000c00080006000800000000000300040000000500000053776f7264000000"

route GET /official = flatbuffers_read(OFFICIAL, SCHEMA)?

let OGRE = {
    pos: { x: 1.5, y: -2.0, z: 0.25 }, hp: 7, name: "Ogre", friendly: true, inventory: [9, 8, 7], color: "Green",
    weapons: [{ name: "Club", damage: 12 }, { name: "Rock" }], equipped_type: "Armor", equipped: { weight: 77 },
    path: [{ a: 1, b: -5, v: { x: 1.0, y: 2.0, z: 3.0 } }], words: ["a", "bb"], big: "18446744073709551615", ratio: 0.125,
}

route GET /write {
    let hex = flatbuffers_write(OGRE, SCHEMA)?
    let b64 = flatbuffers_write_base64(OGRE, SCHEMA)?
    let back = flatbuffers_read(hex, SCHEMA)?
    {
        back: back, identifier: slice(hex, 8, 16), same: flatbuffers_read_base64(b64, SCHEMA)? == back, aligned: len(hex) % 16,
        defaults: flatbuffers_read(flatbuffers_write({ name: "x", hp: 100, color: "Blue" }, SCHEMA)?, SCHEMA)?,
        empty: len(flatbuffers_write({}, SCHEMA)?),
    }
}

// Three ids given out of order, with a gap, and an old reader with fewer fields.
route GET /fields {
    let v2 = { root: "T", tables: { T: [{ name: "c", type: "int", id: 3 }, { name: "a", type: "int", id: 0 }, { name: "n", type: "string", id: 1 }] } }
    let v1 = { root: "T", tables: { T: [{ name: "a", type: "int" }] } }
    let hex = flatbuffers_write({ a: 1, n: "x", c: 3 }, v2)?
    {
        new: flatbuffers_read(hex, v2)?, old: flatbuffers_read(hex, v1)?,
        by_id: flatbuffers_field(hex, 3, 4)?, none: flatbuffers_field(hex, 2, 4)?.present, past: flatbuffers_field(hex, 40, 4)?.present,
    }
}

let SMALL = { root: "T", tables: { T: [{ name: "n", type: "byte" }, { name: "s", type: "string", required: true }, { name: "v", type: "[short]" }, { name: "k", type: "T" }] } }

route GET /errors = {
    big: flatbuffers_write({ s: "x", n: 300 }, SMALL).error,
    unknown: flatbuffers_write({ s: "x", q: 1 }, SMALL).error,
    required: flatbuffers_write({ n: 1 }, SMALL).error,
    deep_required: flatbuffers_write({ s: "x", k: { n: 1 } }, SMALL).error,
    not_list: flatbuffers_write({ s: "x", v: 1 }, SMALL).error,
    bad_enum: flatbuffers_write({ color: "Pink" }, SCHEMA).error,
    half_union: flatbuffers_write({ equipped: {} }, SCHEMA).error,
    bad_member: flatbuffers_write({ equipped_type: "Shield", equipped: {} }, SCHEMA).error,
    struct_gap: flatbuffers_write({ pos: { x: 1 } }, SCHEMA).error,
}

// A buffer damaged in each way there is: every read answers with what is wrong.
route GET /broken {
    let s = { root: "T", tables: { T: [{ name: "n", type: "int" }] } }
    {
        short: flatbuffers_read("0000", SCHEMA).error,
        identifier: flatbuffers_read("0c00000058585858000000000000000000000000", SCHEMA).error,
        past_end: flatbuffers_read("ffffff7f00000000", s).error,
        zero: flatbuffers_read("0000000000000000", s).error,
        misaligned: flatbuffers_read("0300000000000000", s).error,
        before: flatbuffers_read("040000006400000000000000", s).error,
        bad_vtable: flatbuffers_read("080000000000000003000800", s).error != null,
        not_hex: flatbuffers_read("zz", s).error,
        no_root: flatbuffers_read("00", { tables: {} }).error,
        bad_type: flatbuffers_read("00", { root: "T", tables: { T: [{ name: "a", type: "Nope" }] } }).error,
        self_struct: flatbuffers_read("00", { root: "T", tables: { T: [] }, structs: { A: [{ name: "a", type: "A" }] } }).error,
        no_file: flatbuffers_read_file("nothing.bin", s).error != null,
    }
}
