Objectively 1.0.0
Ultra-lightweight object oriented framework for GNU C.
Data Structures | Macros | Functions
JSONSerialization.c File Reference
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "Boole.h"
#include "JSONSerialization.h"
#include "MutableData.h"
#include "MutableDictionary.h"
#include "MutableArray.h"
#include "Null.h"
#include "Number.h"

Go to the source code of this file.

Data Structures

struct  JSONReader
 A reader for parsing JSON Data. More...
 
struct  JSONWriter
 A writer for generating JSON Data. More...
 

Macros

#define _Class   _JSONSerialization
 

Functions

Class_JSONSerialization (void)
 
static void consumeBytes (JSONReader *reader, const char *bytes)
 Consumes and verifies bytes from `reader. More...
 
static DatadataFromObject (const ident obj, int options)
 
static void initialize (Class *clazz)
 
static ident objectFromData (const Data *data, int options)
 
static ArrayreadArray (JSONReader *reader)
 Reads an array from `reader. More...
 
static _Bool * readBoole (JSONReader *reader)
 Reads a Boole from reader. More...
 
static int readByte (JSONReader *reader)
 
static int readByteUntil (JSONReader *reader, const char *stop)
 Consume bytes from reader until a byte from stop is found. More...
 
static ident readElement (JSONReader *reader)
 Reads an element from reader. An element is any valid JSON type. More...
 
static StringreadLabel (JSONReader *reader)
 Reads a label from reader. More...
 
static NullreadNull (JSONReader *reader)
 Reads Null from Reader. More...
 
static NumberreadNumber (JSONReader *reader)
 Reads a Number from reader. More...
 
static DictionaryreadObject (JSONReader *reader)
 Reads an object from reader. An object is a valid JSON structure. More...
 
static StringreadString (JSONReader *reader)
 Reads a String from reader. More...
 
static void writeArray (JSONWriter *writer, const Array *array)
 Writes array to writer. More...
 
static void writeBoole (JSONWriter *writer, const Boole *boolean)
 Writes boolean to writer. More...
 
static void writeElement (JSONWriter *writer, const ident obj)
 Writes the specified JSON element to writer. More...
 
static void writeLabel (JSONWriter *writer, const String *label)
 Writes the label (field name) label to writer. More...
 
static void writeNull (JSONWriter *writer, const Null *null)
 Writes null to writer. More...
 
static void writeNumber (JSONWriter *writer, const Number *number)
 Writes number to writer. More...
 
static void writeObject (JSONWriter *writer, const Dictionary *object)
 Writes object to writer. More...
 
static void writePretty (JSONWriter *writer)
 Writes pretty formatting, if applicable, to writer. More...
 
static void writeString (JSONWriter *writer, const String *string)
 Writes string to writer. More...
 

Macro Definition Documentation

◆ _Class

#define _Class   _JSONSerialization

Definition at line 37 of file JSONSerialization.c.

Function Documentation

◆ _JSONSerialization()

Class * _JSONSerialization ( void  )

Definition at line 511 of file JSONSerialization.c.

511 {
512 static Class *clazz;
513 static Once once;
514
515 do_once(&once, {
516 clazz = _initialize(&(const ClassDef) {
517 .name = "JSONSerialization",
518 .superclass = _Object(),
519 .instanceSize = sizeof(JSONSerialization),
520 .interfaceOffset = offsetof(JSONSerialization, interface),
521 .interfaceSize = sizeof(JSONSerializationInterface),
523 });
524 });
525
526 return clazz;
527}
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition: Class.c:91
static void initialize(Class *clazz)
long Once
The Once type.
Definition: Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition: Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition: Class.h:41
The runtime representation of a Class.
Definition: Class.h:95
JSON serialization and introspection.
Class * _Object(void)
The Object archetype.
Definition: Object.c:136

◆ consumeBytes()

static void consumeBytes ( JSONReader reader,
const char *  bytes 
)
static

