Branch data Line data Source code
1 : : /**
2 : : * @file value.c
3 : : * @brief Value encoding and decoding helpers for typed trie terminals.
4 : : *
5 : : * Copyright (c) 2026 M. A. Chatterjee <deftio at deftio dot com>
6 : : * BSD-2-Clause — see LICENSE.txt
7 : : */
8 : :
9 : : #include "core_internal.h"
10 : :
11 : 10762 : tp_result tp_value_encode(tp_bitstream_writer *w, const tp_value *val)
12 : : {
13 [ + + + + ]: 10762 : if (!w || !val)
14 : 2 : return TP_ERR_INVALID_PARAM;
15 : :
16 : : /* Allocation failure paths are excluded from coverage (LCOV_EXCL). */
17 : : /* Write 4-bit type tag */
18 : 10760 : tp_result rc = tp_bs_write_bits(w, (uint64_t)val->type, 4);
19 [ - + ]: 10760 : if (rc != TP_OK)
20 : : return rc; /* LCOV_EXCL_LINE */
21 : :
22 [ + + + + : 10760 : switch (val->type) {
+ + + + +
- ]
23 : 10 : case TP_NULL:
24 : 10 : break;
25 : 24 : case TP_BOOL:
26 : 24 : rc = tp_bs_write_bit(w, val->data.bool_val ? 1 : 0);
27 : 24 : break;
28 : 548 : case TP_INT:
29 : 548 : rc = tp_bs_write_varint_s(w, val->data.int_val);
30 : 548 : break;
31 : 10079 : case TP_UINT:
32 : 10079 : rc = tp_bs_write_varint_u(w, val->data.uint_val);
33 : 10079 : break;
34 : 9 : case TP_FLOAT32: {
35 : : uint32_t bits;
36 : 9 : memcpy(&bits, &val->data.float32_val, sizeof(bits));
37 : 9 : rc = tp_bs_write_u32(w, bits);
38 : 9 : break;
39 : : }
40 : 20 : case TP_FLOAT64: {
41 : : uint64_t bits;
42 : 20 : memcpy(&bits, &val->data.float64_val, sizeof(bits));
43 : 20 : rc = tp_bs_write_u64(w, bits);
44 : 20 : break;
45 : : }
46 : 59 : case TP_STRING: {
47 : 59 : rc = tp_bs_write_varint_u(w, val->data.string_val.str_len);
48 [ - + ]: 59 : if (rc != TP_OK)
49 : : return rc; /* LCOV_EXCL_LINE */
50 : : /* Align to byte boundary before writing raw string data */
51 : 59 : rc = tp_bs_writer_align_to_byte(w);
52 [ - + ]: 59 : if (rc != TP_OK)
53 : : return rc; /* LCOV_EXCL_LINE */
54 : 59 : rc = tp_bs_write_bytes(w, (const uint8_t *)val->data.string_val.str,
55 : 59 : val->data.string_val.str_len);
56 : 59 : break;
57 : : }
58 : 9 : case TP_BLOB: {
59 : 9 : rc = tp_bs_write_varint_u(w, val->data.blob_val.len);
60 [ - + ]: 9 : if (rc != TP_OK)
61 : : return rc; /* LCOV_EXCL_LINE */
62 : : /* Align to byte boundary before writing raw blob data */
63 : 9 : rc = tp_bs_writer_align_to_byte(w);
64 [ - + ]: 9 : if (rc != TP_OK)
65 : : return rc; /* LCOV_EXCL_LINE */
66 : 9 : rc = tp_bs_write_bytes(w, val->data.blob_val.data, val->data.blob_val.len);
67 : 9 : break;
68 : : }
69 : 2 : case TP_ARRAY:
70 : : case TP_DICT:
71 : 2 : return TP_ERR_INVALID_PARAM; /* deferred */
72 : : }
73 : 10758 : return rc;
74 : : }
75 : :
76 : 50009546 : tp_result tp_value_decode(tp_bitstream_reader *r, tp_value *val, const uint8_t *base_buf)
77 : : {
78 [ + + + + ]: 50009546 : if (!r || !val)
79 : 2 : return TP_ERR_INVALID_PARAM;
80 : :
81 : 50009544 : memset(val, 0, sizeof(*val));
82 : :
83 : : uint64_t tag;
84 : 50009544 : tp_result rc = tp_bs_read_bits(r, 4, &tag);
85 [ + + ]: 50009544 : if (rc != TP_OK)
86 : 3 : return rc;
87 : 50009541 : val->type = (tp_value_type)tag;
88 : :
89 [ + + + + : 50009541 : switch (val->type) {
+ + + + +
+ ]
90 : 169 : case TP_NULL:
91 : 169 : break;
92 : 380 : case TP_BOOL: {
93 : : uint8_t bit;
94 : 380 : rc = tp_bs_read_bit(r, &bit);
95 [ + + ]: 380 : if (rc == TP_OK)
96 : 379 : val->data.bool_val = (bit != 0);
97 : 380 : break;
98 : : }
99 : 1586 : case TP_INT:
100 : 1586 : rc = tp_bs_read_varint_s(r, &val->data.int_val);
101 : 1586 : break;
102 : 50006210 : case TP_UINT:
103 : 50006210 : rc = tp_bs_read_varint_u(r, &val->data.uint_val);
104 : 50006210 : break;
105 : 23 : case TP_FLOAT32: {
106 : : uint32_t bits;
107 : 23 : rc = tp_bs_read_u32(r, &bits);
108 [ + + ]: 23 : if (rc == TP_OK)
109 : 21 : memcpy(&val->data.float32_val, &bits, sizeof(float));
110 : 23 : break;
111 : : }
112 : 53 : case TP_FLOAT64: {
113 : : uint64_t bits;
114 : 53 : rc = tp_bs_read_u64(r, &bits);
115 [ + + ]: 53 : if (rc == TP_OK)
116 : 50 : memcpy(&val->data.float64_val, &bits, sizeof(double));
117 : 53 : break;
118 : : }
119 : 930 : case TP_STRING: {
120 : : uint64_t slen;
121 : 930 : rc = tp_bs_read_varint_u(r, &slen);
122 [ + + ]: 930 : if (rc != TP_OK)
123 : 4 : return rc;
124 : : /* Align to byte boundary before reading raw string data */
125 : 927 : rc = tp_bs_reader_align_to_byte(r);
126 [ + + ]: 927 : if (rc != TP_OK)
127 : 1 : return rc;
128 [ + + ]: 926 : if (base_buf) {
129 : : const uint8_t *ptr;
130 : 925 : rc = tp_bs_reader_direct_ptr(r, &ptr, (size_t)slen);
131 [ + + ]: 925 : if (rc == TP_OK) {
132 : 909 : val->data.string_val.str = (const char *)ptr;
133 : 909 : val->data.string_val.str_len = (size_t)slen;
134 : : }
135 : : } else {
136 : 1 : rc = tp_bs_reader_advance(r, slen * 8);
137 : 1 : val->data.string_val.str = NULL;
138 : 1 : val->data.string_val.str_len = (size_t)slen;
139 : : }
140 : 926 : break;
141 : : }
142 : 18 : case TP_BLOB: {
143 : : uint64_t blen;
144 : 18 : rc = tp_bs_read_varint_u(r, &blen);
145 [ + + ]: 18 : if (rc != TP_OK)
146 : 3 : return rc;
147 : : /* Align to byte boundary before reading raw blob data */
148 : 16 : rc = tp_bs_reader_align_to_byte(r);
149 [ + + ]: 16 : if (rc != TP_OK)
150 : 1 : return rc;
151 [ + + ]: 15 : if (base_buf) {
152 : : const uint8_t *ptr;
153 : 14 : rc = tp_bs_reader_direct_ptr(r, &ptr, (size_t)blen);
154 [ + - ]: 14 : if (rc == TP_OK) {
155 : 14 : val->data.blob_val.data = ptr;
156 : 14 : val->data.blob_val.len = (size_t)blen;
157 : : }
158 : : } else {
159 : 1 : rc = tp_bs_reader_advance(r, blen * 8);
160 : 1 : val->data.blob_val.data = NULL;
161 : 1 : val->data.blob_val.len = (size_t)blen;
162 : : }
163 : 15 : break;
164 : : }
165 : 115 : case TP_ARRAY:
166 : : case TP_DICT:
167 : 115 : return TP_ERR_INVALID_PARAM; /* deferred */
168 : : }
169 : 50009419 : return rc;
170 : : }
|