/*
 * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com>
 *
 * libcbor is free software; you can redistribute it and/or modify
 * it under the terms of the MIT license. See LICENSE for details.
 */

#include "ints.h"

cbor_int_width cbor_int_get_width(const cbor_item_t *item)
{
	assert(cbor_is_int(item));
	return item->metadata.int_metadata.width;
}

uint8_t cbor_get_uint8(const cbor_item_t *item)
{
	assert(cbor_is_int(item));
	assert(cbor_int_get_width(item) == CBOR_INT_8);
	return *item->data;
}

uint16_t cbor_get_uint16(const cbor_item_t *item)
{
	assert(cbor_is_int(item));
	assert(cbor_int_get_width(item) == CBOR_INT_16);
	return *(uint16_t *) item->data;
}

uint32_t cbor_get_uint32(const cbor_item_t *item)
{
	assert(cbor_is_int(item));
	assert(cbor_int_get_width(item) == CBOR_INT_32);
	return *(uint32_t *) item->data;
}

uint64_t cbor_get_uint64(const cbor_item_t *item)
{
	assert(cbor_is_int(item));
	assert(cbor_int_get_width(item) == CBOR_INT_64);
	return *(uint64_t *) item->data;
}

uint64_t cbor_get_int(const cbor_item_t * item)
{
	assert(cbor_is_int(item));
	switch(cbor_int_get_width(item)) {
		case CBOR_INT_8: return cbor_get_uint8(item);
		case CBOR_INT_16: return cbor_get_uint16(item);
		case CBOR_INT_32: return cbor_get_uint32(item);
		case CBOR_INT_64: return cbor_get_uint64(item);
	}
	return 0xDEADBEEF; /* Compiler complaints */
}

void cbor_set_uint8(cbor_item_t *item, uint8_t value)
{
	assert(cbor_is_int(item));
	assert(cbor_int_get_width(item) == CBOR_INT_8);
	*item->data = value;
}

void cbor_set_uint16(cbor_item_t *item, uint16_t value)
{
	assert(cbor_is_int(item));
	assert(cbor_int_get_width(item) == CBOR_INT_16);
	*(uint16_t *) item->data = value;
}


void cbor_set_uint32(cbor_item_t *item, uint32_t value)
{
	assert(cbor_is_int(item));
	assert(cbor_int_get_width(item) == CBOR_INT_32);
	*(uint32_t *) item->data = value;
}

void cbor_set_uint64(cbor_item_t *item, uint64_t value)
{
	assert(cbor_is_int(item));
	assert(cbor_int_get_width(item) == CBOR_INT_64);
	*(uint64_t *) item->data = value;
}

void cbor_mark_uint(cbor_item_t *item)
{
	assert(cbor_is_int(item));
	item->type = CBOR_TYPE_UINT;
}

void cbor_mark_negint(cbor_item_t *item)
{
	assert(cbor_is_int(item));
	item->type = CBOR_TYPE_NEGINT;
}

cbor_item_t *cbor_new_int8()
{
	cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 1);
	*item = (cbor_item_t) {
		.data = (unsigned char *) item + sizeof(cbor_item_t),
		.refcount = 1,
		.metadata = {.int_metadata = {.width = CBOR_INT_8}},
		.type = CBOR_TYPE_UINT
	};
	return item;
}

cbor_item_t *cbor_new_int16()
{
	cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 2);
	*item = (cbor_item_t) {
		.data = (unsigned char *) item + sizeof(cbor_item_t),
		.refcount = 1,
		.metadata = {.int_metadata = {.width = CBOR_INT_16}},
		.type = CBOR_TYPE_UINT
	};
	return item;
}

cbor_item_t *cbor_new_int32()
{
	cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4);
	*item = (cbor_item_t) {
		.data = (unsigned char *) item + sizeof(cbor_item_t),
		.refcount = 1,
		.metadata = {.int_metadata = {.width = CBOR_INT_32}},
		.type = CBOR_TYPE_UINT
	};
	return item;
}

cbor_item_t *cbor_new_int64()
{
	cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 8);
	*item = (cbor_item_t) {
		.data = (unsigned char *) item + sizeof(cbor_item_t),
		.refcount = 1,
		.metadata = {.int_metadata = {.width = CBOR_INT_64}},
		.type = CBOR_TYPE_UINT
	};
	return item;
}

cbor_item_t *cbor_build_uint8(uint8_t value)
{
	cbor_item_t *item = cbor_new_int8();
	cbor_set_uint8(item, value);
	cbor_mark_uint(item);
	return item;
}

cbor_item_t *cbor_build_uint16(uint16_t value)
{
	cbor_item_t *item = cbor_new_int16();
	cbor_set_uint16(item, value);
	cbor_mark_uint(item);
	return item;
}

cbor_item_t *cbor_build_uint32(uint32_t value)
{
	cbor_item_t *item = cbor_new_int32();
	cbor_set_uint32(item, value);
	cbor_mark_uint(item);
	return item;
}

cbor_item_t *cbor_build_uint64(uint64_t value)
{
	cbor_item_t *item = cbor_new_int64();
	cbor_set_uint64(item, value);
	cbor_mark_uint(item);
	return item;
}

cbor_item_t *cbor_build_negint8(uint8_t value)
{
	cbor_item_t *item = cbor_new_int8();
	cbor_set_uint8(item, value);
	cbor_mark_negint(item);
	return item;
}

cbor_item_t *cbor_build_negint16(uint16_t value)
{
	cbor_item_t *item = cbor_new_int16();
	cbor_set_uint16(item, value);
	cbor_mark_negint(item);
	return item;
}

cbor_item_t *cbor_build_negint32(uint32_t value)
{
	cbor_item_t *item = cbor_new_int32();
	cbor_set_uint32(item, value);
	cbor_mark_negint(item);
	return item;
}

cbor_item_t *cbor_build_negint64(uint64_t value)
{
	cbor_item_t *item = cbor_new_int64();
	cbor_set_uint64(item, value);
	cbor_mark_negint(item);
	return item;
}