Consumes and verifies bytes from `reader.

Parameters
readerThe JSONReader.
bytesThe bytes to consume from reader.

Definition at line 294 of file JSONSerialization.c.

294 {
295
296 for (size_t i = 1; i < strlen(bytes); i++) {
297 int b = readByte(reader);
298 assert(b == bytes[i]);
299 }
300}
static int readByte(JSONReader *reader)

◆ dataFromObject()

static Data * dataFromObject ( const ident  obj,
int  options 
)
static

Definition at line 223 of file JSONSerialization.c.

223 {
224
225 if (obj) {
226 JSONWriter writer = {
227 .data = $(alloc(MutableData), init),
228 .options = options
229 };
230
231 writeObject(&writer, obj);
232
233 return (Data *) writer.data;
234 }
235
236 return NULL;
237}
#define obj
#define alloc(type)
Allocate and initialize and instance of type.
Definition: Class.h:159
static void writeObject(JSONWriter *writer, const Dictionary *object)
Writes object to writer.
Condition * init(Condition *self)
Initializes this Condition.
Definition: Condition.c:67
Immutable data buffers.
Definition: Data.h:50
A writer for generating JSON Data.
MutableData * data
Mutable data buffers.
Definition: MutableData.h:40

◆ initialize()

static void initialize ( Class clazz)
static
See also
Class::initialize(Class *)

Definition at line 501 of file JSONSerialization.c.

501 {
502
503 ((JSONSerializationInterface *) clazz->interface)->dataFromObject = dataFromObject;
504 ((JSONSerializationInterface *) clazz->interface)->objectFromData = objectFromData;
505}
ident interface
The interface of the Class.
Definition: Class.h:105
Data * dataFromObject(const ident obj, int options)
Serializes the given Object to JSON Data.
ident objectFromData(const Data *data, int options)
Parses an Object from the specified Data.

◆ objectFromData()

static ident objectFromData ( const Data data,
int  options 
)
static

Definition at line 482 of file JSONSerialization.c.

482 {
483
484 if (data && data->length) {
485 JSONReader reader = {
486 .data = data,
487 .options = options
488 };
489
490 return readElement(&reader);
491 }
492
493 return NULL;
494}
static ident readElement(JSONReader *reader)
Reads an element from reader. An element is any valid JSON type.
size_t length
The length of bytes.
Definition: Data.h:76
A reader for parsing JSON Data.
const Data * data
MutableData * data(void)
Returns a new MutableData.
Definition: MutableData.c:75

◆ readArray()

static Array * readArray ( JSONReader reader)
static

Reads an array from `reader.

Parameters
readerThe JSONReader.
Returns
The array.

Definition at line 430 of file JSONSerialization.c.

430 {
431
433
434 while (true) {
435
436 Object *obj = readElement(reader);
437 if (obj == NULL) {
438 const int b = readByteUntil(reader, "]");
439 assert(b == ']');
440 break;
441 }
442
443 $(array, addObject, obj);
444
445 release(obj);
446 }
447
448 return (Array *) array;
449}
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition: Class.c:196
static int readByteUntil(JSONReader *reader, const char *stop)
Consume bytes from reader until a byte from stop is found.
Immutable arrays.
Definition: Array.h:56
Mutable arrays.
Definition: MutableArray.h:40
void addObject(MutableArray *self, const ident obj)
Adds the specified Object to this MutableArray.
Definition: MutableArray.c:99
MutableArray * array(void)
Returns a new MutableArray.
Definition: MutableArray.c:153
Object is the root Class of The Objectively Class hierarchy.
Definition: Object.h:46

◆ readBoole()

static _Bool * readBoole ( JSONReader reader)
static

Reads a Boole from reader.

Parameters
readerThe JSONReader.
Returns
The Boole.

Definition at line 341 of file JSONSerialization.c.

