
// TODO Experiment with versioning. This may be removed or changed dramatically.
// Please ignore for now. Do not review.
#define OBOE_VERSION_EXPERIMENT  0
#if OBOE_VERSION_EXPERIMENT

#define OBOE_EARLIEST_SUPPORTED_VERSION  1
#define OBOE_CURRENT_VERSION  2

typedef struct OboeInterface_s {
    int32_t size; // do not use size_t because its size can vary
    int32_t version;
    int32_t reserved1;
    void *  reserved2;
    oboe_result_t (*createStreamBuilder)(OboeStreamBuilder *);
} OboeInterface_t;

OboeInterface_t s_oboe_template = {
        .size = sizeof(OboeInterface_t),
        .version = OBOE_CURRENT_VERSION,
        .reserved1 = 0,
        .reserved2 = NULL,
        .createStreamBuilder = Oboe_createStreamBuilder
};

oboe_result_t Oboe_Unimplemented(OboeInterface_t *oboe) {
    (void) oboe;
    return OBOE_ERROR_UNIMPLEMENTED;
}

typedef oboe_result_t (*OboeFunction_t)(OboeInterface_t *oboe);

int32_t Oboe_Initialize(OboeInterface_t *oboe, uint32_t flags) {
    if (oboe->version < OBOE_EARLIEST_SUPPORTED_VERSION) {
        return OBOE_ERROR_INCOMPATIBLE;
    }
    // Fill in callers vector table.
    uint8_t *start = (uint8_t*)&oboe->reserved1;
    uint8_t *end;
    if (oboe->size <= s_oboe_template.size) {
        end = ((uint8_t *)oboe) + oboe->size;
    } else {
        end = ((uint8_t *)oboe) + s_oboe_template.size;
        // Assume the rest of the structure is vectors.
        // Point them all to OboeInternal_Unimplemented()
        // Point to first vector past end of the known structure.
        OboeFunction_t *next = (OboeFunction_t*)end;
        while ((((uint8_t *)next) - ((uint8_t *)oboe)) < oboe->size) {
            *next++ = Oboe_Unimplemented;
        }
    }
    memcpy(&oboe->reserved1, &s_oboe_template.reserved1, end - start);
    return OBOE_OK;
}
#endif /* OBOE_VERSION_EXPERIMENT -------------------------- */
