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 : typedef void
7 : (* fd_types_walk_fn_t)( void * self,
8 : void const * arg,
9 : char const * name,
10 : int type,
11 : char const * type_name,
12 : uint level,
13 : uint varint );
14 :
15 : typedef void
16 : (* fd_types_walk_fn_t)( void * self,
17 : void const * arg,
18 : char const * name,
19 : int type,
20 : char const * type_name,
21 : uint level,
22 : uint varint );
23 :
24 : /* Context argument used for encoding */
25 : struct fd_bincode_encode_ctx {
26 : /* Current position in data buffer */
27 : void * data;
28 : /* End of buffer */
29 : void * dataend;
30 : };
31 : typedef struct fd_bincode_encode_ctx fd_bincode_encode_ctx_t;
32 :
33 : /* Context argument used for decoding */
34 : struct fd_bincode_decode_ctx {
35 : /* Current position in data buffer */
36 : void const * data;
37 : /* End of buffer */
38 : void const * dataend;
39 : };
40 : typedef struct fd_bincode_decode_ctx fd_bincode_decode_ctx_t;
41 :
42 56415 : #define FD_BINCODE_SUCCESS ( 0)
43 0 : #define FD_BINCODE_ERR_UNDERFLOW (-1001) /* Attempted to read past end of buffer */
44 6 : #define FD_BINCODE_ERR_OVERFLOW (-1002) /* Attempted to write past end of buffer */
45 0 : #define FD_BINCODE_ERR_ENCODING (-1003) /* Invalid encoding */
46 :
47 : #define FD_BINCODE_PRIMITIVE_STUBS( name, type ) \
48 : static inline int \
49 : fd_bincode_##name##_decode( type * self, \
50 561 : fd_bincode_decode_ctx_t * ctx ) { \
51 561 : uchar const * ptr = (uchar const *) ctx->data; \
52 561 : if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
53 561 : return FD_BINCODE_ERR_UNDERFLOW; \
54 561 : memcpy( self, ptr, sizeof(type) ); /* unaligned */ \
55 561 : ctx->data = ptr + sizeof(type); \
56 561 : return FD_BINCODE_SUCCESS; \
57 561 : } \
58 : static inline int \
59 49275 : fd_bincode_##name##_decode_footprint( fd_bincode_decode_ctx_t * ctx ) { \
60 49275 : uchar const * ptr = (uchar const *) ctx->data; \
61 49275 : if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
62 49275 : return FD_BINCODE_ERR_UNDERFLOW; \
63 49275 : ctx->data = ptr + sizeof(type); \
64 49275 : return FD_BINCODE_SUCCESS; \
65 49275 : } \
66 : static inline void \
67 : fd_bincode_##name##_decode_unsafe( type * self, \
68 37512 : fd_bincode_decode_ctx_t * ctx ) { \
69 37512 : uchar const * ptr = (uchar const *) ctx->data; \
70 37512 : memcpy( self, ptr, sizeof(type) ); /* unaligned */ \
71 37512 : ctx->data = ptr + sizeof(type); \
72 37512 : } \
73 : static inline int \
74 : fd_bincode_##name##_encode( type self, \
75 3129 : fd_bincode_encode_ctx_t * ctx ) { \
76 3129 : uchar * ptr = (uchar *)ctx->data; \
77 3129 : if ( FD_UNLIKELY((void *)(ptr + sizeof(type)) > ctx->dataend ) ) \
78 3129 : return FD_BINCODE_ERR_OVERFLOW; \
79 3129 : memcpy( ptr, &self, sizeof(type) ); /* unaligned */ \
80 3126 : ctx->data = ptr + sizeof(type); \
81 3126 : return FD_BINCODE_SUCCESS; \
82 3129 : }
83 :
84 : FD_BINCODE_PRIMITIVE_STUBS( uint8, uchar )
85 : FD_BINCODE_PRIMITIVE_STUBS( uint16, ushort )
86 : FD_BINCODE_PRIMITIVE_STUBS( uint32, uint )
87 : FD_BINCODE_PRIMITIVE_STUBS( uint64, ulong )
88 : FD_BINCODE_PRIMITIVE_STUBS( int64, long )
89 : #if FD_HAS_INT128
90 : FD_BINCODE_PRIMITIVE_STUBS( uint128, uint128 )
91 : #endif
92 : FD_BINCODE_PRIMITIVE_STUBS( double, double )
93 :
94 : static inline int
95 : fd_bincode_bool_decode( uchar * self,
96 30 : fd_bincode_decode_ctx_t * ctx ) {
97 :
98 30 : uchar const * ptr = (uchar const *)ctx->data;
99 30 : if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
100 0 : return FD_BINCODE_ERR_UNDERFLOW;
101 :
102 30 : if( FD_UNLIKELY( *ptr & (~1U) ) )
103 0 : return FD_BINCODE_ERR_ENCODING;
104 :
105 30 : *self = *ptr;
106 30 : ctx->data = ptr + 1;
107 :
108 30 : return FD_BINCODE_SUCCESS;
109 30 : }
110 :
111 : static inline int
112 21 : fd_bincode_bool_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
113 :
114 21 : uchar const * ptr = (uchar const *)ctx->data;
115 21 : if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
116 0 : return FD_BINCODE_ERR_UNDERFLOW;
117 :
118 21 : if( FD_UNLIKELY( *ptr & (~1U) ) )
119 0 : return FD_BINCODE_ERR_ENCODING;
120 :
121 21 : ctx->data = ptr + 1;
122 :
123 21 : return FD_BINCODE_SUCCESS;
124 21 : }
125 :
126 : static inline void
127 : fd_bincode_bool_decode_unsafe( uchar * self,
128 42 : fd_bincode_decode_ctx_t * ctx ) {
129 42 : fd_bincode_uint8_decode_unsafe( self, ctx );
130 42 : }
131 :
132 : static inline int
133 : fd_bincode_bool_encode( uchar self,
134 219 : fd_bincode_encode_ctx_t * ctx ) {
135 :
136 219 : uchar * ptr = (uchar *)ctx->data;
137 219 : if ( FD_UNLIKELY( (void *)(ptr + 1) > ctx->dataend ) )
138 0 : return FD_BINCODE_ERR_OVERFLOW;
139 :
140 219 : *ptr = !!self;
141 219 : ctx->data = ptr + 1;
142 :
143 219 : return FD_BINCODE_SUCCESS;
144 219 : }
145 :
146 : static inline int
147 : fd_bincode_bytes_decode( uchar * self,
148 : ulong len,
149 0 : fd_bincode_decode_ctx_t * ctx ) {
150 0 : uchar * ptr = (uchar *) ctx->data;
151 0 : if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) // Get wrap-around case right
152 0 : return FD_BINCODE_ERR_UNDERFLOW;
153 0 :
154 0 : fd_memcpy(self, ptr, len);
155 0 : ctx->data = ptr + len;
156 0 :
157 0 : return FD_BINCODE_SUCCESS;
158 0 : }
159 :
160 : static inline int
161 : fd_bincode_bytes_decode_footprint( ulong len,
162 534 : fd_bincode_decode_ctx_t * ctx ) {
163 534 : uchar * ptr = (uchar *) ctx->data;
164 534 : if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) { // Get wrap-around case right
165 0 : return FD_BINCODE_ERR_UNDERFLOW;
166 0 : }
167 :
168 534 : ctx->data = ptr + len;
169 :
170 534 : return FD_BINCODE_SUCCESS;
171 534 : }
172 :
173 : static inline void
174 : fd_bincode_bytes_decode_unsafe( uchar * self,
175 : ulong len,
176 34539 : fd_bincode_decode_ctx_t * ctx ) {
177 34539 : uchar * ptr = (uchar *) ctx->data;
178 34539 : fd_memcpy(self, ptr, len);
179 34539 : ctx->data = ptr + len;
180 34539 : }
181 :
182 : static inline int
183 : fd_bincode_bytes_encode( uchar const * self,
184 : ulong len,
185 1008 : fd_bincode_encode_ctx_t * ctx ) {
186 1008 : fd_msan_check( self, len );
187 :
188 1008 : uchar * ptr = (uchar *)ctx->data;
189 1008 : if( FD_UNLIKELY( (void *)( ptr+len ) > ctx->dataend ) )
190 0 : return FD_BINCODE_ERR_OVERFLOW;
191 :
192 1008 : fd_memcpy( ptr, self, len );
193 1008 : ctx->data = ptr + len;
194 :
195 1008 : return FD_BINCODE_SUCCESS;
196 1008 : }
197 :
198 : /* Alternate versions of fd_cu16_dec to make the function signature more consistent with the
199 : other fd_bincode_decode functions. */
200 : static inline int
201 : fd_bincode_compact_u16_decode( ushort * self,
202 0 : fd_bincode_decode_ctx_t * ctx ) {
203 0 : const uchar * ptr = (const uchar*) ctx->data;
204 0 : if( FD_UNLIKELY( ptr==NULL ) ) {
205 0 : return FD_BINCODE_ERR_UNDERFLOW;
206 0 : }
207 :
208 0 : if( FD_LIKELY( (void *) (ptr + 1) <= ctx->dataend && !(0x80U & ptr[0]) ) ) {
209 0 : *self = (ushort)ptr[0];
210 0 : ctx->data = ptr + 1;
211 0 : return FD_BINCODE_SUCCESS;
212 0 : }
213 :
214 0 : if( FD_LIKELY( (void *) (ptr + 2) <= ctx->dataend && !(0x80U & ptr[1]) ) ) {
215 0 : if( FD_UNLIKELY( !ptr[1] ) ) /* Detect non-minimal encoding */
216 0 : return FD_BINCODE_ERR_ENCODING;
217 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
218 0 : ctx->data = ptr + 2;
219 0 : return FD_BINCODE_SUCCESS;
220 0 : }
221 :
222 0 : if( FD_LIKELY( (void *) (ptr + 3) <= ctx->dataend && !(0xFCU & ptr[2]) ) ) {
223 0 : if( FD_UNLIKELY( !ptr[2] ) ) /* Detect non-minimal encoding */
224 0 : return FD_BINCODE_ERR_ENCODING;
225 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
226 0 : ctx->data = ptr + 3;
227 0 : return FD_BINCODE_SUCCESS;
228 0 : }
229 :
230 0 : return FD_BINCODE_ERR_UNDERFLOW;
231 0 : }
232 :
233 : static inline void
234 : fd_bincode_compact_u16_decode_unsafe( ushort * self,
235 0 : fd_bincode_decode_ctx_t * ctx ) {
236 0 : const uchar * ptr = (const uchar*) ctx->data;
237 :
238 0 : if( !(0x80U & ptr[0]) ) {
239 0 : *self = (ushort)ptr[0];
240 0 : ctx->data = ptr + 1;
241 0 : return;
242 0 : }
243 :
244 0 : if( !(0x80U & ptr[1]) ) {
245 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
246 0 : ctx->data = ptr + 2;
247 0 : return;
248 0 : }
249 :
250 0 : *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
251 0 : ctx->data = ptr + 3;
252 0 : }
253 :
254 : static inline int
255 : fd_bincode_compact_u16_encode( ushort const * self,
256 12 : fd_bincode_encode_ctx_t * ctx ) {
257 12 : uchar * ptr = (uchar*) ctx->data;
258 12 : ulong val = *self;
259 :
260 12 : if ( val < 0x80UL ) {
261 12 : if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
262 0 : return FD_BINCODE_ERR_OVERFLOW;
263 12 : *ptr = (uchar)val;
264 12 : ctx->data = ptr + 1;
265 12 : return FD_BINCODE_SUCCESS;
266 12 : }
267 :
268 0 : else if ( val < 0x4000UL ) {
269 0 : if ( FD_UNLIKELY((void *) (ptr + 2) > ctx->dataend ) )
270 0 : return FD_BINCODE_ERR_OVERFLOW;
271 0 : ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
272 0 : ptr[1] = (uchar)(val>>7);
273 0 : ctx->data = ptr + 2;
274 0 : return FD_BINCODE_SUCCESS;
275 0 : }
276 :
277 0 : else {
278 0 : if ( FD_UNLIKELY((void *) (ptr + 3) > ctx->dataend ) )
279 0 : return FD_BINCODE_ERR_OVERFLOW;
280 0 : ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
281 0 : ptr[1] = (uchar)(((val>>7)&0x7FUL)|0x80UL);
282 0 : ptr[2] = (uchar)(val>>14);
283 0 : ctx->data = ptr + 3;
284 0 : return FD_BINCODE_SUCCESS;
285 0 : }
286 12 : }
287 :
288 : static inline ulong
289 0 : fd_bincode_compact_u16_size( ushort const * self ) {
290 0 : ulong val = *self;
291 :
292 0 : if ( val < 0x80UL ) {
293 0 : return 1;
294 0 : }
295 0 : else if ( val < 0x4000UL ) {
296 0 : return 2;
297 0 : }
298 0 : else {
299 0 : return 3;
300 0 : }
301 0 : }
302 :
303 : /* Decodes an integer encoded using the serde_varint algorithm:
304 : https://github.com/solana-labs/solana/blob/master/sdk/program/src/serde_varint.rs
305 :
306 : A variable number of bytes could have been used to encode the integer.
307 : The most significant bit of each byte indicates if more bytes have been used, so we keep consuming until
308 : we reach a byte where the most significant bit is 0.
309 : */
310 : static inline int
311 : fd_bincode_varint_decode( ulong * self,
312 0 : fd_bincode_decode_ctx_t * ctx ) {
313 0 : ulong out = 0UL;
314 0 : uint shift = 0U;
315 0 :
316 0 : while( FD_LIKELY( shift < 64U ) ) {
317 0 :
318 0 : if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
319 0 : return FD_BINCODE_ERR_UNDERFLOW;
320 0 :
321 0 : uint byte = *(uchar const *)ctx->data;
322 0 : ctx->data = (uchar const *)ctx->data + 1;
323 0 : out |= (byte & 0x7FUL) << shift;
324 0 :
325 0 : if( (byte & 0x80U) == 0U ) {
326 0 : if( (out>>shift) != byte )
327 0 : return FD_BINCODE_ERR_ENCODING;
328 0 : if( byte==0U && (shift!=0U || out!=0UL) )
329 0 : return FD_BINCODE_ERR_ENCODING;
330 0 : *self = out;
331 0 : return FD_BINCODE_SUCCESS;
332 0 : }
333 0 :
334 0 : shift += 7U;
335 0 :
336 0 : }
337 0 :
338 0 : return FD_BINCODE_ERR_ENCODING;
339 0 : }
340 :
341 : static inline int
342 0 : fd_bincode_varint_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
343 0 : ulong out = 0UL;
344 0 : uint shift = 0U;
345 :
346 0 : while( FD_LIKELY( shift < 64U ) ) {
347 :
348 0 : if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
349 0 : return FD_BINCODE_ERR_UNDERFLOW;
350 :
351 0 : uint byte = *(uchar const *)ctx->data;
352 0 : ctx->data = (uchar const *)ctx->data + 1;
353 0 : out |= (byte & 0x7FUL) << shift;
354 :
355 0 : if( (byte & 0x80U) == 0U ) {
356 0 : if( (out>>shift) != byte )
357 0 : return FD_BINCODE_ERR_ENCODING;
358 0 : if( byte==0U && (shift!=0U || out!=0UL) )
359 0 : return FD_BINCODE_ERR_ENCODING;
360 0 : return FD_BINCODE_SUCCESS;
361 0 : }
362 :
363 0 : shift += 7U;
364 :
365 0 : }
366 :
367 0 : return FD_BINCODE_ERR_ENCODING;
368 0 : }
369 :
370 : static inline void
371 : fd_bincode_varint_decode_unsafe( ulong * self,
372 0 : fd_bincode_decode_ctx_t * ctx ) {
373 0 : ulong out = 0UL;
374 0 : uint shift = 0U;
375 :
376 0 : for(;;) {
377 0 : uint byte = *(uchar const *)ctx->data;
378 0 : ctx->data = (uchar const *)ctx->data + 1;
379 0 : out |= (byte & 0x7FUL) << shift;
380 :
381 0 : if( (byte & 0x80U) == 0U ) {
382 0 : *self = out;
383 0 : return;
384 0 : }
385 :
386 0 : shift += 7U;
387 0 : }
388 0 : }
389 :
390 : static inline int
391 : fd_bincode_varint_encode( ulong val,
392 0 : fd_bincode_encode_ctx_t * ctx ) {
393 0 : uchar * ptr = (uchar *) ctx->data;
394 0 : while (1) {
395 0 : if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
396 0 : return FD_BINCODE_ERR_OVERFLOW;
397 0 : if ( val < 0x80UL ) {
398 0 : *(ptr++) = (uchar)val;
399 0 : ctx->data = ptr;
400 0 : return FD_BINCODE_SUCCESS;
401 0 : }
402 0 : *(ptr++) = (uchar)((val&0x7FUL)|0x80UL);
403 0 : val >>= 7;
404 0 : }
405 0 : }
406 :
407 : static inline ulong
408 0 : fd_bincode_varint_size( ulong val ) {
409 0 : ulong sz = 0;
410 0 : while (1) {
411 0 : if ( val < 0x80UL ) {
412 0 : return sz+1;
413 0 : }
414 0 : sz++;
415 0 : val >>= 7;
416 0 : }
417 0 : }
418 :
419 : enum {
420 : /* All meta tags must fit in 6 bits */
421 :
422 : /* Primitive types with an implicit encoding length */
423 : FD_ARCHIVE_META_CHAR = 0x1,
424 : FD_ARCHIVE_META_STRING = 0x2,
425 : FD_ARCHIVE_META_CHAR32 = 0x3,
426 : FD_ARCHIVE_META_DOUBLE = 0x4,
427 : FD_ARCHIVE_META_LONG = 0x5,
428 : FD_ARCHIVE_META_UINT = 0x6,
429 : FD_ARCHIVE_META_UINT128 = 0x7,
430 : FD_ARCHIVE_META_BOOL = 0x8,
431 : FD_ARCHIVE_META_UCHAR = 0x9,
432 : FD_ARCHIVE_META_UCHAR32 = 0xa,
433 : FD_ARCHIVE_META_UCHAR128 = 0xb,
434 : FD_ARCHIVE_META_UCHAR2048 = 0xc,
435 : FD_ARCHIVE_META_ULONG = 0xd,
436 : FD_ARCHIVE_META_USHORT = 0xe,
437 :
438 : /* Meta types which have an encoding length after the short tag */
439 : FD_ARCHIVE_META_STRUCT = 0x21,
440 : FD_ARCHIVE_META_VECTOR = 0x22,
441 : FD_ARCHIVE_META_DEQUE = 0x23,
442 : FD_ARCHIVE_META_MAP = 0x24,
443 : FD_ARCHIVE_META_TREAP = 0x25,
444 : FD_ARCHIVE_META_OPTION = 0x26,
445 : FD_ARCHIVE_META_ARRAY = 0x27,
446 : FD_ARCHIVE_META_STATIC_VECTOR = 0x28,
447 : };
448 :
449 : #define FD_ARCHIVE_META_SENTINAL (ushort)0 /* End of structure */
450 :
451 0 : static inline int fd_archive_encode_setup_length( fd_bincode_encode_ctx_t * ctx, void ** offset_out ) {
452 0 : uchar * ptr = (uchar *)ctx->data;
453 0 : if ( FD_UNLIKELY((void *)(ptr + sizeof(uint)) > ctx->dataend ) )
454 0 : return FD_BINCODE_ERR_OVERFLOW;
455 0 : /* Skip over length for now but make space for it */
456 0 : *offset_out = ptr;
457 0 : ctx->data = ptr + sizeof(uint);
458 0 : return FD_BINCODE_SUCCESS;
459 0 : }
460 :
461 0 : static inline int fd_archive_encode_set_length( fd_bincode_encode_ctx_t * ctx, void * offset ) {
462 0 : *(uint *)offset = (uint)((uchar *)ctx->data - ((uchar *)offset + sizeof(uint)));
463 0 : return FD_BINCODE_SUCCESS;
464 0 : }
465 :
466 0 : static inline int fd_archive_decode_setup_length( fd_bincode_decode_ctx_t * ctx, void ** offset_out ) {
467 0 : uchar * ptr = (uchar *)ctx->data;
468 0 : if ( FD_UNLIKELY((void *)(ptr + sizeof(uint)) > ctx->dataend ) )
469 0 : return FD_BINCODE_ERR_UNDERFLOW;
470 0 : /* Skip over length for now and verify it later */
471 0 : *offset_out = ptr;
472 0 : ctx->data = ptr + sizeof(uint);
473 0 : return FD_BINCODE_SUCCESS;
474 0 : }
475 :
476 0 : static inline int fd_archive_decode_check_length( fd_bincode_decode_ctx_t * ctx, void * offset ) {
477 0 : if( *(uint *)offset != (uint)((uchar *)ctx->data - ((uchar *)offset + sizeof(uint))) )
478 0 : return FD_BINCODE_ERR_ENCODING;
479 0 : return FD_BINCODE_SUCCESS;
480 0 : }
481 :
482 : /* Convenience API for deserializing with common allocators */
483 :
484 : /* fd_bincode_decode_spad decodes a bincode type. The result is
485 : allocated into a spad on success. On failure, no spad allocations
486 : are made.
487 :
488 : fd_bincode_decode1_spad optionally outputs the number of bytes read
489 : to *psz. */
490 :
491 : #define fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, psz ) \
492 0 : __extension__({ \
493 0 : fd_spad_t * const spad_ = (spad); \
494 0 : void const * const buf_ = (buf); \
495 0 : ulong const buf_sz_ = (buf_sz); \
496 0 : int * perr_ = (perr); \
497 0 : ulong * psz_ = (psz); \
498 0 : fd_bincode_decode_ctx_t ctx = {0}; \
499 0 : if( perr_ ) *perr_ = -1; \
500 0 : ctx.data = (void const *)( buf_ ); \
501 0 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
502 0 : ulong total_sz = 0UL; \
503 0 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
504 0 : fd_##type##_t * out = NULL; \
505 0 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
506 0 : ulong align = fd_##type##_align(); \
507 0 : void * mem = fd_spad_alloc( spad_, align, total_sz ); \
508 0 : if( FD_UNLIKELY( !mem ) ) { \
509 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_ ) )); \
510 0 : } \
511 0 : out = fd_##type##_decode( mem, &ctx ); \
512 0 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
513 0 : } \
514 0 : if( perr_ ) *perr_ = err; \
515 0 : out; \
516 0 : })
517 :
518 : #define fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, psz ) \
519 : __extension__({ \
520 : fd_spad_t * const spad_ = (spad); \
521 : void const * const buf_ = (buf); \
522 : ulong const buf_sz_ = (buf_sz); \
523 : int * perr_ = (perr); \
524 : ulong * psz_ = (psz); \
525 : fd_bincode_decode_ctx_t ctx = {0}; \
526 : if( perr_ ) *perr_ = -1; \
527 : ctx.data = (void const *)( buf_ ); \
528 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
529 : ulong total_sz = 0UL; \
530 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
531 : fd_##type##_global_t * out = NULL; \
532 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
533 : ulong align = fd_##type##_align(); \
534 : void * mem = fd_spad_alloc( spad_, align, total_sz ); \
535 : if( FD_UNLIKELY( !mem ) ) { \
536 : 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_ ) )); \
537 : } \
538 : out = fd_##type##_decode_global( mem, &ctx ); \
539 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
540 : } \
541 : if( perr_ ) *perr_ = err; \
542 : out; \
543 : })
544 :
545 : #define fd_bincode_decode_spad( type, spad, buf, buf_sz, perr ) \
546 0 : fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, NULL )
547 :
548 : #define fd_bincode_decode_spad_global( type, spad, buf, buf_sz, perr ) \
549 : fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, NULL )
550 :
551 : /* fd_bincode_decode_scratch decodes a bincode type. The result is
552 : allocated into the thread's scratch region on success. On failure,
553 : no allocations are made. */
554 :
555 : #define fd_bincode_decode1_scratch( type, buf, buf_sz, perr, psz ) \
556 3 : __extension__({ \
557 3 : void const * const buf_ = (buf); \
558 3 : ulong const buf_sz_ = (buf_sz); \
559 3 : int * perr_ = (perr); \
560 3 : ulong * psz_ = (psz); \
561 3 : fd_bincode_decode_ctx_t ctx = {0}; \
562 3 : if( perr_ ) *perr_ = -1; \
563 3 : ctx.data = (void const *)( buf_ ); \
564 3 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
565 3 : ulong total_sz = 0UL; \
566 3 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
567 3 : fd_##type##_t * out = NULL; \
568 3 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
569 3 : ulong align = fd_##type##_align(); \
570 3 : if( FD_UNLIKELY( !fd_scratch_alloc_is_safe( align, total_sz ) ) ) { \
571 0 : 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() )); \
572 0 : } \
573 3 : void * mem = fd_scratch_alloc( align, total_sz ); \
574 3 : out = fd_##type##_decode( mem, &ctx ); \
575 3 : if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_; \
576 3 : } \
577 3 : if( perr_ ) *perr_ = err; \
578 3 : out; \
579 3 : })
580 :
581 : #define fd_bincode_decode_scratch( type, buf, buf_sz, perr ) \
582 3 : fd_bincode_decode1_scratch( type, buf, buf_sz, perr, NULL )
583 :
584 : /* fd_bincode_decode_static decodes a statically-sized bincode type.
585 :
586 : Example usage:
587 :
588 : fd_epoch_schedule_t es[1]; int err;
589 : if( FD_UNLIKELY( fd_bincode_decode_static( epoch_schedule, es, buf, bufsz, &err ) ) ) {
590 : ... parse fail ...
591 : return;
592 : }
593 : ... parse success ... */
594 :
595 : #define fd_bincode_decode_static( type, out, buf, buf_sz, perr ) \
596 6 : __extension__({ \
597 6 : void const * const buf_ = (buf); \
598 6 : ulong const buf_sz_ = (buf_sz); \
599 6 : int * perr_ = (perr); \
600 6 : fd_##type##_t * res = NULL; \
601 6 : fd_bincode_decode_ctx_t ctx = {0}; \
602 6 : ctx.data = (void const *)( buf_ ); \
603 6 : ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ ); \
604 6 : ulong total_sz = 0UL; \
605 6 : int err = fd_##type##_decode_footprint( &ctx, &total_sz ); \
606 6 : if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) { \
607 6 : res = fd_##type##_decode( (out), &ctx ); \
608 6 : } \
609 6 : if( perr_ ) *perr_ = err; \
610 6 : res; \
611 6 : })
612 :
613 : #endif /* HEADER_fd_src_flamenco_types_fd_bincode_h */
|