Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_types_fd_bincode_h
2 : #define HEADER_fd_src_flamenco_types_fd_bincode_h
3 :
4 : #include "../../util/fd_util.h"
5 :
6 : /* Context argument used for encoding */
7 : struct fd_bincode_encode_ctx {
8 : /* Current position in data buffer */
9 : void * data;
10 : /* End of buffer */
11 : void * dataend;
12 : };
13 : typedef struct fd_bincode_encode_ctx fd_bincode_encode_ctx_t;
14 :
15 : /* Context argument used for decoding */
16 : struct fd_bincode_decode_ctx {
17 : /* Current position in data buffer */
18 : void const * data;
19 : /* End of buffer */
20 : void const * dataend;
21 : };
22 : typedef struct fd_bincode_decode_ctx fd_bincode_decode_ctx_t;
23 :
24 53889 : #define FD_BINCODE_SUCCESS ( 0)
25 0 : #define FD_BINCODE_ERR_UNDERFLOW (-1001) /* Attempted to read past end of buffer */
26 6 : #define FD_BINCODE_ERR_OVERFLOW (-1002) /* Attempted to write past end of buffer */
27 0 : #define FD_BINCODE_ERR_ENCODING (-1003) /* Invalid encoding */
28 :
29 : #define FD_BINCODE_PRIMITIVE_STUBS( name, type ) \
30 : static inline int \
31 : fd_bincode_##name##_decode( type * self, \
32 504 : fd_bincode_decode_ctx_t * ctx ) { \
33 504 : uchar const * ptr = (uchar const *) ctx->data; \
34 504 : if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
35 504 : return FD_BINCODE_ERR_UNDERFLOW; \
36 504 : memcpy( self, ptr, sizeof(type) ); /* unaligned */ \
37 504 : ctx->data = ptr + sizeof(type); \
38 504 : return FD_BINCODE_SUCCESS; \
39 504 : } \
40 : static inline int \
41 49206 : fd_bincode_##name##_decode_footprint( fd_bincode_decode_ctx_t * ctx ) { \
42 49206 : uchar const * ptr = (uchar const *) ctx->data; \
43 49206 : if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
44 49206 : return FD_BINCODE_ERR_UNDERFLOW; \
45 49206 : ctx->data = ptr + sizeof(type); \
46 49206 : return FD_BINCODE_SUCCESS; \
47 49206 : } \
48 : static inline void \
49 : fd_bincode_##name##_decode_unsafe( type * self, \
50 34551 : fd_bincode_decode_ctx_t * ctx ) { \
51 34551 : uchar const * ptr = (uchar const *) ctx->data; \
52 34551 : memcpy( self, ptr, sizeof(type) ); /* unaligned */ \
53 34551 : ctx->data = ptr + sizeof(type); \
54 34551 : } \
55 : static inline int \
56 : fd_bincode_##name##_encode( type self, \
57 1752 : fd_bincode_encode_ctx_t * ctx ) { \
58 1752 : uchar * ptr = (uchar *)ctx->data; \
59 1752 : if ( FD_UNLIKELY((void *)(ptr + sizeof(type)) > ctx->dataend ) ) \
60 1752 : return FD_BINCODE_ERR_OVERFLOW; \
61 1752 : memcpy( ptr, &self, sizeof(type) ); /* unaligned */ \
62 1749 : ctx->data = ptr + sizeof(type); \
63 1749 : return FD_BINCODE_SUCCESS; \
64 1752 : }
65 :
66 : /* fd_w_u128 is a wrapped "uint128" type providing basic 128-bit
67 : unsigned int functionality to fd_types, even if the compile target
68 : does not natively support uint128. */
69 :
70 : union __attribute__((aligned(16))) fd_w_u128 {
71 : uchar uc[16];
72 : ulong ul[2];
73 : # if FD_HAS_INT128
74 : uint128 ud;
75 : # endif
76 : };
77 :
78 : typedef union fd_w_u128 fd_w_u128_t;
79 :
80 : FD_BINCODE_PRIMITIVE_STUBS( uint8, uchar )
81 : FD_BINCODE_PRIMITIVE_STUBS( uint16, ushort )
82 : FD_BINCODE_PRIMITIVE_STUBS( uint32, uint )
83 : FD_BINCODE_PRIMITIVE_STUBS( uint64, ulong )
84 : FD_BINCODE_PRIMITIVE_STUBS( int64, long )
85 : FD_BINCODE_PRIMITIVE_STUBS( uint128, fd_w_u128_t )
86 : FD_BINCODE_PRIMITIVE_STUBS( double, double )
87 :
88 : static inline int
89 : fd_bincode_bool_decode( uchar * self,
90 3 : fd_bincode_decode_ctx_t * ctx ) {
91 :
92 3 : uchar const * ptr = (uchar const *)ctx->data;
93 3 : if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
94 0 : return FD_BINCODE_ERR_UNDERFLOW;
95 :
96 3 : if( FD_UNLIKELY( *ptr & (~1U) ) )
97 0 : return FD_BINCODE_ERR_ENCODING;
98 :
99 3 : *self = *ptr;
100 3 : ctx->data = ptr + 1;
101 :
102 3 : return FD_BINCODE_SUCCESS;
103 3 : }
104 :
105 : static inline int
106 6 : fd_bincode_bool_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
107 :
108 6 : uchar const * ptr = (uchar const *)ctx->data;
109 6 : if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
110 0 : return FD_BINCODE_ERR_UNDERFLOW;
111 :
112 6 : if( FD_UNLIKELY( *ptr & (~1U) ) )
113 0 : return FD_BINCODE_ERR_ENCODING;
114 :
115 6 : ctx->data = ptr + 1;
116 :
117 6 : return FD_BINCODE_SUCCESS;
118 6 : }
119 :
120 : static inline void
121 : fd_bincode_bool_decode_unsafe( uchar * self,
122 0 : fd_bincode_decode_ctx_t * ctx ) {
123 0 : fd_bincode_uint8_decode_unsafe( self, ctx );
124 0 : }
125 :
126 : static inline int
127 : fd_bincode_bool_encode( uchar self,
128 195 : fd_bincode_encode_ctx_t * ctx ) {
129 :
130 195 : uchar * ptr = (uchar *)ctx->data;
131 195 : if ( FD_UNLIKELY( (void *)(ptr + 1) > ctx->dataend ) )
132 0 : return FD_BINCODE_ERR_OVERFLOW;
133 :
134 195 : *ptr = !!self;
135 195 : ctx->data = ptr + 1;
136 :
137 195 : return FD_BINCODE_SUCCESS;
138 195 : }
139 :
140 : static inline int
141 : fd_bincode_bytes_decode( uchar * self,
142 : ulong len,
143 0 : fd_bincode_decode_ctx_t * ctx ) {
144 0 : uchar * ptr = (uchar *) ctx->data;
145 0 : if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) // Get wrap-around case right
146 0 : return FD_BINCODE_ERR_UNDERFLOW;
147 0 :
148 0 : fd_memcpy(self, ptr, len);
149 0 : ctx->data = ptr + len;
150 0 :
151 0 : return FD_BINCODE_SUCCESS;
152 0 : }
153 :
154 : static inline int
155 : fd_bincode_bytes_decode_footprint( ulong len,
156 462 : fd_bincode_decode_ctx_t * ctx ) {
157 462 : uchar * ptr = (uchar *) ctx->data;
158 462 : if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) { // Get wrap-around case right
159 0 : return FD_BINCODE_ERR_UNDERFLOW;
160 0 : }
161 :
162 462 : ctx->data = ptr + len;
163 :
164 462 : return FD_BINCODE_SUCCESS;
165 462 : }
166 :
167 : static inline void
168 : fd_bincode_bytes_decode_unsafe( uchar * self,
169 : ulong len,
170 33975 : fd_bincode_decode_ctx_t * ctx ) {
171 33975 : uchar * ptr = (uchar *) ctx->data;
172 33975 : fd_memcpy(self, ptr, len);
173 33975 : ctx->data = ptr + len;
174 33975 : }
175 :
176 : static inline int
177 : fd_bincode_bytes_encode( uchar const * self,
178 : ulong len,
179 786 : fd_bincode_encode_ctx_t * ctx ) {
180 786 : fd_msan_check( self, len );
181 :
182 786 : uchar * ptr = (uchar *)ctx->data;
183 786 : if( FD_UNLIKELY( (void *)( ptr+len ) > ctx->dataend ) )
184 0 : return FD_BINCODE_ERR_OVERFLOW;
185 :
186 786 : fd_memcpy( ptr, self, len );
187 786 : ctx->data = ptr + len;
188 :
189 786 : return FD_BINCODE_SUCCESS;
190 786 : }
191 :
192 : /* Alternate versions of fd_cu16_dec to make the function signature more consistent with the
193 : other fd_bincode_decode functions. */
194 : static inline int
195 : fd_bincode_compact_u16_decode( ushort * self,
196 0 : fd_bincode_decode_ctx_t * ctx ) {
197 0 : const uchar * ptr = (const uchar*) ctx->data;
198 0 : if( FD_UNLIKELY( ptr==NULL ) ) {
199 0 : return FD_BINCODE_ERR_UNDERFLOW;
200 0 : }
201 :
202 0 : if( FD_LIKELY( (void *) (ptr + 1) <= ctx->dataend && !(0x80U & ptr[0]) ) ) {
203 0 : *self = (ushort)ptr[0];
204 0 : ctx->data = ptr + 1;
205 0 : return FD_BINCODE_SUCCESS;
206 0 : }
207 :
208 0 : if( FD_LIKELY( (void *) (ptr + 2) <= ctx->dataend && !(0x80U & ptr[1]) ) ) {
209 0 : if( FD_UNLIKELY( !ptr[1] ) ) /* Detect non-minimal encoding */
210 0 : return FD_BINCODE_ERR_ENCODING;
211 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
212 0 : ctx->data = ptr + 2;
213 0 : return FD_BINCODE_SUCCESS;
214 0 : }
215 :
216 0 : if( FD_LIKELY( (void *) (ptr + 3) <= ctx->dataend && !(0xFCU & ptr[2]) ) ) {
217 0 : if( FD_UNLIKELY( !ptr[2] ) ) /* Detect non-minimal encoding */
218 0 : return FD_BINCODE_ERR_ENCODING;
219 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
220 0 : ctx->data = ptr + 3;
221 0 : return FD_BINCODE_SUCCESS;
222 0 : }
223 :
224 0 : return FD_BINCODE_ERR_UNDERFLOW;
225 0 : }
226 :
227 : static inline void
228 : fd_bincode_compact_u16_decode_unsafe( ushort * self,
229 0 : fd_bincode_decode_ctx_t * ctx ) {
230 0 : const uchar * ptr = (const uchar*) ctx->data;
231 :
232 0 : if( !(0x80U & ptr[0]) ) {
233 0 : *self = (ushort)ptr[0];
234 0 : ctx->data = ptr + 1;
235 0 : return;
236 0 : }
237 :
238 0 : if( !(0x80U & ptr[1]) ) {
239 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
240 0 : ctx->data = ptr + 2;
241 0 : return;
242 0 : }
243 :
244 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
245 0 : ctx->data = ptr + 3;
246 0 : }
247 :
248 : static inline int
249 : fd_bincode_compact_u16_encode( ushort const * self,
250 12 : fd_bincode_encode_ctx_t * ctx ) {
251 12 : uchar * ptr = (uchar*) ctx->data;
252 12 : ulong val = *self;
253 :
254 12 : if ( val < 0x80UL ) {
255 12 : if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
256 0 : return FD_BINCODE_ERR_OVERFLOW;
257 12 : *ptr = (uchar)val;
258 12 : ctx->data = ptr + 1;
259 12 : return FD_BINCODE_SUCCESS;
260 12 : }
261 :
262 0 : else if ( val < 0x4000UL ) {
263 0 : if ( FD_UNLIKELY((void *) (ptr + 2) > ctx->dataend ) )
264 0 : return FD_BINCODE_ERR_OVERFLOW;
265 0 : ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
266 0 : ptr[1] = (uchar)(val>>7);
267 0 : ctx->data = ptr + 2;
268 0 : return FD_BINCODE_SUCCESS;
269 0 : }
270 :
271 0 : else {
272 0 : if ( FD_UNLIKELY((void *) (ptr + 3) > ctx->dataend ) )
273 0 : return FD_BINCODE_ERR_OVERFLOW;
274 0 : ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
275 0 : ptr[1] = (uchar)(((val>>7)&0x7FUL)|0x80UL);
276 0 : ptr[2] = (uchar)(val>>14);
277 0 : ctx->data = ptr + 3;
278 0 : return FD_BINCODE_SUCCESS;
279 0 : }
280 12 : }
281 :
282 : static inline ulong
283 0 : fd_bincode_compact_u16_size( ushort const * self ) {
284 0 : ulong val = *self;
285 :
286 0 : if ( val < 0x80UL ) {
287 0 : return 1;
288 0 : }
289 0 : else if ( val < 0x4000UL ) {
290 0 : return 2;
291 0 : }
292 0 : else {
293 0 : return 3;
294 0 : }
295 0 : }
296 :
297 : /* Decodes an integer encoded using the serde_varint algorithm:
298 : https://github.com/solana-labs/solana/blob/master/sdk/program/src/serde_varint.rs
299 :
300 : A variable number of bytes could have been used to encode the integer.
301 : The most significant bit of each byte indicates if more bytes have been used, so we keep consuming until
302 : we reach a byte where the most significant bit is 0.
303 : */
304 : static inline int
305 : fd_bincode_varint_decode( ulong * self,
306 0 : fd_bincode_decode_ctx_t * ctx ) {
307 0 : ulong out = 0UL;
308 0 : uint shift = 0U;
309 0 :
310 0 : while( FD_LIKELY( shift < 64U ) ) {
311 0 :
312 0 : if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
313 0 : return FD_BINCODE_ERR_UNDERFLOW;
314 0 :
315 0 : uint byte = *(uchar const *)ctx->data;
316 0 : ctx->data = (uchar const *)ctx->data + 1;
317 0 : out |= (byte & 0x7FUL) << shift;
318 0 :
319 0 : if( (byte & 0x80U) == 0U ) {
320 0 : if( (out>>shift) != byte )
321 0 : return FD_BINCODE_ERR_ENCODING;
322 0 : if( byte==0U && (shift!=0U || out!=0UL) )
323 0 : return FD_BINCODE_ERR_ENCODING;
324 0 : *self = out;
325 0 : return FD_BINCODE_SUCCESS;
326 0 : }
327 0 :
328 0 : shift += 7U;
329 0 :
330 0 : }
331 0 :
332 0 : return FD_BINCODE_ERR_ENCODING;
333 0 : }
334 :
335 : static inline int
336 0 : fd_bincode_varint_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
337 0 : ulong out = 0UL;
338 0 : uint shift = 0U;
339 :
340 0 : while( FD_LIKELY( shift < 64U ) ) {
341 :
342 0 : if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
343 0 : return FD_BINCODE_ERR_UNDERFLOW;
344 :
345 0 : uint byte = *(uchar const *)ctx->data;
346 0 : ctx->data = (uchar const *)ctx->data + 1;
347 0 : out |= (byte & 0x7FUL) << shift;
348 :
349 0 : if( (byte & 0x80U) == 0U ) {
350 0 : if( (out>>shift) != byte )
351 0 : return FD_BINCODE_ERR_ENCODING;
352 0 : if( byte==0U && (shift!=0U || out!=0UL) )
353 0 : return FD_BINCODE_ERR_ENCODING;
354 0 : return FD_BINCODE_SUCCESS;
355 0 : }
356 :
357 0 : shift += 7U;
358 :
359 0 : }
360 :
361 0 : return FD_BINCODE_ERR_ENCODING;
362 0 : }
363 :
364 : static inline void
365 : fd_bincode_varint_decode_unsafe( ulong * self,
366 0 : fd_bincode_decode_ctx_t * ctx ) {
367 0 : ulong out = 0UL;
368 0 : uint shift = 0U;
369 :
370 0 : for(;;) {
371 0 : uint byte = *(uchar const *)ctx->data;
372 0 : ctx->data = (uchar const *)ctx->data + 1;
373 0 : out |= (byte & 0x7FUL) << shift;
374 :
375 0 : if( (byte & 0x80U) == 0U ) {
376 0 : *self = out;
377 0 : return;
378 0 : }
379 :
380 0 : shift += 7U;
381 0 : }
382 0 : }
383 :
384 : static inline int
385 : fd_bincode_varint_encode( ulong val,
386 0 : fd_bincode_encode_ctx_t * ctx ) {
387 0 : uchar * ptr = (uchar *) ctx->data;
388 0 : while (1) {
389 0 : if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
390 0 : return FD_BINCODE_ERR_OVERFLOW;
391 0 : if ( val < 0x80UL ) {
392 0 : *(ptr++) = (uchar)val;
393 0 : ctx->data = ptr;
394 0 : return FD_BINCODE_SUCCESS;
395 0 : }
396 0 : *(ptr++) = (uchar)((val&0x7FUL)|0x80UL);
397 0 : val >>= 7;
398 0 : }
399 0 : }
400 :
401 : static inline ulong
402 0 : fd_bincode_varint_size( ulong val ) {
403 0 : ulong sz = 0;
404 0 : while (1) {
405 0 : if ( val < 0x80UL ) {
406 0 : return sz+1;
407 0 : }
408 0 : sz++;
409 0 : val >>= 7;
410 0 : }
411 0 : }
412 :
413 : /* Convenience API for deserializing with common allocators */
414 :
415 : /* fd_bincode_decode_spad decodes a bincode type. The result is
416 : allocated into a spad on success. On failure, no spad allocations
417 : are made.
418 :
419 : fd_bincode_decode1_spad optionally outputs the number of bytes read
420 : to *psz. */
421 :
422 : #define fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, psz ) \
423 0 : __extension__({ \
424 0 : fd_spad_t * const spad_ = (spad); \
425 0 : void const * const buf_ = (buf); \
426 0 : ulong const buf_sz_ = (buf_sz); \
427 0 : int * perr_ = (perr); \
428 0 : ulong * psz_ = (psz); \
429 0 : fd_bincode_decode_ctx_t ctx = {0}; \
430 0 : if( perr_ ) *perr_ = -1; \
431 0 : ctx.data = (void const *)( buf_ ); \
432 0 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
433 0 : ulong total_sz = 0UL; \
434 0 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
435 0 : fd_##type##_t * out = NULL; \
436 0 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
437 0 : ulong align = fd_##type##_align(); \
438 0 : void * mem = fd_spad_alloc( spad_, align, total_sz ); \
439 0 : if( FD_UNLIKELY( !mem ) ) { \
440 0 : FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in spad)", align-1UL, total_sz, fd_spad_mem_free( spad_ ) )); \
441 0 : } \
442 0 : out = fd_##type##_decode( mem, &ctx ); \
443 0 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
444 0 : } \
445 0 : if( perr_ ) *perr_ = err; \
446 0 : out; \
447 0 : })
448 :
449 : #define fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, psz ) \
450 : __extension__({ \
451 : fd_spad_t * const spad_ = (spad); \
452 : void const * const buf_ = (buf); \
453 : ulong const buf_sz_ = (buf_sz); \
454 : int * perr_ = (perr); \
455 : ulong * psz_ = (psz); \
456 : fd_bincode_decode_ctx_t ctx = {0}; \
457 : if( perr_ ) *perr_ = -1; \
458 : ctx.data = (void const *)( buf_ ); \
459 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
460 : ulong total_sz = 0UL; \
461 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
462 : fd_##type##_global_t * out = NULL; \
463 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
464 : ulong align = fd_##type##_align(); \
465 : void * mem = fd_spad_alloc( spad_, align, total_sz ); \
466 : if( FD_UNLIKELY( !mem ) ) { \
467 : FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in spad)", align-1UL, total_sz, fd_spad_mem_free( spad_ ) )); \
468 : } \
469 : out = fd_##type##_decode_global( mem, &ctx ); \
470 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
471 : } \
472 : if( perr_ ) *perr_ = err; \
473 : out; \
474 : })
475 :
476 : #define fd_bincode_decode_spad( type, spad, buf, buf_sz, perr ) \
477 0 : fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, NULL )
478 :
479 : #define fd_bincode_decode_spad_global( type, spad, buf, buf_sz, perr ) \
480 : fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, NULL )
481 :
482 : /* fd_bincode_decode_scratch decodes a bincode type. The result is
483 : allocated into the thread's scratch region on success. On failure,
484 : no allocations are made. */
485 :
486 : #define fd_bincode_decode1_scratch( type, buf, buf_sz, perr, psz ) \
487 : __extension__({ \
488 : void const * const buf_ = (buf); \
489 : ulong const buf_sz_ = (buf_sz); \
490 : int * perr_ = (perr); \
491 : ulong * psz_ = (psz); \
492 : fd_bincode_decode_ctx_t ctx = {0}; \
493 : if( perr_ ) *perr_ = -1; \
494 : ctx.data = (void const *)( buf_ ); \
495 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
496 : ulong total_sz = 0UL; \
497 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
498 : fd_##type##_t * out = NULL; \
499 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
500 : ulong align = fd_##type##_align(); \
501 : if( FD_UNLIKELY( !fd_scratch_alloc_is_safe( align, total_sz ) ) ) { \
502 : FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in scratch region)", align-1UL, total_sz, fd_scratch_free() )); \
503 : } \
504 : void * mem = fd_scratch_alloc( align, total_sz ); \
505 : out = fd_##type##_decode( mem, &ctx ); \
506 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
507 : } \
508 : if( perr_ ) *perr_ = err; \
509 : out; \
510 : })
511 :
512 : #define fd_bincode_decode_scratch( type, buf, buf_sz, perr ) \
513 : fd_bincode_decode1_scratch( type, buf, buf_sz, perr, NULL )
514 :
515 : /* fd_bincode_decode_static decodes a statically-sized bincode type.
516 :
517 : Example usage:
518 :
519 : fd_epoch_schedule_t es[1]; int err;
520 : if( FD_UNLIKELY( fd_bincode_decode_static( epoch_schedule, es, buf, bufsz, &err ) ) ) {
521 : ... parse fail ...
522 : return;
523 : }
524 : ... parse success ... */
525 :
526 : #define fd_bincode_decode_static1( type, suffix, out, buf, buf_sz, perr ) \
527 30 : __extension__({ \
528 30 : void const * const buf_ = (buf); \
529 48 : ulong const buf_sz_ = (buf_sz); \
530 30 : int * perr_ = (perr); \
531 30 : fd_##type##suffix##_t * res = NULL; \
532 30 : fd_bincode_decode_ctx_t ctx = {0}; \
533 30 : ctx.data = (void const *)( buf_ ); \
534 30 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
535 30 : ulong total_sz = 0UL; \
536 30 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
537 30 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
538 30 : res = fd_##type##_decode##suffix( (out), &ctx ); \
539 30 : } \
540 30 : if( perr_ ) *perr_ = err; \
541 30 : res; \
542 30 : })
543 :
544 : #define fd_bincode_decode_static( t,o,b,s,p ) \
545 30 : fd_bincode_decode_static1( t, , o, b, s, p )
546 :
547 : #define fd_bincode_decode_static_global( t,o,b,s,p ) \
548 : fd_bincode_decode_static1( t, _global, o, b, s, p )
549 :
550 : #define fd_bincode_decode_static_limited_deserialize( type, out, buf, buf_sz, limit, perr ) \
551 24 : fd_bincode_decode_static( type, out, buf, buf_sz>limit ? limit : buf_sz, perr )
552 :
553 : #endif /* HEADER_fd_src_flamenco_types_fd_bincode_h */
|