Skip to content

Commit

Permalink
improved JSON API + FIOBJ details + fooling around
Browse files Browse the repository at this point in the history
  • Loading branch information
boazsegev committed Aug 18, 2024
1 parent 1feebdf commit fd3533f
Show file tree
Hide file tree
Showing 15 changed files with 3,394 additions and 2,044 deletions.
2,000 changes: 1,368 additions & 632 deletions fio-stl.h

Large diffs are not rendered by default.

202 changes: 61 additions & 141 deletions fio-stl.md
Original file line number Diff line number Diff line change
Expand Up @@ -3290,18 +3290,6 @@ The JSON parser isn't recursive, but it allocates a nesting bitmap on the stack,

To ensure the stack isn't abused, the parser will limit JSON nesting levels to a customizable `FIO_JSON_MAX_DEPTH` number of nesting levels.

#### `fio_json_parser_s`

```c
typedef struct {
/** level of nesting. */
uint32_t depth;
/** expectation bit flag: 0=key, 1=colon, 2=value, 4=comma/closure . */
uint8_t expect;
/** nesting bit flags - dictionary bit = 0, array bit = 1. */
uint8_t nesting[(FIO_JSON_MAX_DEPTH + 7) >> 3];
} fio_json_parser_s;
```

The JSON parser type. Memory must be initialized to 0 before first uses (see `FIO_JSON_INIT`).

Expand Down Expand Up @@ -3329,169 +3317,101 @@ typedef struct {
A convenient macro that could be used to initialize the parser's memory to 0.

### JSON parser API

#### `fio_json_parse`

```c
size_t fio_json_parse(fio_json_parser_s *parser,
const char *buffer,
const size_t len);
```

Returns the number of bytes consumed before parsing stopped (due to either error or end of data). Stops as close as possible to the end of the buffer or once an object parsing was completed.

Zero (0) is a valid number and may indicate that the buffer's memory contains a partial object that can't be fully parsed just yet.

**Note!**: partial Numeral objects may be result in errors, as the number 1234 may be fragmented as 12 and 34 when streaming data. facil.io doesn't protect against this possible error.


#### `fio_json_parser_is_in_array`

```c
uint8_t fio_json_parser_is_in_array(fio_json_parser_s *parser);
```

Tests the state of the JSON parser.

Returns 1 if the parser is currently within an Array or 0 if it isn't.

**Note**: this Helper function is only available within the parsing code.

#### `fio_json_parser_is_in_object`

```c
uint8_t fio_json_parser_is_in_object(fio_json_parser_s *parser);
```

Tests the state of the JSON parser.

Returns 1 if the parser is currently within an Object or 0 if it isn't.

**Note**: this Helper function is only available within the parsing code.

#### `fio_json_parser_is_key`

```c
uint8_t fio_json_parser_is_key(fio_json_parser_s *parser);
```

Tests the state of the JSON parser.

Returns 1 if the parser is currently parsing a "key" within an object or 0 if it isn't.

**Note**: this Helper function is only available within the parsing code.

#### `fio_json_parser_is_value`
#### `fio_json_parser_callbacks_s`

```c
uint8_t fio_json_parser_is_value(fio_json_parser_s *parser);
```

Tests the state of the JSON parser.

Returns 1 if the parser is currently parsing a "value" (within a array, an object or stand-alone) or 0 if it isn't (it's parsing a key).

**Note**: this Helper function is only available within the parsing code.

### JSON Required Callbacks

The JSON parser requires the following callbacks to be defined as static functions.

#### `fio_json_on_null`

```c
static void fio_json_on_null(fio_json_parser_s *p);
typedef struct {
/** NULL object was detected. Returns new object as `void *`. */
void *(*get_null)(void);
/** TRUE object was detected. Returns new object as `void *`. */
void *(*get_true)(void);
/** FALSE object was detected. Returns new object as `void *`. */
void *(*get_false)(void);
/** Number was detected (long long). Returns new object as `void *`. */
void *(*get_number)(int64_t i);
/** Float was detected (double).Returns new object as `void *`. */
void *(*get_float)(double f);
/** String was detected (int / float). update `pos` to point at ending */
void *(*get_string)(const void *start, size_t len);
/** Dictionary was detected. Returns ctx to hash map or NULL on error. */
void *(*get_map)(void *ctx, void *at);
/** Array was detected. Returns ctx to array or NULL on error. */
void *(*get_array)(void *ctx, void *at);
/** Array was detected. Returns non-zero on error. */
int (*map_push)(void *ctx, void *key, void *value);
/** Array was detected. Returns non-zero on error. */
int (*array_push)(void *ctx, void *value);
/** Called for the `key` element in case of error or NULL value. */
void (*free_unused_object)(void *ctx);
/** the JSON parsing encountered an error - what to do with ctx? */
void *(*on_error)(void *ctx);
} fio_json_parser_callbacks_s;
```

A `null` object was detected
The JSON parser requires certain callbacks to create objects or perform actions based on JSON data.

#### `fio_json_on_true`

```c
static void fio_json_on_true(fio_json_parser_s *p);
```
The following callbacks MUST be provided to the parser:

A `true` object was detected
- `void *(*get_null)(void)` - `NULL` object was detected. Returns NULL object as `void *`.

#### `fio_json_on_false`
- `void *(*get_true)(void)` - `true` object was detected. Returns TRUE object as `void *`.

```c
static void fio_json_on_false(fio_json_parser_s *p);
```
- `void *(*get_false)(void)` - `false` object was detected. Returns FALSE object as `void *`.

A `false` object was detected
- `void *(*get_number)(int64_t i)` - Number was detected (`int64_t`). Returns new number object as `void *`.

