// SPDX-License-Identifier: Apache-2.0

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

#include "stdlib.h"

// 32 bit integer as as scale compact integer
// https://docs.substrate.io/reference/scale-codec/#fn-1
uint8_t *compact_encode_u32(uint8_t *dest, uint32_t val)
{
    if (val < 64)
    {
        *dest++ = val << 2;
    }
    else if (val < 0x4000)
    {
        *((uint16_t *)dest) = (val << 2) | 1;
        dest += 2;
    }
    else if (val < 0x40000000)
    {
        *((uint32_t *)dest) = (val << 2) | 2;
        dest += 4;
    }
    else
    {
        *dest++ = 3;
        *((uint32_t *)dest) = val;
        dest += 4;
    }

    return dest;
}

uint8_t *compact_decode_u32(uint8_t *dest, uint32_t *val)
{
    switch (*dest & 3)
    {
    case 0:
        *val = *dest >> 2;
        dest += 1;
        break;
    case 1:
        *val = *((uint16_t *)dest) >> 2;
        dest += 2;
        break;
    case 2:
        *val = *((uint32_t *)dest) >> 2;
        dest += 4;
        break;
    default:
        // sizes of 2**30 (1GB) or larger are not allowed
        __builtin_unreachable();
    }

    return dest;
}

uint8_t *scale_encode_string(uint8_t *dest, uint8_t *data, uint32_t len)
{
    uint8_t *data_dst = compact_encode_u32(dest, len);

    while (len--)
    {
        *data_dst++ = *data++;
    }

    return data_dst;
}

struct vector *scale_decode_string(uint8_t **from)
{
    uint8_t *src = *from;
    uint32_t size_array;

    src = compact_decode_u32(src, &size_array);

    struct vector *v = __malloc(sizeof(*v) + size_array);

    v->len = size_array;
    v->size = size_array;

    uint8_t *data = v->data;

    while (size_array--)
    {
        *data++ = *src++;
    }

    *from = src;

    return v;
}
