Line data Source code
1 : #include "fd_pb_gen.h"
2 :
3 : uchar *
4 : fd_pb_encode( fd_pb_msgdesc_t const * desc,
5 : void const * msg,
6 : uchar * out,
7 0 : ulong * out_sz ) {
8 0 : fd_pb_encoder_t enc[1];
9 0 : fd_pb_encoder_init( enc, out, *out_sz );
10 0 : if( FD_UNLIKELY( !desc->encode( enc, msg ) ) ) return NULL;
11 0 : *out_sz = fd_pb_encoder_out_sz( enc );
12 0 : fd_pb_encoder_fini( enc );
13 0 : return out;
14 0 : }
15 :
16 : void *
17 : fd_pb_decode( fd_pb_msgdesc_t const * desc,
18 : void * msg,
19 : void const * in,
20 : ulong in_sz,
21 0 : fd_spad_t * spad ) {
22 0 : fd_pb_inbuf_t buf[1];
23 0 : fd_pb_inbuf_init( buf, in, in_sz );
24 0 : if( FD_UNLIKELY( !desc->decode( buf, msg, spad ) ) ) return NULL;
25 0 : return msg;
26 0 : }
27 :
28 : /* Scalar decoding */
29 :
30 : static int
31 : dec_varint( fd_pb_tlv_t const * tlv,
32 0 : ulong * out ) {
33 0 : if( FD_UNLIKELY( tlv->wire_type!=FD_PB_WIRE_TYPE_VARINT ) ) return 0;
34 0 : *out = tlv->varint;
35 0 : return 1;
36 0 : }
37 :
38 : int
39 0 : fd_pb_dec_bool( fd_pb_tlv_t const * tlv, bool * out ) {
40 0 : ulong v;
41 0 : if( FD_UNLIKELY( !dec_varint( tlv, &v ) ) ) return 0;
42 0 : *out = v!=0UL;
43 0 : return 1;
44 0 : }
45 :
46 : int
47 0 : fd_pb_dec_int32( fd_pb_tlv_t const * tlv, int * out ) {
48 0 : ulong v;
49 0 : if( FD_UNLIKELY( !dec_varint( tlv, &v ) ) ) return 0;
50 0 : *out = (int)(uint)v;
51 0 : return 1;
52 0 : }
53 :
54 : int
55 0 : fd_pb_dec_uint32( fd_pb_tlv_t const * tlv, uint * out ) {
56 0 : ulong v;
57 0 : if( FD_UNLIKELY( !dec_varint( tlv, &v ) ) ) return 0;
58 0 : if( FD_UNLIKELY( v>UINT_MAX ) ) return 0;
59 0 : *out = (uint)v;
60 0 : return 1;
61 0 : }
62 :
63 : int
64 0 : fd_pb_dec_sint32( fd_pb_tlv_t const * tlv, int * out ) {
65 0 : ulong v;
66 0 : if( FD_UNLIKELY( !dec_varint( tlv, &v ) ) ) return 0;
67 0 : long s = fd_long_zz_dec( v );
68 0 : if( FD_UNLIKELY( s<INT_MIN || s>INT_MAX ) ) return 0;
69 0 : *out = (int)s;
70 0 : return 1;
71 0 : }
72 :
73 : int
74 0 : fd_pb_dec_int64( fd_pb_tlv_t const * tlv, long * out ) {
75 0 : ulong v;
76 0 : if( FD_UNLIKELY( !dec_varint( tlv, &v ) ) ) return 0;
77 0 : *out = (long)v;
78 0 : return 1;
79 0 : }
80 :
81 : int
82 0 : fd_pb_dec_uint64( fd_pb_tlv_t const * tlv, ulong * out ) {
83 0 : return dec_varint( tlv, out );
84 0 : }
85 :
86 : int
87 0 : fd_pb_dec_sint64( fd_pb_tlv_t const * tlv, long * out ) {
88 0 : ulong v;
89 0 : if( FD_UNLIKELY( !dec_varint( tlv, &v ) ) ) return 0;
90 0 : *out = fd_long_zz_dec( v );
91 0 : return 1;
92 0 : }
93 :
94 : int
95 0 : fd_pb_dec_fixed32( fd_pb_tlv_t const * tlv, uint * out ) {
96 0 : if( FD_UNLIKELY( tlv->wire_type!=FD_PB_WIRE_TYPE_I32 ) ) return 0;
97 0 : *out = tlv->i32;
98 0 : return 1;
99 0 : }
100 :
101 : int
102 0 : fd_pb_dec_fixed64( fd_pb_tlv_t const * tlv, ulong * out ) {
103 0 : if( FD_UNLIKELY( tlv->wire_type!=FD_PB_WIRE_TYPE_I64 ) ) return 0;
104 0 : *out = tlv->i64;
105 0 : return 1;
106 0 : }
107 :
108 : int
109 0 : fd_pb_dec_float( fd_pb_tlv_t const * tlv, float * out ) {
110 0 : union { uint u; float f; } cast;
111 0 : if( FD_UNLIKELY( !fd_pb_dec_fixed32( tlv, &cast.u ) ) ) return 0;
112 0 : *out = cast.f;
113 0 : return 1;
114 0 : }
115 :
116 : int
117 0 : fd_pb_dec_double( fd_pb_tlv_t const * tlv, double * out ) {
118 0 : union { ulong u; double d; } cast;
119 0 : if( FD_UNLIKELY( !fd_pb_dec_fixed64( tlv, &cast.u ) ) ) return 0;
120 0 : *out = cast.d;
121 0 : return 1;
122 0 : }
123 :
124 : /* Repeated fields */
125 :
126 : void *
127 : fd_pb_dec_grow( fd_spad_t * spad,
128 : void * arr,
129 : uint * cnt,
130 : ulong ele_align,
131 0 : ulong ele_sz ) {
132 0 : uint n = *cnt;
133 0 : if( FD_UNLIKELY( n==UINT_MAX ) ) return NULL;
134 0 : void * base;
135 0 : fd_memcpy( &base, arr, sizeof(void *) );
136 : /* Capacity is the next power of two of n (geometric growth) */
137 0 : if( !n || fd_uint_is_pow2( n ) ) {
138 0 : ulong cap = n ? 2UL*n : 1UL;
139 0 : if( FD_UNLIKELY( fd_spad_alloc_max( spad, ele_align )<cap*ele_sz ) ) return NULL;
140 0 : void * p = fd_spad_alloc( spad, ele_align, cap*ele_sz );
141 0 : if( n ) fd_memcpy( p, base, n*ele_sz );
142 0 : base = p;
143 0 : fd_memcpy( arr, &base, sizeof(void *) );
144 0 : }
145 0 : uchar * ele = (uchar *)base + n*ele_sz;
146 0 : memset( ele, 0, ele_sz );
147 0 : *cnt = n+1U;
148 0 : return ele;
149 0 : }
150 :
151 : static ulong
152 0 : type_sz( int type ) {
153 0 : switch( type ) {
154 0 : case FD_PB_GEN_BOOL: return sizeof(bool);
155 0 : case FD_PB_GEN_INT32:
156 0 : case FD_PB_GEN_UINT32:
157 0 : case FD_PB_GEN_SINT32:
158 0 : case FD_PB_GEN_FIXED32: return 4UL;
159 0 : default: return 8UL;
160 0 : }
161 0 : }
162 :
163 : static int
164 : dec_scalar( fd_pb_tlv_t const * tlv,
165 : int type,
166 0 : void * out ) {
167 0 : switch( type ) {
168 0 : case FD_PB_GEN_BOOL: return fd_pb_dec_bool ( tlv, out );
169 0 : case FD_PB_GEN_INT32: return fd_pb_dec_int32 ( tlv, out );
170 0 : case FD_PB_GEN_UINT32: return fd_pb_dec_uint32 ( tlv, out );
171 0 : case FD_PB_GEN_SINT32: return fd_pb_dec_sint32 ( tlv, out );
172 0 : case FD_PB_GEN_INT64: return fd_pb_dec_int64 ( tlv, out );
173 0 : case FD_PB_GEN_UINT64: return fd_pb_dec_uint64 ( tlv, out );
174 0 : case FD_PB_GEN_SINT64: return fd_pb_dec_sint64 ( tlv, out );
175 0 : case FD_PB_GEN_FIXED32: return fd_pb_dec_fixed32( tlv, out );
176 0 : case FD_PB_GEN_FIXED64: return fd_pb_dec_fixed64( tlv, out );
177 0 : default: return 0;
178 0 : }
179 0 : }
180 :
181 : static uint
182 0 : type_wire( int type ) {
183 0 : switch( type ) {
184 0 : case FD_PB_GEN_FIXED32: return FD_PB_WIRE_TYPE_I32;
185 0 : case FD_PB_GEN_FIXED64: return FD_PB_WIRE_TYPE_I64;
186 0 : default: return FD_PB_WIRE_TYPE_VARINT;
187 0 : }
188 0 : }
189 :
190 : int
191 : fd_pb_dec_repeated( fd_pb_inbuf_t * in,
192 : fd_pb_tlv_t const * tlv,
193 : fd_spad_t * spad,
194 : int type,
195 : void * arr,
196 0 : uint * cnt ) {
197 0 : ulong ele_sz = type_sz( type );
198 0 : if( tlv->wire_type!=FD_PB_WIRE_TYPE_LEN ) {
199 0 : void * ele = fd_pb_dec_grow( spad, arr, cnt, ele_sz, ele_sz );
200 0 : if( FD_UNLIKELY( !ele ) ) return 0;
201 0 : return dec_scalar( tlv, type, ele );
202 0 : }
203 :
204 : /* Packed */
205 0 : fd_pb_inbuf_t sub[1];
206 0 : if( FD_UNLIKELY( !fd_pb_tlv_submsg( in, tlv, sub ) ) ) return 0;
207 0 : in->cur = sub->end;
208 0 : fd_pb_tlv_t vtlv[1] = {{ .wire_type = type_wire( type ), .field_id = tlv->field_id }};
209 0 : while( fd_pb_inbuf_sz( sub ) ) {
210 0 : switch( vtlv->wire_type ) {
211 0 : case FD_PB_WIRE_TYPE_VARINT:
212 0 : if( FD_UNLIKELY( !fd_pb_read_varint( sub, &vtlv->varint ) ) ) return 0;
213 0 : break;
214 0 : case FD_PB_WIRE_TYPE_I32:
215 0 : if( FD_UNLIKELY( fd_pb_inbuf_sz( sub )<4UL ) ) return 0;
216 0 : vtlv->varint = 0UL;
217 0 : vtlv->i32 = FD_LOAD( uint, sub->cur );
218 0 : sub->cur += 4UL;
219 0 : break;
220 0 : case FD_PB_WIRE_TYPE_I64:
221 0 : if( FD_UNLIKELY( fd_pb_inbuf_sz( sub )<8UL ) ) return 0;
222 0 : vtlv->i64 = FD_LOAD( ulong, sub->cur );
223 0 : sub->cur += 8UL;
224 0 : break;
225 0 : }
226 0 : void * ele = fd_pb_dec_grow( spad, arr, cnt, ele_sz, ele_sz );
227 0 : if( FD_UNLIKELY( !ele ) ) return 0;
228 0 : if( FD_UNLIKELY( !dec_scalar( vtlv, type, ele ) ) ) return 0;
229 0 : }
230 0 : return 1;
231 0 : }
232 :
233 : /* Length-delimited fields */
234 :
235 : int
236 : fd_pb_dec_submsg( fd_pb_inbuf_t * in,
237 : fd_pb_tlv_t const * tlv,
238 : fd_spad_t * spad,
239 : fd_pb_msgdesc_t const * desc,
240 0 : void * msg ) {
241 0 : fd_pb_inbuf_t sub[1];
242 0 : if( FD_UNLIKELY( !fd_pb_tlv_submsg( in, tlv, sub ) ) ) return 0;
243 0 : in->cur = sub->end;
244 0 : return desc->decode( sub, msg, spad );
245 0 : }
246 :
247 : int
248 : fd_pb_dec_bytes_ptr( fd_pb_inbuf_t * in,
249 : fd_pb_tlv_t const * tlv,
250 : fd_spad_t * spad,
251 0 : fd_pb_bytes_array_t ** out ) {
252 0 : uchar const * data = fd_pb_tlv_bytes( in, tlv );
253 0 : if( FD_UNLIKELY( !data || tlv->len>UINT_MAX ) ) return 0;
254 0 : ulong sz = FD_PB_BYTES_ARRAY_T_ALLOCSIZE( tlv->len );
255 0 : if( FD_UNLIKELY( fd_spad_alloc_max( spad, alignof(fd_pb_bytes_array_t) )<sz ) ) return 0;
256 0 : fd_pb_bytes_array_t * arr = fd_spad_alloc( spad, alignof(fd_pb_bytes_array_t), sz );
257 0 : arr->size = (uint)tlv->len;
258 0 : fd_memcpy( arr->bytes, data, tlv->len );
259 0 : *out = arr;
260 0 : in->cur += tlv->len;
261 0 : return 1;
262 0 : }
263 :
264 : int
265 : fd_pb_dec_bytes_fixed( fd_pb_inbuf_t * in,
266 : fd_pb_tlv_t const * tlv,
267 : uchar * out,
268 0 : ulong sz ) {
269 0 : uchar const * data = fd_pb_tlv_bytes( in, tlv );
270 0 : if( FD_UNLIKELY( !data ) ) return 0;
271 0 : if( !tlv->len ) {
272 : /* Empty bytes decode as all zeros */
273 0 : memset( out, 0, sz );
274 0 : return 1;
275 0 : }
276 0 : if( FD_UNLIKELY( tlv->len!=sz ) ) return 0;
277 0 : fd_memcpy( out, data, sz );
278 0 : in->cur += sz;
279 0 : return 1;
280 0 : }
281 :
282 : int
283 : fd_pb_dec_bytes_static( fd_pb_inbuf_t * in,
284 : fd_pb_tlv_t const * tlv,
285 : uchar * out,
286 : uint * out_sz,
287 0 : ulong max ) {
288 0 : uchar const * data = fd_pb_tlv_bytes( in, tlv );
289 0 : if( FD_UNLIKELY( !data || tlv->len>max ) ) return 0;
290 0 : fd_memcpy( out, data, tlv->len );
291 0 : *out_sz = (uint)tlv->len;
292 0 : in->cur += tlv->len;
293 0 : return 1;
294 0 : }
295 :
296 : int
297 : fd_pb_dec_string_static( fd_pb_inbuf_t * in,
298 : fd_pb_tlv_t const * tlv,
299 : char * out,
300 0 : ulong max ) {
301 0 : if( FD_UNLIKELY( !fd_pb_tlv_cstr( in, tlv, out, max ) ) ) return 0;
302 0 : in->cur += tlv->len;
303 0 : return 1;
304 0 : }
305 :
306 : /* Encoding */
307 :
308 : /* lp_close_compact closes a LEN field opened with fd_pb_lp_open and
309 : rewrites the length prefix in its shortest form. */
310 :
311 : static int
312 0 : lp_close_compact( fd_pb_encoder_t * enc ) {
313 0 : uchar * lp = enc->buf0 + enc->lp_off[ enc->depth-1U ];
314 0 : uchar * sub0 = lp + fd_pb_varint32_sz_max;
315 0 : ulong sz = (ulong)( enc->cur - sub0 );
316 0 : if( FD_UNLIKELY( sz>UINT_MAX ) ) return 0;
317 0 : fd_pb_lp_close( enc );
318 0 : uchar tmp[ 8 ];
319 0 : ulong lp_sz = (ulong)( fd_pb_append_varint32( tmp, (uint)sz ) - tmp );
320 0 : fd_memcpy( lp, tmp, lp_sz );
321 0 : memmove( lp+lp_sz, sub0, sz );
322 0 : enc->cur = lp + lp_sz + sz;
323 0 : return 1;
324 0 : }
325 :
326 : int
327 : fd_pb_enc_submsg( fd_pb_encoder_t * enc,
328 : uint field_id,
329 : fd_pb_msgdesc_t const * desc,
330 0 : void const * msg ) {
331 0 : if( FD_UNLIKELY( !fd_pb_submsg_open( enc, field_id ) ) ) return 0;
332 0 : if( FD_UNLIKELY( !desc->encode( enc, msg ) ) ) return 0;
333 0 : return lp_close_compact( enc );
334 0 : }
335 :
336 : int
337 : fd_pb_enc_bytes_ptr( fd_pb_encoder_t * enc,
338 : uint field_id,
339 0 : fd_pb_bytes_array_t const * bytes ) {
340 0 : static uchar const empty[1];
341 0 : if( !bytes ) return !!fd_pb_push_bytes( enc, field_id, empty, 0UL );
342 0 : return !!fd_pb_push_bytes( enc, field_id, bytes->bytes, bytes->size );
343 0 : }
344 :
345 : int
346 : fd_pb_enc_packed( fd_pb_encoder_t * enc,
347 : uint field_id,
348 : int type,
349 : void const * arr,
350 0 : ulong cnt ) {
351 0 : if( !cnt ) return 1;
352 0 : if( FD_UNLIKELY( !fd_pb_lp_open( enc, field_id ) ) ) return 0;
353 0 : for( ulong i=0UL; i<cnt; i++ ) {
354 0 : if( FD_UNLIKELY( fd_pb_encoder_space( enc )<fd_pb_varint64_sz_max ) ) return 0;
355 0 : switch( type ) {
356 0 : case FD_PB_GEN_BOOL: enc->cur = fd_pb_append_bool ( enc->cur, ((bool const *)arr)[i] ); break;
357 0 : case FD_PB_GEN_INT32: enc->cur = fd_pb_append_int64 ( enc->cur, (long)((int const *)arr)[i] ); break;
358 0 : case FD_PB_GEN_UINT32: enc->cur = fd_pb_append_uint32 ( enc->cur, ((uint const *)arr)[i] ); break;
359 0 : case FD_PB_GEN_SINT32: enc->cur = fd_pb_append_sint32 ( enc->cur, ((int const *)arr)[i] ); break;
360 0 : case FD_PB_GEN_INT64: enc->cur = fd_pb_append_int64 ( enc->cur, ((long const *)arr)[i] ); break;
361 0 : case FD_PB_GEN_UINT64: enc->cur = fd_pb_append_uint64 ( enc->cur, ((ulong const *)arr)[i] ); break;
362 0 : case FD_PB_GEN_SINT64: enc->cur = fd_pb_append_sint64 ( enc->cur, ((long const *)arr)[i] ); break;
363 0 : case FD_PB_GEN_FIXED32: enc->cur = fd_pb_append_fixed32( enc->cur, FD_LOAD( uint, (uchar const *)arr+4UL*i ) ); break;
364 0 : case FD_PB_GEN_FIXED64: enc->cur = fd_pb_append_fixed64( enc->cur, FD_LOAD( ulong, (uchar const *)arr+8UL*i ) ); break;
365 0 : default: return 0;
366 0 : }
367 0 : }
368 0 : return lp_close_compact( enc );
369 0 : }
|