#### `fio_json_on_number`
- `void *(*get_float)(double f)` - Float was detected (`double`). Returns new float object as `void *`.

```c
static void fio_json_on_number(fio_json_parser_s *p, long long i);
```
- `void *(*get_string)(const void *start, size_t len)` - String was detected. `start` points to a JSON escaped String (remember to unescape). Returns a new String as `void *`.

A Number was detected (long long).
- `void *(*get_map)(void *ctx, void *at)` - Dictionary was detected. Returns new `ctx` to hash map or `NULL` on error.

#### `fio_json_on_float`
- `void *(*get_array)(void *ctx, void *at)` - Array was detected. Returns new `ctx` to array or `NULL` on error.

```c
static void fio_json_on_float(fio_json_parser_s *p, double f);
```
- `int (*map_push)(void *ctx, void *key, void *value)` - Pushes data to Array. Returns non-zero on error.

A Float was detected (double).
- `int (*array_push)(void *ctx, void *value)` - Pushes data to Dictionary. Returns non-zero on error.

#### `fio_json_on_string`
- `void (*free_unused_object)(void *ctx)` - Called for the `key` element in case of error that caused `key` to be unused.

```c
static void fio_json_on_string(fio_json_parser_s *p, const void *start, size_t len);
```
- `void *(*on_error)(void *ctx)` - the JSON parsing encountered an error - what to do with ctx?

A String was detected (int / float). update `pos` to point at ending


#### `fio_json_on_start_object`
#### `fio_json_parse`

```c
static int fio_json_on_start_object(fio_json_parser_s *p);
```

A dictionary object was detected, should return 0 unless error occurred.

#### `fio_json_on_end_object`
/** The JSON return type. */
typedef struct {
void *ctx;
size_t stop_pos;
int err;
} fio_json_result_s;

```c
static void fio_json_on_end_object(fio_json_parser_s *p);
fio_json_result_s fio_json_parse(fio_json_parser_callbacks_s *callbacks,
const char *json_string,
const size_t len);
```

A dictionary object closure detected

#### `fio_json_on_start_array`
The facil.io JSON parser is a non-strict parser, with support for trailing commas in collections, new-lines in strings, extended escape characters and octal, hex and binary numbers.

```c
static int fio_json_on_start_array(fio_json_parser_s *p);
```
An array object was detected, should return 0 unless error occurred.
The parser allows for streaming data and decouples the parsing process from the resulting data-structure by calling the requested callbacks for JSON related events.

#### `fio_json_on_end_array`
Returns the result object which details the number of bytes consumed (stop position index `stop_pos`), if the parsing stopped due to an error (`err`) and the top most context / object in the JSON stream.

```c
static void fio_json_on_end_array(fio_json_parser_s *p);
```

An array closure was detected

#### `fio_json_on_json`
#### `fio_json_parse_update`

```c
static void fio_json_on_json(fio_json_parser_s *p);
fio_json_result_s fio_json_parse_update(fio_json_parser_callbacks_s *s,
void *ctx,
const char *start,
const size_t len);
```

The JSON parsing is complete (JSON data parsed so far contains a valid JSON object).

#### `fio_json_on_error`

```c
static void fio_json_on_error(fio_json_parser_s *p);
```
Use only when `ctx` is an object and JSON data is wrapped in an object (of the same type).

The JSON parsing should stop with an error.
i.e., update an array or hash map.

### JSON Parsing Example - a JSON minifier

Expand Down
9 changes: 9 additions & 0 deletions fio-stl/000 core.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ typedef SSIZE_T ssize_t;
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -1443,6 +1444,14 @@ FIO_IFUNC intmax_t fio_ct_max(intmax_t a_, intmax_t b_) {
intmax_t)fio_ct_if_bool(((a - b) >> ((sizeof(a) << 3) - 1)) & 1, b, a);
}

/** Returns `a` if a >= `b`. */
FIO_IFUNC intmax_t fio_ct_min(intmax_t a_, intmax_t b_) {
// if b - a is negative, a > b, unless both / one are negative.
const uintmax_t a = a_, b = b_;
return (
intmax_t)fio_ct_if_bool(((a - b) >> ((sizeof(a) << 3) - 1)) & 1, a, b);
}

/** Returns absolute value. */
FIO_IFUNC uintmax_t fio_ct_abs(intmax_t i_) {
// if b - a is negative, a > b, unless both / one are negative.
Expand Down
3 changes: 1 addition & 2 deletions fio-stl/000 dependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,11 @@ Basics Inclusion
#undef FIO_FIOBJ
#undef FIO_MALLOC
#undef FIO_MUSTACHE
#undef FIO_STATE
#undef FIO_THREADS
#undef FIOBJ_MALLOC
#define FIO_CLI
#define FIO_CORE
#define FIO_CRYPT
#define FIO_STATE
#define FIO_THREADS

#elif !defined(H___FIO_BASIC_ROUND2___H)
Expand Down Expand Up @@ -294,6 +292,7 @@ FIO_MAP Ordering & Naming Shortcut

#if defined(FIO_FIOBJ)
#define FIO_MUSTACHE
#define FIO_JSON
#endif

#if defined(FIO_HTTP)
Expand Down
2 changes: 1 addition & 1 deletion fio-stl/001 memalt.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ FIO_MEMCHR / fio_memchr - memchr fallbacks
* should be faster.
*/
SFUNC void *fio_memchr(const void *buffer, const char token, size_t len) {
return memchr(buffer, token, len); /* FIXME */
// return (void *)memchr(buffer, token, len); /* FIXME */
const char *r = (const char *)buffer;
const char *e = r + (len - 127);
uint64_t u[16] FIO_ALIGN(64) = {0};
Expand Down
Loading

0 comments on commit fd3533f

Please sign in to comment.