341 {
342
343 Boole *boolean = NULL;
344
345 switch (*reader->b) {
346 case 't':
347 consumeBytes(reader, "true");
348 boolean = $$(Boole, True);
349 break;
350 case 'f':
351 consumeBytes(reader, "false");
352 boolean = $$(Boole, False);
353 break;
354 default:
355 assert(false);
356 }
357
358 return retain(boolean);
359}
ident retain(ident obj)
Atomically increment the given Object's reference count.
Definition: Class.c:211
static void consumeBytes(JSONReader *reader, const char *bytes)
Consumes and verifies bytes from `reader.
A wrapper for placing boolean primitives into collections, etc.
Definition: Boole.h:41
Boole * False(void)
Definition: Boole.c:59
Boole * True(void)
Definition: Boole.c:77

◆ readByte()

static int readByte ( JSONReader reader)
static
Parameters
readerThe JSONReader.
Returns
The next byte in reader, or -1 if reader is exhausted.

Definition at line 254 of file JSONSerialization.c.

254 {
255
256 if (reader->b) {
257 if (reader->b - reader->data->bytes < reader->data->length) {
258 return (int) *(++(reader->b));
259 }
260 } else {
261 if (reader->data->bytes) {
262 return (int) *(reader->b = reader->data->bytes);
263 }
264 }
265
266 return -1;
267}
uint8_t * bytes
The bytes.
Definition: Data.h:66

◆ readByteUntil()

static int readByteUntil ( JSONReader reader,
const char *  stop 
)
static

Consume bytes from reader until a byte from stop is found.

Parameters
readerThe JSONReader.
stopA sequence of stop characters.
Returns
The stop byte found, or -1 if reader is exhausted.

Definition at line 275 of file JSONSerialization.c.

275 {
276
277 int b;
278
279 while (true) {
280 b = readByte(reader);
281 if (b == -1 || strchr(stop, b)) {
282 break;
283 }
284 }
285
286 return b;
287}

◆ readElement()

static ident readElement ( JSONReader reader)
static

Reads an element from reader. An element is any valid JSON type.

Parameters
readerThe JSONReader.
Returns
The element, or NULL if no element is available.

Definition at line 456 of file JSONSerialization.c.

456 {
457
458 const int b = readByteUntil(reader, "{[\"tfn0123456789.-]}");
459 if (b == '{') {
460 return readObject(reader);
461 } else if (b == '[') {
462 return readArray(reader);
463 } else if (b == '\"') {
464 return readString(reader);
465 } else if (b == 't' || b == 'f') {
466 return readBoole(reader);
467 } else if (b == 'n') {
468 return readNull(reader);
469 } else if (b == '.' || b == '-' || isdigit(b)) {
470 return readNumber(reader);
471 } else if (b == ']' || b == '}') {
472 reader->b--;
473 }
474
475 return NULL;
476}
static _Bool * readBoole(JSONReader *reader)
Reads a Boole from reader.
static Dictionary * readObject(JSONReader *reader)
Reads an object from reader. An object is a valid JSON structure.
static String * readString(JSONReader *reader)
Reads a String from reader.
static Array * readArray(JSONReader *reader)
Reads an array from `reader.
static Number * readNumber(JSONReader *reader)
Reads a Number from reader.
static Null * readNull(JSONReader *reader)
Reads Null from Reader.

◆ readLabel()

static String * readLabel ( JSONReader reader)
static

Reads a label from reader.

Parameters
readerThe JSONReader.
Returns
The label, or NULL on error.

Definition at line 380 of file JSONSerialization.c.

380 {
381
382 const int b = readByteUntil(reader, "\"}");
383 if (b == '"') {
384 return readString(reader);
385 } if (b == '}') {
386 reader->b--;
387 }
388
389 return NULL;
390}

◆ readNull()

static Null * readNull ( JSONReader reader)
static

Reads Null from Reader.

Parameters
readerThe JSONReader.
Returns
Null.

Definition at line 366 of file JSONSerialization.c.

366 {
367
368 consumeBytes(reader, "null");
369
370 Null *null = $$(Null, null);
371
372 return retain(null);
373}
The Null sentinel.
Definition: Null.h:42
Null * null(void)
Definition: Null.c:48

◆ readNumber()

static Number * readNumber ( JSONReader reader)
static

Reads a Number from reader.

Parameters
readerThe JSONReader.
Returns
The Number.

Definition at line 323 of file JSONSerialization.c.

323 {
324
325 uint8_t *bytes = reader->b;
326
327 uint8_t *end;
328 double d = strtod((char *) bytes, (char **) &end);
329
330 assert(end > bytes);
331 reader->b = end - 1;
332
333 return $$(Number, numberWithValue, d);
334}
A wrapper for placing numeric primitives into collections, etc.
Definition: Number.h:41
Number * numberWithValue(double value)
Returns a new Number with the given value.
Definition: Number.c:159

◆ readObject()

static Dictionary * readObject ( JSONReader reader)
static

Reads an object from reader. An object is a valid JSON structure.

Parameters
readerThe JSONReader.
Returns
The object.

Definition at line 397 of file JSONSerialization.c.

397 {
398
400
401 while (true) {
402
403 String *key = readLabel(reader);
404 if (key == NULL) {
405 const int b = readByteUntil(reader, "}");
406 assert(b == '}');
407 break;
408 }
409
410 const int b = readByteUntil(reader, ":");
411 assert(b == ':');
412
413 ident obj = readElement(reader);
414 assert(obj);
415
416 $(object, setObjectForKey, obj, key);
417
418 release(key);
419 release(obj);
420 }
421
422 return (Dictionary *) object;
423}
static String * readLabel(JSONReader *reader)
Reads a label from reader.
void * ident
The identity type, similar to Objective-C id.
Definition: Types.h:49
Immutable key-value stores.
Definition: Dictionary.h:60
Mutable key-value stores.
void setObjectForKey(MutableDictionary *self, const ident obj, const ident key)
Sets a pair in this MutableDictionary.
Immutable UTF-8 strings.
Definition: String.h:69

◆ readString()

