Convert between JSON, DUST, EDN and TRON with the library's parse and serialize operations, through the C ABI or any binding.
Serialization writes a document as text, or as binary bytes for TRON.
The example parses the people document and serializes it in the same format.
people_text holds this document:
TRON449 B
Offset (hex) Bytes (hex) Meaning 000 54 52 4F 4E magic TRON 004 3C 616765 txt "age" 008 02 24000000000000
00 i64 36 011 0F 0A 04000000 0800
0000 map leaf, size 10: @4 → @8 01B 4C 726F6C65 txt "role" 020 8C 656E67696E6565
72 txt "engineer" 029 0F 0A 1B000000 2000
0000 map leaf, size 10: @1B → @20 033 4C 6E616D65 txt "name" 038 3C 416461 txt "Ada" 03C 0F 0A 33000000 3800
0000 map leaf, size 10: @33 → @38 046 07 12 00910000 1100
0000 29000000 3C00
0000 map branch, size 18, depth 0 (root), slots 8, 12, 15: @11 → @29 → @3C 058 5C 236C696E6B txt "#link" 05E 5C 235F616461 txt "#_ada" 064 0F 0A 58000000 5E00
0000 map leaf, size 10: @58 → @5E 06E 3C 616765 txt "age" 072 02 29000000000000
00 i64 41 07B 0F 0A 6E000000 7200
0000 map leaf, size 10: @6E → @72 085 6C 6D656E746F72 txt "mentor" 08C 0F 0A 85000000 6400
0000 map leaf, size 10: @85 → @64 096 4C 726F6C65 txt "role" 09B 8C 656E67696E6565
72 txt "engineer" 0A4 0F 0A 96000000 9B00
0000 map leaf, size 10: @96 → @9B 0AE 4C 6E616D65 txt "name" 0B3 3C 426F62 txt "Bob" 0B7 0F 0A AE000000 B300
0000 map leaf, size 10: @AE → @B3 0C1 07 16 00990000 7B00
0000 8C000000 A400
0000 B7000000 map branch, size 22, depth 0 (root), slots 8, 11, 12, 15: @7B → @8C → @A4 → @B7 0D7 3C 616765 txt "age" 0DB 02 1D000000000000
00 i64 29 0E4 0F 0A D7000000 DB00
0000 map leaf, size 10: @D7 → @DB 0EE 4C 726F6C65 txt "role" 0F3 8C 64657369676E65
72 txt "designer" 0FC 0F 0A EE000000 F300
0000 map leaf, size 10: @EE → @F3 106 4C 6E616D65 txt "name" 10B 2C 4379 txt "Cy" 10E 0F 0A 06010000 0B01
0000 map leaf, size 10: @106 → @10B 118 07 12 00910000 E400
0000 FC000000 0E01
0000 map branch, size 18, depth 0 (root), slots 8, 12, 15: @E4 → @FC → @10E 12A 6C 617574686F72 txt "author" 131 5C 736D6F6B65 txt "smoke" 137 0F 0A 2A010000 3101
0000 map leaf, size 10: @12A → @131 141 6C 726561736F6E txt "reason" 148 4C 73656564 txt "seed" 14D 0F 0A 41010000 4801
0000 map leaf, size 10: @141 → @148 157 07 0E 40080000 3701
0000 4D010000 map branch, size 14, depth 0 (root), slots 6, 11: @137 → @14D 165 4C 235F7478 txt "#_tx" 16A 0F 0A 65010000 5701
0000 map leaf, size 10: @165 → @157 174 4C 235F6379 txt "#_cy" 179 0F 0A 74010000 1801
0000 map leaf, size 10: @174 → @118 183 5C 235F626F62 txt "#_bob" 189 0F 0A 83010000 C100
0000 map leaf, size 10: @183 → @C1 193 5C 235F616461 txt "#_ada" 199 0F 0A 93010000 4600
0000 map leaf, size 10: @193 → @46 1A3 07 16 88210000 6A01
0000 79010000 8901
0000 99010000 map branch, size 22, depth 0 (root), slots 3, 7, 8, 13: @16A → @179 → @189 → @199
rust 159 B
let people = stardust:: parse ( people_text, Format :: TRON ) ?;
let output = people. serialize ( Format :: TRON , 0 ) ?;
let result = stardust:: parse ( output, Format :: TRON ) ?;
TRON449 B
Offset (hex) Bytes (hex) Meaning 000 54 52 4F 4E magic TRON 004 6C 617574686F72 txt "author" 00B 5C 736D6F6B65 txt "smoke" 011 0F 0A 04000000 0B00
0000 map leaf, size 10: @4 → @B 01B 6C 726561736F6E txt "reason" 022 4C 73656564 txt "seed" 027 0F 0A 1B000000 2200
0000 map leaf, size 10: @1B → @22 031 07 0E 40080000 1100
0000 27000000 map branch, size 14, depth 0 (root), slots 6, 11: @11 → @27 03F 3C 616765 txt "age" 043 02 1D000000000000
00 i64 29 04C 0F 0A 3F000000 4300
0000 map leaf, size 10: @3F → @43 056 4C 726F6C65 txt "role" 05B 8C 64657369676E65
72 txt "designer" 064 0F 0A 56000000 5B00
0000 map leaf, size 10: @56 → @5B 06E 4C 6E616D65 txt "name" 073 2C 4379 txt "Cy" 076 0F 0A 6E000000 7300
0000 map leaf, size 10: @6E → @73 080 07 12 00910000 4C00
0000 64000000 7600
0000 map branch, size 18, depth 0 (root), slots 8, 12, 15: @4C → @64 → @76 092 5C 236C696E6B txt "#link" 098 5C 235F616461 txt "#_ada" 09E 0F 0A 92000000 9800
0000 map leaf, size 10: @92 → @98 0A8 3C 616765 txt "age" 0AC 02 29000000000000
00 i64 41 0B5 0F 0A A8000000 AC00
0000 map leaf, size 10: @A8 → @AC 0BF 6C 6D656E746F72 txt "mentor" 0C6 0F 0A BF000000 9E00
0000 map leaf, size 10: @BF → @9E 0D0 4C 726F6C65 txt "role" 0D5 8C 656E67696E6565
72 txt "engineer" 0DE 0F 0A D0000000 D500
0000 map leaf, size 10: @D0 → @D5 0E8 4C 6E616D65 txt "name" 0ED 3C 426F62 txt "Bob" 0F1 0F 0A E8000000 ED00
0000 map leaf, size 10: @E8 → @ED 0FB 07 16 00990000 B500
0000 C6000000 DE00
0000 F1000000 map branch, size 22, depth 0 (root), slots 8, 11, 12, 15: @B5 → @C6 → @DE → @F1 111 3C 616765 txt "age" 115 02 24000000000000
00 i64 36 11E 0F 0A 11010000 1501
0000 map leaf, size 10: @111 → @115 128 4C 726F6C65 txt "role" 12D 8C 656E67696E6565
72 txt "engineer" 136 0F 0A 28010000 2D01
0000 map leaf, size 10: @128 → @12D 140 4C 6E616D65 txt "name" 145 3C 416461 txt "Ada" 149 0F 0A 40010000 4501
0000 map leaf, size 10: @140 → @145 153 07 12 00910000 1E01
0000 36010000 4901
0000 map branch, size 18, depth 0 (root), slots 8, 12, 15: @11E → @136 → @149 165 4C 235F7478 txt "#_tx" 16A 0F 0A 65010000 3100
0000 map leaf, size 10: @165 → @31 174 4C 235F6379 txt "#_cy" 179 0F 0A 74010000 8000
0000 map leaf, size 10: @174 → @80 183 5C 235F626F62 txt "#_bob" 189 0F 0A 83010000 FB00
0000 map leaf, size 10: @183 → @FB 193 5C 235F616461 txt "#_ada" 199 0F 0A 93010000 5301
0000 map leaf, size 10: @193 → @153 1A3 07 16 88210000 6A01
0000 79010000 8901
0000 99010000 map branch, size 22, depth 0 (root), slots 3, 7, 8, 13: @16A → @179 → @189 → @199
Warning
A format can change number spelling, member order, or tagged values. Check the fidelity table before you depend on them.
EDN symbols such as ?name parse as native strings. Serialization writes a native string such as "?name" as the EDN symbol ?name. The string must start with ?, contain a name, and form one valid EDN symbol token. Other string values remain quoted.
Query variables therefore keep their symbol form through EDN, JSON, DUST and TRON conversions. Clojure users can quote a query map to pass its symbols as data:
clojure 204 B
(with-open [query (sd/from-value
' {:find [?name ?age]
:where [[?e :name ?name] [?e :age ?age]]
:orderBy [?name]})]
(sd/serialize query :edn ))
An object on one line, {op a args {t 1} e 1}, separates its members with whitespace. A top-level document, and any object that spans lines, holds exactly one member per line, and the rest of the line is the value of that member:
text 34 B
{name Ada Lovelace
role engineer}
This object is {"name":"Ada Lovelace","role":"engineer"}. In a multi-line object, {op a args 1 is the member op with the string a args 1. A line that cannot be one bare value, such as {op a args {t 1}, fails with Members_On_One_Line and the offset of its second key. Start each member on its own line, or keep the whole object on one line. Serialization never writes several members on one line of a multi-line object.
rust 70 B
pub fn serialize ( & self , format : Format , width : i64 ) -> Result < Vec < u8 >>
Close consumes this owner. Rust ownership prevents later access. Thus, the safe API does not report closed for this receiver.
source_text holds this document:
TRON47 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 1C 2B txt "+" 06 2C 3F78 txt "?x" 09 02 01000000000000
00 i64 1 12 0E 15 00 0700 030000
00 04000000 060000
00 09000000 array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @4 → @6 → @9
rust 106 B
let source = stardust:: parse ( source_text, Format :: TRON ) ?;
let result = source. serialize ( Format :: TRON , 0 ) ?;
TRON76 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 4C 74657874 txt "text" 09 14 2F 54524F4E1C2B
2C3F780201000000
000000000E150007
0003000000040000
0006000000090000
0012000000000000
00 txt "TRON\u001C+,?x\u0002\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000E\u0015\u0000\u0007\u0000\u0003…" 3A 0F 0A 04000000 0900
0000 map leaf, size 10: @4 → @9
source_text holds this document:
TRON21 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 02 01000000000000
00 i64 1
rust 106 B
let source = stardust:: parse ( source_text, Format :: TRON ) ?;
let result = source. serialize ( Format :: TRON , 0 ) ?;
TRON50 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 4C 74657874 txt "text" 09 14 15 54524F4E0201
0000000000000004
00000000000000 txt "TRON\u0002\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0004\u0000\u0000\u0000\u0000\u0000\u0000\u0000" 20 0F 0A 04000000 0900
0000 map leaf, size 10: @4 → @9
source_text holds this document:
TRON16 B
Offset (hex) Bytes (hex) Meaning 0 54 52 4F 4E magic TRON 4 3C 416461 txt "Ada"
rust 106 B
let source = stardust:: parse ( source_text, Format :: TRON ) ?;
let result = source. serialize ( Format :: TRON , 0 ) ?;
TRON45 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 4C 74657874 txt "text" 09 14 10 54524F4E3C41
6461040000000000
0000 txt "TRON<Ada\u0004\u0000\u0000\u0000\u0000\u0000\u0000\u0000" 1B 0F 0A 04000000 0900
0000 map leaf, size 10: @4 → @9
source_text holds this document:
TRON47 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 1C 2B txt "+" 06 2C 3F78 txt "?x" 09 02 01000000000000
00 i64 1 12 0E 15 00 0700 030000
00 04000000 060000
00 09000000 array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @4 → @6 → @9
rust 106 B
let source = stardust:: parse ( source_text, Format :: TRON ) ?;
let result = source. serialize ( Format :: TRON , 0 ) ?;
TRON76 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 4C 74657874 txt "text" 09 14 2F 54524F4E1C2B
2C3F780201000000
000000000E150007
0003000000040000
0006000000090000
0012000000000000
00 txt "TRON\u001C+,?x\u0002\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000E\u0015\u0000\u0007\u0000\u0003…" 3A 0F 0A 04000000 0900
0000 map leaf, size 10: @4 → @9
source_text holds this document:
TRON47 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 1C 2B txt "+" 06 2C 3F78 txt "?x" 09 02 01000000000000
00 i64 1 12 0E 15 00 0700 030000
00 04000000 060000
00 09000000 array leaf, size 21, shift 0, bitmap 0007, count 3 (root): @4 → @6 → @9
rust 106 B
let source = stardust:: parse ( source_text, Format :: TRON ) ?;
let result = source. serialize ( Format :: TRON , 0 ) ?;
TRON76 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 4C 74657874 txt "text" 09 14 2F 54524F4E1C2B
2C3F780201000000
000000000E150007
0003000000040000
0006000000090000
0012000000000000
00 txt "TRON\u001C+,?x\u0002\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000E\u0015\u0000\u0007\u0000\u0003…" 3A 0F 0A 04000000 0900
0000 map leaf, size 10: @4 → @9
C exports: stardust_serialize , stardust_text_data , stardust_text_error , stardust_text_release
rust 95 B
pub fn convert ( text : impl AsRef <[ u8 ]> , from : Format , to : Format , width : i64 ) -> Result < Vec < u8 >>
expression holds these bytes:
text 278 B
// One expression built once and evaluated against several inputs. The
// evaluate examples load this file, build `expression`, evaluate it with each
// of `inputs` in order and compare each result with `expected`.
expression [+ ?x 1]
inputs [{x 1} {x 41}]
expected [2 42]
rust 75 B
let result = stardust:: convert ( expression, Format :: DUST , Format :: TRON , 0 ) ?;
TRON497 B
Offset (hex) Bytes (hex) Meaning 000 54 52 4F 4E magic TRON 004 5C 6279746573 txt "bytes" 00A 25 D201 54524F4E1C
2B2C3F7802010000
00000000000E1500
0700030000000400
0000060000000900
00001C7802010000
00000000000F0A27
000000290000001C
7802290000000000
00000F0A3C000000
3E0000000E110003
0002000000320000
0047000000020200
000000000000022A
000000000000000E
1100030002000000
620000006B000000
8C24636F6D6D656E
7414CD4F6E652065
787072657373696F
6E206275696C7420
6F6E636520616E64
206576616C756174
656420616761696E
7374207365766572
616C20696E707574
732E205468650A65
76616C7561746520
6578616D706C6573
206C6F6164207468
69732066696C652C
206275696C642060
6578707265737369
6F6E602C20657661
6C75617465206974
2077697468206561
63680A6F66206069
6E70757473602069
6E206F7264657220
616E6420636F6D70
6172652065616368
20726573756C7420
7769746820606578
706563746564602E
0F0A850000008E00
00006C696E707574
730F0A6701000051
0000008C65787065
637465640F0A7801
000074000000070E
020100006E010000
81010000070A0100
00008B010000AC65
787072657373696F
6E0F0AA301000012
0000000712400900
005D010000990100
00AE010000B80100
0000000000 bin, length 466 1DF 0F 0A 04000000 0A00
0000 map leaf, size 10: @4 → @A
edn_text holds this document:
TRON24 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 BC 7B3A612031203A
6120327D txt "{:a 1 :a 2}"
rust 150 B
let edn = stardust:: parse ( edn_text, Format :: TRON ) ?;
let output = edn. read ( edn. root () ?) ?. text ;
let result = stardust:: parse ( output, Format :: EDN ) . err () ;
TRON254 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 6C 737461747573 txt "status" 0B 14 10 696E76616C69
645F617267756D65
6E74 txt "invalid_argument" 1D 0F 0A 04000000 0B00
0000 map leaf, size 10: @4 → @B 27 6C 656E74697479 txt "entity" 2E 00 nil 2F 0F 0A 27000000 2E00
0000 map leaf, size 10: @27 → @2E 39 7C 6D657373616765 txt "message" 41 14 27 696E76616C69
642045444E202844
75706C6963617465
5F4B657929206174
206F666673657420
36 txt "invalid EDN (Duplicate_K…" 6A 0F 0A 39000000 4100
0000 map leaf, size 10: @39 → @41 74 07 0E 08020000 2F00
0000 6A000000 map branch, size 14, depth 1, slots 3, 9: @2F → @6A 82 4C 70617468 txt "path" 87 00 nil 88 0F 0A 82000000 8700
0000 map leaf, size 10: @82 → @87 92 5C 6669656C64 txt "field" 98 00 nil 99 0F 0A 92000000 9800
0000 map leaf, size 10: @92 → @98 A3 4C 636F6465 txt "code" A8 BC 696E76616C6964
5F65646E txt "invalid_edn" B4 0F 0A A3000000 A800
0000 map leaf, size 10: @A3 → @A8 BE 6C 6F6666736574 txt "offset" C5 02 06000000000000
00 i64 6 CE 0F 0A BE000000 C500
0000 map leaf, size 10: @BE → @C5 D8 07 1E 51620000 1D00
0000 74000000 8800
0000 99000000 B400
0000 CE000000 map branch, size 30, depth 0 (root), slots 0, 4, 6, 9, 13, 14: @1D → @74 → @88 → @99 → @B4 → @CE
instant_text holds this document:
TRON49 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 4C 23757463 txt "#utc" 09 14 14 323032362D31
302D30375431323A
33343A35365A txt "2026-10-07T12:34:56Z" 1F 0F 0A 04000000 0900
0000 map leaf, size 10: @4 → @9
rust 108 B
let instant = stardust:: parse ( instant_text, Format :: TRON ) ?;
let result = instant. serialize ( Format :: EDN , 0 ) ?;
TRON57 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 4C 74657874 txt "text" 09 14 1C 23696E737420
22323032362D3130
2D30375431323A33
343A35365A22 txt "#inst \"2026-10-07T12:34:…" 27 0F 0A 04000000 0900
0000 map leaf, size 10: @4 → @9
source_text holds this document:
TRON34 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 02 01000000000000
00 i64 1 0D 0E 0D 00 0100 010000
00 04000000 array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @4
rust 159 B
let source = stardust:: parse ( source_text, Format :: TRON ) ?;
let output = source. serialize ( Format :: TRON , 0 ) ?;
let result = stardust:: parse ( output, Format :: TRON ) ?;
TRON34 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 02 01000000000000
00 i64 1 0D 0E 0D 00 0100 010000
00 04000000 array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @4
source_text holds this document:
TRON68 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 1C 61 txt "a" 06 02 01000000000000
00 i64 1 0F 0F 0A 04000000 0600
0000 map leaf, size 10: @4 → @6 19 1C 7A txt "z" 1B 02 02000000000000
00 i64 2 24 0F 0A 19000000 1B00
0000 map leaf, size 10: @19 → @1B 2E 07 0E 40400000 0F00
0000 24000000 map branch, size 14, depth 0 (root), slots 6, 14: @F → @24
rust 159 B
let source = stardust:: parse ( source_text, Format :: TRON ) ?;
let output = source. serialize ( Format :: TRON , 0 ) ?;
let result = stardust:: parse ( output, Format :: TRON ) ?;
TRON68 B
Offset (hex) Bytes (hex) Meaning 00 54 52 4F 4E magic TRON 04 1C 61 txt "a" 06 02 01000000000000
00 i64 1 0F 0F 0A 04000000 0600
0000 map leaf, size 10: @4 → @6 19 1C 7A txt "z" 1B 02 02000000000000
00 i64 2 24 0F 0A 19000000 1B00
0000 map leaf, size 10: @19 → @1B 2E 07 0E 40400000 0F00
0000 24000000 map branch, size 14, depth 0 (root), slots 6, 14: @F → @24
C exports: stardust_parse , stardust_serialize , stardust_text_data , stardust_text_error , stardust_text_release
Each cell shows the result after parsing and serialization in that format. The notes below the table explain each result.
null_boolean
JSON: Round trip. Null and booleans keep their values.
DUST: Round trip. Null and booleans keep their values.
EDN: Round trip. EDN nil maps to null.
TRON: Round trip. Binary tags preserve null and booleans.
integer
JSON: Round trip. The codec preserves integer spelling.
DUST: Changed . Leading-zero tokens are strings.
EDN: Changed . Integer spelling is canonical.
TRON: Changed . Integers keep their value and use canonical spelling.
float
JSON: Round trip. The codec preserves float spelling.
DUST: Round trip. The codec preserves float spelling.
EDN: Round trip. The codec preserves this float spelling.
TRON: Changed . Integral floats in containers become integers.
non_finite
JSON: Refused . JSON has no non-finite numbers.
DUST: Changed . NaN is a string.
EDN: Refused . The parser rejects non-finite numeric values.
TRON: Refused . The parser rejects non-finite binary values.
decimal_ratio
JSON: Round trip. The codec preserves finite decimal spelling.
DUST: Round trip. The codec preserves finite decimal spelling.
EDN: Changed . Ratios reduce to native numbers.
TRON: Changed . Decimals use f64 precision.
string
JSON: Round trip. Strings require UTF-8.
DUST: Round trip. Number-like strings require quotes.
EDN: Changed . A lone surrogate becomes a question mark.
TRON: Round trip. Decoded strings require UTF-8.
member_order
JSON: Round trip. The codec preserves object order.
DUST: Round trip. The codec preserves object order.
EDN: Round trip. The codec preserves map order.
TRON: Changed . Members use trie order.
duplicate_keys
JSON: Round trip. The codec preserves all duplicate members.
DUST: Round trip. The codec preserves all duplicate members.
EDN: Refused . The parser rejects equal map keys.
TRON: Changed . The codec keeps the last duplicate value.
empty_object
JSON: Round trip. The empty object is braces.
DUST: Round trip. The empty root object serializes to zero bytes.
EDN: Round trip. The empty map is braces.
TRON: Round trip. The empty object has a binary footer.
utc
JSON: Round trip. UTC remains a tagged object.
DUST: Round trip. UTC uses a tagged object.
EDN: Changed . Millisecond instants use the EDN inst tag.
TRON: Round trip. UTC remains a plain map.
link
JSON: Round trip. Links remain tagged objects.
DUST: Round trip. Links remain tagged objects.
EDN: Round trip. Links remain maps.
TRON: Round trip. Links remain maps.
binary
JSON: Round trip. Base64 remains a tagged object.
DUST: Round trip. Base64 remains a tagged object.
EDN: Round trip. Base64 remains a map.
TRON: Changed . Valid padded base64 in a sole member becomes a binary node.
edn_forms
JSON: Not applicable. EDN forms have no JSON syntax.
DUST: Not applicable. EDN forms have no DUST syntax.
EDN: Changed . The parser converts keywords, symbols, characters, sets and lists to native values. It omits metadata and discarded forms. It reads only the first form.
TRON: Not applicable. EDN forms have no TRON syntax.
The host mapping on the Language values and documents page shows how language values become documents without a text format.