{"id":13741266,"url":"https://github.com/rdpoor/jemi","last_synced_at":"2025-05-08T21:33:04.376Z","repository":{"id":69792714,"uuid":"545149664","full_name":"rdpoor/jemi","owner":"rdpoor","description":"jemi: a compact, trusting, JSON serializer with static allocation in pure C for embedded systems","archived":false,"fork":false,"pushed_at":"2023-08-03T13:34:20.000Z","size":50,"stargazers_count":19,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-08-04T04:07:36.604Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rdpoor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-10-03T21:44:26.000Z","updated_at":"2024-03-26T13:05:43.000Z","dependencies_parsed_at":"2023-07-11T01:31:49.036Z","dependency_job_id":null,"html_url":"https://github.com/rdpoor/jemi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdpoor%2Fjemi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdpoor%2Fjemi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdpoor%2Fjemi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdpoor%2Fjemi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rdpoor","download_url":"https://codeload.github.com/rdpoor/jemi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224774724,"owners_count":17367783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T04:00:57.342Z","updated_at":"2024-11-15T11:31:04.023Z","avatar_url":"https://github.com/rdpoor.png","language":"C","funding_links":[],"categories":["C Libraries"],"sub_categories":["JSON"],"readme":"# jemi\njemi: a compact, pure-C JSON serializer for embedded systems\n\n## Overview\n\n`jemi` makes it easy to construct complex JSON structures and then emit them\nto a buffer, a string or a stream.  Designed specifically for embedded systems,\n`jemi` is:\n* **compact**: one source file and one header file\n* **portable**: written in pure C\n* **deterministic**: `jemi` uses user-provided data structures and never calls\n`malloc()`.\n* **yours to use**: `jemi` is covered under the permissive MIT License.\n\n`jemi` derives much of its efficiency and small footprint by a philosophy of\ntrust: Rather than provide rigorous error checking of input parameters,\n`jemi` instead assumes that you provide valid parameters to function calls.\n\n\n## A Short Example\n\n\n`jemi` provides two styles for building JSON structures.  The \"all in one\" style\nshown in jemi_example1() lets you use C syntax that parallels the resulting JSON\nstructure.  The \"piecewise\" style shown in jemi_example2() shows how you can\npre-build pieces of JSON structure to be emitted later.  Both examples emit the\nsame results.\n\n```\n#include \"jemi.h\"\n#include \u003cstdio.h\u003e\n\n#define JEMI_NODES_MAX 30\nstatic jemi_node_t node_pool[JEMI_NODES_MAX];\n\n/**\n * Using the \"all in one\" constructors to create a compound JSON structure.\n */\nvoid jemi_example1(void) {\n    jemi_init(node_pool, JEMI_NODES_MAX);\n\n    jemi_node_t *root =\n        jemi_object(\n            jemi_string(\"colors\"),\n            jemi_object(\n                jemi_string(\"yellow\"),\n                jemi_array(jemi_integer(255), jemi_integer(255), jemi_integer(0), NULL),\n                jemi_string(\"cyan\"),\n                jemi_array(jemi_integer(0), jemi_integer(255), jemi_integer(255), NULL),\n                jemi_string(\"magenta\"),\n                jemi_array(jemi_integer(255), jemi_integer(0), jemi_integer(255), NULL),\n                NULL),\n            NULL);\n    jemi_emit(root, (void (*)(char))putchar); // casting avoids compiler warning\n    putchar('\\n');\n}\n\n/**\n * Using the \"append\" functions to piecewise build a compound JSON structure.\n */\nvoid jemi_example2(void) {\n    jemi_node_t *root, *dict, *rgb;\n\n    jemi_init(node_pool, JEMI_NODES_MAX);\n\n    // build from the inside out...\n    root = jemi_object(NULL);\n    jemi_object_append(root, jemi_list(jemi_string(\"colors\"), dict = jemi_object(NULL), NULL));\n    jemi_object_append(dict, jemi_list(jemi_string(\"yellow\"), rgb = jemi_array(NULL), NULL));\n    jemi_array_append(rgb, jemi_list(jemi_integer(255), jemi_integer(255), jemi_integer(0), NULL));\n    jemi_object_append(dict, jemi_list(jemi_string(\"cyan\"), rgb = jemi_array(NULL), NULL));\n    jemi_array_append(rgb, jemi_list(jemi_integer(0), jemi_integer(255), jemi_integer(255), NULL));\n    jemi_object_append(dict, jemi_list(jemi_string(\"magenta\"), rgb = jemi_array(NULL), NULL));\n    jemi_array_append(rgb, jemi_list(jemi_integer(255), jemi_integer(0), jemi_integer(255), NULL));\n\n    jemi_emit(root, (void (*)(char))putchar); // casting avoids compiler warning\n    putchar('\\n');\n}\n\nint main(void) {\n    jemi_example1();\n    jemi_example2();\n}\n```\n\nBoth `example1()` and `example2()` output the same JSON, which (when formatted\nfor redability) looks like this:\n\n```\n{\n   \"colors\":{\n      \"yellow\":[\n         255,\n         255,\n         0\n      ],\n      \"cyan\":[\n         0,\n         255,\n         255\n      ],\n      \"magenta\":[\n         255,\n         0,\n         255\n      ]\n   }\n}\n```\n\n## Advanced Example\n\nSuppose you know the overall JSON structure that you're going to use, but you\nwant to dynamically add data to various nodes within the structure before\nemitting it.  \n\njemi handles this case for you with the following features;\n* jemi_copy() makes a copy of any jemi structure (or substructure)\n* jemi_list() lets you create a \"disembodied list\" of items that can be\nappended to the body of a jemi_list or jemi_object via jemi_array_append()\nand jemi_object_append().\n* jemi_xxx_set() lets you update the value of a string, boolean or number node.\n* The C syntax `a = fn()` evaluates `fn()` and assigns it to `a` and the entire\nexpression evaluates to that value.  As shown in the example below, you can\nexploit this to save references to jemi sub-expressions in the JSON structure.\n\nThe result isn't especially pretty, but in practice, you'd create bespoke\nfunctions to fill in and copy your templates and to insert them into your\noverall structure.\n\n```\njemi_node_t *snippet_template, *snippets, *color_map, *color_name, *colors,\n            *red_val, *grn_val, *blu_val;\n\n// create a snippet that will be used as a key/value pair in an object.\nsnippet_template =\n    jemi_list(\n        color_name = jemi_string(\"color_name\"),\n        jemi_array(red_val=jemi_integer(0),\n                   grn_val=jemi_integer(0),\n                   blu_val=jemi_integer(0),\n                   NULL),\n        NULL);\n\n// Define the overall JSON structure for our color map\ncolor_map =\n    jemi_object(\n        colors = jemi_string(\"colors\"),\n        snippets = jemi_object(NULL),\n        NULL);\nASSERT(renders_as(color_map, \"{\\\"colors\\\":{}}\"));\n\n// customize template for yellow and add a copy to the \"snippets\" sub-structure\njemi_string_set(color_name, \"yellow\");\njemi_integer_set(red_val, 255);\njemi_integer_set(grn_val, 255);\njemi_integer_set(blu_val, 0);\njemi_object_append(snippets, jemi_copy(snippet_template));\nASSERT(renders_as(color_map, \"{\\\"colors\\\":{\"\n                                  \"\\\"yellow\\\":[255,255,0]\"\n                                  \"}}\"));\n\n// customize template for cyan and add a copy to the \"snippets\" sub-structure\njemi_string_set(color_name, \"cyan\");\njemi_integer_set(red_val, 0);\njemi_integer_set(grn_val, 255);\njemi_integer_set(blu_val, 255);\njemi_object_append(snippets, jemi_copy(snippet_template));\nASSERT(renders_as(color_map, \"{\\\"colors\\\":{\"\n                             \"\\\"yellow\\\":[255,255,0],\"\n                             \"\\\"cyan\\\":[0,255,255]\"\n                             \"}}\"));\n\n// customize template for magenta and add a copy to the \"snippets\" sub-structure\njemi_string_set(color_name, \"magenta\");\njemi_integer_set(red_val, 255);\njemi_integer_set(grn_val, 0);\njemi_integer_set(blu_val, 255);\njemi_object_append(snippets, jemi_copy(snippet_template));\nASSERT(renders_as(color_map, \"{\\\"colors\\\":{\"\n                             \"\\\"yellow\\\":[255,255,0],\"\n                             \"\\\"cyan\\\":[0,255,255],\"\n                             \"\\\"magenta\\\":[255,0,255]\"\n                             \"}}\"));\n\n```\n\n## No Guard Rails\n\njemi trusts that you know what you're doing and that you'll pass valid arguments\nto the functions.  As such, jemi does very little error checking.  If your\napp warrants additional error checking, by all means, write wrappers around the\njemi functions to perform whatever level of safety you need.\n\nWith that said, there are a few things to keep in mind:\n\n* Don't forget to pass NULL as the last argument to `jemi_array()`,\n`jemi_object()`, or `jemi_list()`.  Failure to do so will almost certainly\nresult in some sort of segfault.\n* Calling `jemi_float_set()` on a node that's not a number will lead to\nunexpected results.  Ditto for integer, string and boolean.\n* Calling `jemi_array_append()` on a node that's not an array will lead to\nunexpected results.  Ditto for `jemi_object_append()`.  However, it is okay\nto call `jemi_list_append()` on any jemi node type or NULL.\n* The JSON spec requires that each key of a key/value pair in an object is a\nstring.  However, `jemi_object()` does not enforce this: you can use any jemi\nobject as a key.  Furthermore, it does not check to see that every key has a\ncorresponding value.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frdpoor%2Fjemi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frdpoor%2Fjemi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frdpoor%2Fjemi/lists"}