LCOV - code coverage report
Current view: top level - ballet/json - fd_jtok.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 20 0.0 %
Date: 2026-10-23 17:13:25 Functions: 0 28 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_ballet_json_fd_jtok_h
       2             : #define HEADER_fd_src_ballet_json_fd_jtok_h
       3             : 
       4             : /* fd_jtok is a JSON tokenizer.
       5             : 
       6             :    Example:
       7             : 
       8             :      fd_jtok_t j[1];
       9             :      fd_jtok_init( j, buf, buf_sz );
      10             :      fd_jtok_str_t key;
      11             :      fd_jtok_obj_enter( j );
      12             :      while( fd_jtok_obj_next( j, &key ) ) {
      13             :        if(      fd_jtok_str_eq( &key, "commitment"     ) ) fd_jtok_cstr ( j, cfg->commitment, sizeof(cfg->commitment) );
      14             :        else if( fd_jtok_str_eq( &key, "minContextSlot" ) ) fd_jtok_ulong( j, &cfg->min_ctx_slot );
      15             :      }
      16             :      if( fd_jtok_fini( j ) ) reject( fd_jtok_err_off( j ) );
      17             : 
      18             :    Errors are sticky.  After the first error every call returns 0.
      19             : 
      20             :    obj_next / arr_next leave the cursor on the member's value.  If the
      21             :    caller does not read it, the next obj_next / arr_next / fini skips
      22             :    it.
      23             : 
      24             :    To read a value whose meaning depends on a later sibling (JSON-RPC
      25             :    "params" before "method"), capture it with fd_jtok_raw and tokenize
      26             :    the slice with a second cursor after the loop.
      27             : 
      28             :    Input must be RFC 8259 JSON.  Strings must be valid UTF-8 with no
      29             :    raw control characters.  Bytes after the top-level value are an
      30             :    error.  If a key repeats, the last one wins. */
      31             : 
      32             : #include "../fd_ballet_base.h"
      33             : 
      34             : /* FD_JTOK_ERR_* give error codes */
      35             : 
      36           0 : #define FD_JTOK_ERR_SYNTAX (1) /* malformed JSON */
      37           0 : #define FD_JTOK_ERR_TYPE   (2) /* value has the wrong kind */
      38           0 : #define FD_JTOK_ERR_RANGE  (3) /* number or string does not fit */
      39           0 : #define FD_JTOK_ERR_DEPTH  (4) /* skipped value nests deeper than FD_JTOK_SKIP_DEPTH_MAX */
      40           0 : #define FD_JTOK_ERR_TRAIL  (5) /* bytes after the top-level value */
      41           0 : #define FD_JTOK_ERR_USAGE  (6) /* getter with no pending value, or fini inside a container */
      42             : 
      43             : /* FD_JTOK_* give value kinds (fd_jtok_peek) */
      44             : 
      45           0 : #define FD_JTOK_OBJ  (1) /* { ... } */
      46           0 : #define FD_JTOK_ARR  (2) /* [ ... ] */
      47           0 : #define FD_JTOK_STR  (3) /* " ... " */
      48           0 : #define FD_JTOK_INT  (4) /* number without fraction or exponent */
      49           0 : #define FD_JTOK_NUM  (5) /* any other number */
      50           0 : #define FD_JTOK_BOOL (6) /* false/true */
      51           0 : #define FD_JTOK_NULL (7) /* null */
      52             : 
      53             : /* FD_JTOK_SKIP_DEPTH_MAX is the max nesting of a value consumed by
      54             :    skip, raw, or auto-skip. */
      55             : 
      56           0 : #define FD_JTOK_SKIP_DEPTH_MAX (64UL)
      57             : 
      58             : /* FD_JTOK_NUM_SZ_MAX is the max length of a number literal accepted by
      59             :    fd_jtok_double. */
      60             : 
      61             : #define FD_JTOK_NUM_SZ_MAX (64UL)
      62             : 
      63             : /* fd_jtok_str_t spans encoded string bytes from the input buffer. */
      64             : 
      65             : struct fd_jtok_str {
      66             :   char const * ptr;
      67             :   ulong        sz;
      68             : };
      69             : 
      70             : typedef struct fd_jtok_str fd_jtok_str_t;
      71             : 
      72             : /* fd_jtok_t is the parser cursor. */
      73             : 
      74             : struct fd_jtok {
      75             :   char const * beg;
      76             :   char const * cur;
      77             :   char const * end;
      78             :   int          err;
      79             :   int          pending;
      80             :   int          first;
      81             :   ulong        depth;
      82             : };
      83             : 
      84             : typedef struct fd_jtok fd_jtok_t;
      85             : 
      86             : FD_PROTOTYPES_BEGIN
      87             : 
      88             : /* fd_jtok_init starts tokenizing the sz bytes at buf.  buf must
      89             :    outlive any fd_jtok_str_t taken from it.  Returns j with the
      90             :    top-level value pending.  An empty input (sz 0, buf may then be
      91             :    NULL) is not valid JSON and starts out with FD_JTOK_ERR_SYNTAX. */
      92             : 
      93             : fd_jtok_t *
      94             : fd_jtok_init( fd_jtok_t *  j,
      95             :               void const * buf,
      96             :               ulong        sz );
      97             : 
      98             : /* fd_jtok_fini skips the top-level value if still pending and checks
      99             :    that only whitespace remains.  Returns the error code, 0 on
     100             :    success.  Call it at top level, after the last obj_next / arr_next
     101             :    returned 0. */
     102             : 
     103             : int
     104             : fd_jtok_fini( fd_jtok_t * j );
     105             : 
     106             : FD_FN_PURE static inline int
     107           0 : fd_jtok_err( fd_jtok_t const * j ) {
     108           0 :   return j->err;
     109           0 : }
     110             : 
     111             : /* fd_jtok_err_off returns the input offset at which the error was
     112             :    detected. */
     113             : 
     114             : FD_FN_PURE static inline ulong
     115           0 : fd_jtok_err_off( fd_jtok_t const * j ) {
     116           0 :   return (ulong)( j->cur - j->beg );
     117           0 : }
     118             : 
     119             : /* fd_jtok_peek returns the FD_JTOK_* kind of the pending value, 0 on
     120             :    error.  The value stays pending. */
     121             : 
     122             : int
     123             : fd_jtok_peek( fd_jtok_t * j );
     124             : 
     125             : /* fd_jtok_obj_enter consumes the opening brace of the pending object.
     126             :    FD_JTOK_ERR_TYPE if it is not an object. */
     127             : 
     128             : void
     129             : fd_jtok_obj_enter( fd_jtok_t * j );
     130             : 
     131             : /* fd_jtok_obj_next advances to the next member of the innermost
     132             :    object, skipping the previous value if it was not read.  Returns 1
     133             :    with *key set and the value pending, or 0 after the closing brace
     134             :    (or on error). */
     135             : 
     136             : int
     137             : fd_jtok_obj_next( fd_jtok_t *     j,
     138             :                   fd_jtok_str_t * key );
     139             : 
     140             : /* Array equivalents of obj_enter / obj_next. */
     141             : 
     142             : void
     143             : fd_jtok_arr_enter( fd_jtok_t * j );
     144             : 
     145             : int
     146             : fd_jtok_arr_next( fd_jtok_t * j );
     147             : 
     148             : /* Scalar getters consume the pending value into *out.  Wrong kind is
     149             :    FD_JTOK_ERR_TYPE, out of range is FD_JTOK_ERR_RANGE.  *out is
     150             :    written on success only.  ulong and long require an INT.  double
     151             :    accepts INT or NUM up to FD_JTOK_NUM_SZ_MAX chars and fails with
     152             :    FD_JTOK_ERR_RANGE if the literal overflows or underflows a finite
     153             :    double (e.g. 1e999, 1e-999).  bool stores 0 or 1. */
     154             : 
     155             : void fd_jtok_ulong ( fd_jtok_t * j, ulong  * out );
     156             : void fd_jtok_long  ( fd_jtok_t * j, long   * out );
     157             : void fd_jtok_double( fd_jtok_t * j, double * out );
     158             : void fd_jtok_bool  ( fd_jtok_t * j, int    * out );
     159             : void fd_jtok_null  ( fd_jtok_t * j );
     160             : 
     161             : /* fd_jtok_cstr consumes the pending string, decodes escapes to UTF-8
     162             :    and writes it NUL-terminated to the out_sz bytes at out.
     163             :    FD_JTOK_ERR_RANGE if it does not fit or contains an escaped NUL.
     164             :    On failure out[0] is '\0' (if out_sz>0). */
     165             : 
     166             : void
     167             : fd_jtok_cstr( fd_jtok_t * j,
     168             :               char *      out,
     169             :               ulong       out_sz );
     170             : 
     171             : /* fd_jtok_str consumes the pending string as a zero-copy view. */
     172             : 
     173             : void
     174             : fd_jtok_str( fd_jtok_t *     j,
     175             :              fd_jtok_str_t * out );
     176             : 
     177             : /* fd_jtok_skip consumes the pending value. */
     178             : 
     179             : void
     180             : fd_jtok_skip( fd_jtok_t * j );
     181             : 
     182             : /* fd_jtok_raw consumes the pending value and returns the input bytes
     183             :    from its first to its last character. */
     184             : 
     185             : void
     186             : fd_jtok_raw( fd_jtok_t *   j,
     187             :              char const ** ptr,
     188             :              ulong *       sz );
     189             : 
     190             : /* fd_jtok_str_decode decodes the escapes in s to UTF-8 and writes the
     191             :    result NUL-terminated to the out_sz bytes at out.  Returns the
     192             :    decoded length excluding the terminator, or -1 if it does not fit or
     193             :    s contains an escaped NUL (out[0] is then '\0' if out_sz>0). */
     194             : 
     195             : long
     196             : fd_jtok_str_decode( fd_jtok_str_t const * s,
     197             :                     char *                out,
     198             :                     ulong                 out_sz );
     199             : 
     200             : /* fd_jtok_str_eq returns 1 if s decodes to exactly lit.  Escapes in s
     201             :    are decoded before comparing. */
     202             : 
     203             : FD_FN_PURE int
     204             : fd_jtok_str_eq( fd_jtok_str_t const * s,
     205             :                 char const *          lit );
     206             : 
     207             : FD_PROTOTYPES_END
     208             : 
     209             : #endif /* HEADER_fd_src_ballet_json_fd_jtok_h */

Generated by: LCOV version 1.14