static String * readString ( JSONReader reader)
static

Reads a String from reader.

Parameters
readerThe JSONReader.
Returns
The String.

Definition at line 307 of file JSONSerialization.c.

307 {
308
309 uint8_t *bytes = reader->b;
310
311 const int b = readByteUntil(reader, "\"");
312 assert(b == '"');
313
314 const size_t length = reader->b - bytes - 1;
315 return $$(String, stringWithBytes, bytes + 1, length, STRING_ENCODING_UTF8);
316}
@ STRING_ENCODING_UTF8
Definition: String.h:53
String * stringWithBytes(const uint8_t *bytes, size_t length, StringEncoding encoding)
Returns a new String by decoding length of bytes to UTF-8.
Definition: String.c:478

◆ writeArray()

static void writeArray ( JSONWriter writer,
const Array array 
)
static

Writes array to writer.

Parameters
writerThe JSONWriter.
arrayThe Array to write.

Definition at line 172 of file JSONSerialization.c.

172 {
173
174 $(writer->data, appendBytes, (uint8_t * ) "[", 1);
175 writer->depth++;
176
177 for (size_t i = 0; i < array->count; i++) {
178
179 writePretty(writer);
180
181 writeElement(writer, $(array, objectAtIndex, i));
182
183 if (i < array->count - 1) {
184 $(writer->data, appendBytes, (uint8_t *) ",", 1);
185 }
186 }
187
188 writer->depth--;
189 writePretty(writer);
190
191 $(writer->data, appendBytes, (uint8_t * ) "]", 1);
192}
static void writePretty(JSONWriter *writer)
Writes pretty formatting, if applicable, to writer.
static void writeElement(JSONWriter *writer, const ident obj)
Writes the specified JSON element to writer.
ident objectAtIndex(const Array *self, int index)
size_t count
The count of elements.
Definition: Array.h:72
void appendBytes(MutableData *self, const uint8_t *bytes, size_t length)
Appends the given bytes to this Data.
Definition: MutableData.c:53

◆ writeBoole()

static void writeBoole ( JSONWriter writer,
const Boole boolean 
)
static

Writes boolean to writer.

Parameters
writerThe JSONWriter.
booleanThe Boole to write.

Definition at line 67 of file JSONSerialization.c.

67 {
68
69 if (boolean->value) {
70 $(writer->data, appendBytes, (uint8_t *) "true", 4);
71 } else {
72 $(writer->data, appendBytes, (uint8_t *) "false", 5);
73 }
74}
_Bool value
The backing _Bool.
Definition: Boole.h:57

◆ writeElement()

static void writeElement ( JSONWriter writer,
const ident  obj 
)
static

Writes the specified JSON element to writer.

Parameters
writerThe JSONWriter.
objThe JSON element to write.

Definition at line 199 of file JSONSerialization.c.

199 {
200
201 const Object *object = cast(Object, obj);
202 if (object) {
203 if ($(object, isKindOfClass, _Dictionary())) {
204 writeObject(writer, (const Dictionary *) object);
205 } else if ($(object, isKindOfClass, _Array())) {
206 writeArray(writer, (const Array *) object);
207 } else if ($(object, isKindOfClass, _String())) {
208 writeString(writer, (const String *) object);
209 } else if ($(object, isKindOfClass, _Number())) {
210 writeNumber(writer, (const Number *) object);
211 } else if ($(object, isKindOfClass, _Boole())) {
212 writeBoole(writer, (const Boole *) object);
213 } else if ($(object, isKindOfClass, _Null())) {
214 writeNull(writer, (const Null *) object);
215 }
216 }
217}
#define cast(type, obj)
Safely cast obj to type.
Definition: Class.h:165
static void writeNull(JSONWriter *writer, const Null *null)
Writes null to writer.
static void writeString(JSONWriter *writer, const String *string)
Writes string to writer.
static void writeNumber(JSONWriter *writer, const Number *number)
Writes number to writer.
static void writeBoole(JSONWriter *writer, const Boole *boolean)
Writes boolean to writer.
static void writeArray(JSONWriter *writer, const Array *array)
Writes array to writer.
Class * _Array(void)
The Array archetype.
Definition: Array.c:470
Class * _Boole(void)
The Boole archetype.
Definition: Boole.c:125
Class * _Dictionary(void)
The Dictionary archetype.
Definition: Dictionary.c:451
Class * _Null(void)
The Null archetype.
Definition: Null.c:83
Class * _Number(void)
The Number archetype.
Definition: Number.c:198
_Bool isKindOfClass(const Object *self, const Class *clazz)
Tests for Class hierarchy membership.
Definition: Object.c:101
Class * _String(void)
The String archetype.
Definition: String.c:654

