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