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 : 12793 : tp_result tp_value_encode(tp_bitstream_writer *w, const tp_value *val)
12 : : {
13 [ + + + + ]: 12793 : 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 : 12791 : tp_result rc = tp_bs_write_bits(w, (uint64_t)val->type, 4);
19 : 12791 : if (rc != TP_OK) /* LCOV_EXCL_BR_LINE */
20 : : return rc; /* LCOV_EXCL_LINE */
21 : :
22 [ + + + + : 12791 : switch (val->type) {
+ + + + +
- ]
23 : 14 : case TP_NULL:
24 : 14 : break;
25 : 31 : case TP_BOOL:
26 : 31 : rc = tp_bs_write_bit(w, val->data.bool_val ? 1 : 0);
27 : 31 : break;
28 : 870 : case TP_INT:
29 : 870 : rc = tp_bs_write_varint_s(w, val->data.int_val);
30 : 870 : break;
31 : 11741 : case TP_UINT:
32 : 11741 : rc = tp_bs_write_varint_u(w, val->data.uint_val);
33 : 11741 : break;
34 : 10 : case TP_FLOAT32: {
35 : : uint32_t bits;
36 : 10 : memcpy(&bits, &val->data.float32_val, sizeof(bits));
37 : 10 : rc = tp_bs_write_u32(w, bits);
38 : 10 : break;
39 : : }
40 : 31 : case TP_FLOAT64: {
41 : : uint64_t bits;
42 : 31 : memcpy(&bits, &val->data.float64_val, sizeof(bits));
43 : 31 : rc = tp_bs_write_u64(w, bits);
44 : 31 : break;
45 : : }
46 : 73 : case TP_STRING: {
47 : 73 : rc = tp_bs_write_varint_u(w, val->data.string_val.str_len);
48 : 73 : if (rc != TP_OK) /* LCOV_EXCL_BR_LINE */
49 : : return rc; /* LCOV_EXCL_LINE */
50 : : /* Align to byte boundary before writing raw string data */
51 : 73 : rc = tp_bs_writer_align_to_byte(w);
52 : 73 : if (rc != TP_OK) /* LCOV_EXCL_BR_LINE */
53 : : return rc; /* LCOV_EXCL_LINE */
54 : 73 : rc = tp_bs_write_bytes(w, (const uint8_t *)val->data.string_val.str,
55 : 73 : val->data.string_val.str_len);
56 : 73 : break;
57 : : }
58 : 19 : case TP_BLOB: {
59 : 19 : rc = tp_bs_write_varint_u(w, val->data.blob_val.len);
60 : 19 : if (rc != TP_OK) /* LCOV_EXCL_BR_LINE */
61 : : return rc; /* LCOV_EXCL_LINE */
62 : : /* Align to byte boundary before writing raw blob data */
63 : 19 : rc = tp_bs_writer_align_to_byte(w);
64 : 19 : if (rc != TP_OK) /* LCOV_EXCL_BR_LINE */
65 : : return rc; /* LCOV_EXCL_LINE */
66 : 19 : rc = tp_bs_write_bytes(w, val->data.blob_val.data, val->data.blob_val.len);
67 : 19 : break;
68 : : }
69 : 2 : case TP_ARRAY:
70 : : case TP_DICT:
71 : 2 : return TP_ERR_INVALID_PARAM; /* deferred */
72 : : }
73 : 12789 : return rc;
74 : : }
75 : :
76 : 50275564 : tp_result tp_value_decode(tp_bitstream_reader *r, tp_value *val, const uint8_t *base_buf)
77 : : {
78 [ + + + + ]: 50275564 : if (!r || !val)
79 : 2 : return TP_ERR_INVALID_PARAM;
80 : :
81 : 50275562 : memset(val, 0, sizeof(*val));
82 : :
83 : : uint64_t tag;
84 : 50275562 : tp_result rc = tp_bs_read_bits(r, 4, &tag);
85 [ + + ]: 50275562 : if (rc != TP_OK)
86 : 10 : return rc;
87 : 50275552 : val->type = (tp_value_type)tag;
88 : :
89 [ + + + + : 50275552 : switch (val->type) {
+ + + + +
+ ]
90 : 3611 : case TP_NULL:
91 : 3611 : break;
92 : 8410 : case TP_BOOL: {
93 : : uint8_t bit;
94 : 8410 : rc = tp_bs_read_bit(r, &bit);
95 [ + + ]: 8410 : if (rc == TP_OK)
96 : 8409 : val->data.bool_val = (bit != 0);
97 : 8410 : break;
98 : : }
99 : 19913 : case TP_INT:
100 : 19913 : rc = tp_bs_read_varint_s(r, &val->data.int_val);
101 : 19913 : break;
102 : 50222660 : case TP_UINT:
103 : 50222660 : rc = tp_bs_read_varint_u(r, &val->data.uint_val);
104 : 50222660 : break;
105 : 143 : case TP_FLOAT32: {
106 : : uint32_t bits;
107 : 143 : rc = tp_bs_read_u32(r, &bits);
108 [ + + ]: 143 : if (rc == TP_OK)
109 : 129 : memcpy(&val->data.float32_val, &bits, sizeof(float));
110 : 143 : break;
111 : : }
112 : 9823 : case TP_FLOAT64: {
113 : : uint64_t bits;
114 : 9823 : rc = tp_bs_read_u64(r, &bits);
115 [ + + ]: 9823 : if (rc == TP_OK)
116 : 9798 : memcpy(&val->data.float64_val, &bits, sizeof(double));
117 : 9823 : break;
118 : : }
119 : 10236 : case TP_STRING: {
120 : : uint64_t slen;
121 : 10236 : rc = tp_bs_read_varint_u(r, &slen);
122 [ + + ]: 10236 : if (rc != TP_OK)
123 : 4 : return rc;
124 : : /* Align to byte boundary before reading raw string data */
125 : 10233 : rc = tp_bs_reader_align_to_byte(r);
126 [ + + ]: 10233 : if (rc != TP_OK)
127 : 1 : return rc;
128 [ + + ]: 10232 : if (base_buf) {
129 : : const uint8_t *ptr;
130 : 10231 : rc = tp_bs_reader_direct_ptr(r, &ptr, (size_t)slen);
131 [ + + ]: 10231 : if (rc == TP_OK) {
132 : 10130 : val->data.string_val.str = (const char *)ptr;
133 : 10130 : 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 : 10232 : break;
141 : : }
142 : 223 : case TP_BLOB: {
143 : : uint64_t blen;
144 : 223 : rc = tp_bs_read_varint_u(r, &blen);
145 [ + + ]: 223 : if (rc != TP_OK)
146 : 7 : return rc;
147 : : /* Align to byte boundary before reading raw blob data */
148 : 217 : rc = tp_bs_reader_align_to_byte(r);
149 [ + + ]: 217 : if (rc != TP_OK)
150 : 1 : return rc;
151 [ + + ]: 216 : if (base_buf) {
152 : : const uint8_t *ptr;
153 : 215 : rc = tp_bs_reader_direct_ptr(r, &ptr, (size_t)blen);
154 [ + + ]: 215 : if (rc == TP_OK) {
155 : 74 : val->data.blob_val.data = ptr;
156 : 74 : 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 : 216 : break;
164 : : }
165 : 200 : case TP_ARRAY:
166 : : case TP_DICT:
167 : 200 : return TP_ERR_INVALID_PARAM; /* deferred */
168 : : }
169 : 50275341 : return rc;
170 : : }
|