◆ writeLabel()

static void writeLabel ( JSONWriter writer,
const String label 
)
static

Writes the label (field name) label to writer.

Parameters
writerThe JSONWriter.
labelThe label to write.

Definition at line 107 of file JSONSerialization.c.

107 {
108
109 writeString(writer, label);
110 $(writer->data, appendBytes, (uint8_t *) ": ", 2);
111}

◆ writeNull()

static void writeNull ( JSONWriter writer,
const Null null 
)
static

Writes null to writer.

Parameters
writerThe JSONWriter.
nullThe Null to write.

Definition at line 57 of file JSONSerialization.c.

57 {
58
59 $(writer->data, appendBytes, (uint8_t *) "null", 4);
60}

◆ writeNumber()

static void writeNumber ( JSONWriter writer,
const Number number 
)
static

Writes number to writer.

Parameters
writerThe JSONWriter.
numberThe Number to write.

Definition at line 93 of file JSONSerialization.c.

93 {
94
95 String *string = $(alloc(String), initWithFormat, "%g", number->value);
96
97 $(writer->data, appendBytes, (uint8_t *) string->chars, string->length);
98
99 release(string);
100}
DateFormatter * initWithFormat(DateFormatter *self, const char *fmt)
Initializes a DateFormatter with the specified format string.
Definition: DateFormatter.c:76
MutableString * string(void)
Returns a new MutableString.
double value
The backing value.
Definition: Number.h:57
char * chars
The backing null-terminated UTF-8 encoded character array.
Definition: String.h:85
size_t length
The length of the String in bytes.
Definition: String.h:90

◆ writeObject()

static void writeObject ( JSONWriter writer,
const Dictionary object 
)
static

Writes object to writer.

Parameters
writerThe JSONWriter.
objectThe object (Dictionary) to write.

Definition at line 132 of file JSONSerialization.c.

132 {
133
134 $(writer->data, appendBytes, (uint8_t * ) "{", 1);
135 writer->depth++;
136
137 Array *keys = $(object, allKeys);
138 if (writer->options & JSON_WRITE_SORTED) {
139 Array *sorted = $(keys, sortedArray, StringCompare);
140 release(keys);
141 keys = sorted;
142 }
143
144 for (size_t i = 0; i < keys->count; i++) {
145
146 writePretty(writer);
147
148 const ident key = $(keys, objectAtIndex, i);
149 writeLabel(writer, (String *) key);
150
151 const ident obj = $(object, objectForKey, key);
152 writeElement(writer, obj);
153
154 if (i < keys->count - 1) {
155 $(writer->data, appendBytes, (uint8_t *) ",", 1);
156 }
157 }
158
159 release(keys);
160
161 writer->depth--;
162 writePretty(writer);
163
164 $(writer->data, appendBytes, (uint8_t * ) "}", 1);
165}
static void writeLabel(JSONWriter *writer, const String *label)
Writes the label (field name) label to writer.
@ JSON_WRITE_SORTED
Enables lexicographic sorting of JSON output.
Array * sortedArray(const Array *self, Comparator comparator)
Definition: Array.c:420
Array * allKeys(const Dictionary *self)
Definition: Dictionary.c:169
ident objectForKey(const Dictionary *self, const ident key)
Definition: Dictionary.c:382
OBJECTIVELY_EXPORT Order StringCompare(const ident a, const ident b)
A Comparator for sorting Strings.
Definition: String.c:721

◆ writePretty()

static void writePretty ( JSONWriter writer)
static

Writes pretty formatting, if applicable, to writer.

Parameters
writerThe JSONWriter.

Definition at line 117 of file JSONSerialization.c.

117 {
118
119 if (writer->options & JSON_WRITE_PRETTY) {
120 $(writer->data, appendBytes, (uint8_t *) "\n", 1);
121 for (size_t i = 0; i < writer->depth; i++) {
122 $(writer->data, appendBytes, (uint8_t *) " ", 2);
123 }
124 }
125}
@ JSON_WRITE_PRETTY
Enables pretty (indented) formatting of JSON output.

◆ writeString()

static void writeString ( JSONWriter writer,
const String string 
)
static

Writes string to writer.

Parameters
writerThe JSONWriter.
stringThe String to write.

Definition at line 81 of file JSONSerialization.c.

81 {
82
83 $(writer->data, appendBytes, (uint8_t *) "\"", 1);
84 $(writer->data, appendBytes, (uint8_t *) string->chars, string->length);
85 $(writer->data, appendBytes, (uint8_t *) "\"", 1);
86}