1 #include "../minilang.h"
2 #include "../ml_macros.h"
3 #include "../ml_cbor.h"
4 #include <gc/gc.h>
5 #include <string.h>
6 #include "../ml_object.h"
7
8 #include "minicbor/minicbor.h"
9
ml_cbor_write(ml_value_t * Value,void * Data,ml_cbor_write_fn WriteFn)10 ml_value_t *ml_cbor_write(ml_value_t *Value, void *Data, ml_cbor_write_fn WriteFn) {
11 typeof(ml_cbor_write) *function = ml_typed_fn_get(Value->Type, ml_cbor_write);
12 if (function) {
13 return function(Value, Data, WriteFn);
14 } else {
15 return ml_error("CBORError", "No method to encode %s to CBOR", ml_typeof(Value)->Name);
16 }
17 }
18
ml_cbor_size_fn(size_t * Total,unsigned char * Bytes,int Size)19 static void ml_cbor_size_fn(size_t *Total, unsigned char *Bytes, int Size) {
20 *Total += Size;
21 }
22
ml_cbor_bytes_fn(unsigned char ** End,unsigned char * Bytes,int Size)23 static void ml_cbor_bytes_fn(unsigned char **End, unsigned char *Bytes, int Size) {
24 memcpy(*End, Bytes, Size);
25 *End += Size;
26 }
27
ml_to_cbor(ml_value_t * Value)28 ml_cbor_t ml_to_cbor(ml_value_t *Value) {
29 size_t Size = 0;
30 ml_value_t *Error = ml_cbor_write(Value, &Size, (void *)ml_cbor_size_fn);
31 if (Error) return (ml_cbor_t){{Error}, 0};
32 unsigned char *Bytes = GC_MALLOC_ATOMIC(Size), *End = Bytes;
33 ml_cbor_write(Value, &End, (void *)ml_cbor_bytes_fn);
34 return (ml_cbor_t){{Bytes}, Size};
35 }
36
37 typedef struct block_t {
38 struct block_t *Prev;
39 const void *Data;
40 int Size;
41 } block_t;
42
43 typedef struct collection_t {
44 struct collection_t *Prev;
45 struct tag_t *Tags;
46 ml_value_t *Key;
47 ml_value_t *Collection;
48 block_t *Blocks;
49 int Remaining;
50 } collection_t;
51
52 typedef struct tag_t {
53 struct tag_t *Prev;
54 ml_tag_t Handler;
55 void *Data;
56 } tag_t;
57
58 typedef struct ml_cbor_reader_t {
59 collection_t *Collection;
60 tag_t *Tags;
61 ml_value_t *Value;
62 ml_tag_t (*TagFn)(uint64_t Tag, void *Data, void **TagData);
63 void *TagFnData;
64 minicbor_reader_t Reader[1];
65 } ml_cbor_reader_t;
66
ml_cbor_reader_new(void * TagFnData,ml_tag_t (* TagFn)(uint64_t,void *,void **))67 ml_cbor_reader_t *ml_cbor_reader_new(void *TagFnData, ml_tag_t (*TagFn)(uint64_t, void *, void **)) {
68 ml_cbor_reader_t *Reader = new(ml_cbor_reader_t);
69 Reader->TagFnData = TagFnData;
70 Reader->TagFn = TagFn;
71 ml_cbor_reader_init(Reader->Reader);
72 Reader->Reader->UserData = Reader;
73 return Reader;
74 }
75
ml_cbor_reader_read(ml_cbor_reader_t * Reader,unsigned char * Bytes,int Size)76 void ml_cbor_reader_read(ml_cbor_reader_t *Reader, unsigned char *Bytes, int Size) {
77 ml_cbor_read(Reader->Reader, Bytes, Size);
78 }
79
ml_cbor_reader_get(ml_cbor_reader_t * Reader)80 ml_value_t *ml_cbor_reader_get(ml_cbor_reader_t *Reader) {
81 if (!Reader->Value) return ml_error("CBORError", "CBOR not completely read");
82 return Reader->Value;
83 }
84
ml_cbor_reader_extra(ml_cbor_reader_t * Reader)85 int ml_cbor_reader_extra(ml_cbor_reader_t *Reader) {
86 return ml_cbor_reader_remaining(Reader->Reader);
87 }
88
89 static ml_value_t IsByteString[1];
90 static ml_value_t IsString[1];
91 static ml_value_t IsList[1];
92
value_handler(ml_cbor_reader_t * Reader,ml_value_t * Value)93 static void value_handler(ml_cbor_reader_t *Reader, ml_value_t *Value) {
94 for (tag_t *Tag = Reader->Tags; Tag; Tag = Tag->Prev) {
95 if (!ml_is_error(Value)) Value = Tag->Handler(Tag->Data, Value);
96 }
97 Reader->Tags = 0;
98 collection_t *Collection = Reader->Collection;
99 if (!Collection) {
100 Reader->Value = Value;
101 ml_cbor_reader_finish(Reader->Reader);
102 } else if (Collection->Key == IsList) {
103 ml_list_append(Collection->Collection, Value);
104 if (Collection->Remaining && --Collection->Remaining == 0) {
105 Reader->Collection = Collection->Prev;
106 Reader->Tags = Collection->Tags;
107 value_handler(Reader, Collection->Collection);
108 }
109 } else if (Collection->Key) {
110 ml_map_insert(Collection->Collection, Collection->Key, Value);
111 if (Collection->Remaining && --Collection->Remaining == 0) {
112 Reader->Collection = Collection->Prev;
113 Reader->Tags = Collection->Tags;
114 value_handler(Reader, Collection->Collection);
115 } else {
116 Collection->Key = 0;
117 }
118 } else {
119 Collection->Key = Value;
120 }
121 }
122
ml_cbor_read_positive_fn(ml_cbor_reader_t * Reader,uint64_t Value)123 void ml_cbor_read_positive_fn(ml_cbor_reader_t *Reader, uint64_t Value) {
124 value_handler(Reader, ml_integer(Value));
125 }
126
ml_cbor_read_negative_fn(ml_cbor_reader_t * Reader,uint64_t Value)127 void ml_cbor_read_negative_fn(ml_cbor_reader_t *Reader, uint64_t Value) {
128 if (Value <= 0x7FFFFFFFL) {
129 value_handler(Reader, ml_integer(~(uint32_t)Value));
130 } else {
131 value_handler(Reader, ml_integer(Value));
132 // TODO: Implement large numbers somehow
133 // mpz_t Temp;
134 // mpz_init_set_ui(Temp, (uint32_t)(Value >> 32));
135 // mpz_mul_2exp(Temp, Temp, 32);
136 // mpz_add_ui(Temp, Temp, (uint32_t)Value);
137 // mpz_com(Temp, Temp);
138 // value_handler(Reader, Std$Integer$new_big(Temp));
139 }
140 }
141
ml_cbor_read_bytes_fn(ml_cbor_reader_t * Reader,int Size)142 void ml_cbor_read_bytes_fn(ml_cbor_reader_t *Reader, int Size) {
143 if (Size) {
144 collection_t *Collection = new(collection_t);
145 Collection->Prev = Reader->Collection;
146 Collection->Tags = Reader->Tags;
147 Reader->Tags = 0;
148 Collection->Key = IsByteString;
149 Collection->Remaining = 0;
150 Collection->Blocks = 0;
151 Reader->Collection = Collection;
152 } else {
153 value_handler(Reader, ml_cstring(""));
154 }
155 }
156
ml_cbor_read_bytes_piece_fn(ml_cbor_reader_t * Reader,const void * Bytes,int Size,int Final)157 void ml_cbor_read_bytes_piece_fn(ml_cbor_reader_t *Reader, const void *Bytes, int Size, int Final) {
158 collection_t *Collection = Reader->Collection;
159 if (Final) {
160 Reader->Collection = Collection->Prev;
161 Reader->Tags = Collection->Tags;
162 int Total = Collection->Remaining + Size;
163 char *Buffer = GC_MALLOC_ATOMIC(Total);
164 Buffer += Collection->Remaining;
165 memcpy(Buffer, Bytes, Size);
166 for (block_t *B = Collection->Blocks; B; B = B->Prev) {
167 Buffer -= B->Size;
168 memcpy(Buffer, B->Data, B->Size);
169 }
170 value_handler(Reader, ml_string(Buffer, Total));
171 } else {
172 block_t *Block = new(block_t);
173 Block->Prev = Collection->Blocks;
174 Block->Data = Bytes;
175 Block->Size = Size;
176 Collection->Blocks = Block;
177 Collection->Remaining += Size;
178 }
179 }
180
ml_cbor_read_string_fn(ml_cbor_reader_t * Reader,int Size)181 void ml_cbor_read_string_fn(ml_cbor_reader_t *Reader, int Size) {
182 if (Size) {
183 collection_t *Collection = new(collection_t);
184 Collection->Prev = Reader->Collection;
185 Collection->Tags = Reader->Tags;
186 Reader->Tags = 0;
187 Collection->Key = IsString;
188 Collection->Remaining = 0;
189 Collection->Blocks = 0;
190 Reader->Collection = Collection;
191 } else {
192 value_handler(Reader, ml_cstring(""));
193 }
194 }
195
ml_cbor_read_string_piece_fn(ml_cbor_reader_t * Reader,const void * Bytes,int Size,int Final)196 void ml_cbor_read_string_piece_fn(ml_cbor_reader_t *Reader, const void *Bytes, int Size, int Final) {
197 collection_t *Collection = Reader->Collection;
198 if (Final) {
199 Reader->Collection = Collection->Prev;
200 Reader->Tags = Collection->Tags;
201 int Total = Collection->Remaining + Size;
202 char *Buffer = GC_MALLOC_ATOMIC(Total);
203 Buffer += Collection->Remaining;
204 memcpy(Buffer, Bytes, Size);
205 for (block_t *B = Collection->Blocks; B; B = B->Prev) {
206 Buffer -= B->Size;
207 memcpy(Buffer, B->Data, B->Size);
208 }
209 value_handler(Reader, ml_string(Buffer, Total));
210 } else {
211 block_t *Block = new(block_t);
212 Block->Prev = Collection->Blocks;
213 Block->Data = Bytes;
214 Block->Size = Size;
215 Collection->Blocks = Block;
216 Collection->Remaining += Size;
217 }
218 }
219
ml_cbor_read_array_fn(ml_cbor_reader_t * Reader,int Size)220 void ml_cbor_read_array_fn(ml_cbor_reader_t *Reader, int Size) {
221 if (Size) {
222 collection_t *Collection = new(collection_t);
223 Collection->Prev = Reader->Collection;
224 Collection->Tags = Reader->Tags;
225 Reader->Tags = 0;
226 Collection->Remaining = Size;
227 Collection->Key = IsList;
228 Collection->Collection = ml_list();
229 Reader->Collection = Collection;
230 } else {
231 value_handler(Reader, ml_list());
232 }
233 }
234
ml_cbor_read_map_fn(ml_cbor_reader_t * Reader,int Size)235 void ml_cbor_read_map_fn(ml_cbor_reader_t *Reader, int Size) {
236 if (Size > 0) {
237 collection_t *Collection = new(collection_t);
238 Collection->Prev = Reader->Collection;
239 Collection->Tags = Reader->Tags;
240 Reader->Tags = 0;
241 Collection->Remaining = Size;
242 Collection->Key = 0;
243 Collection->Collection = ml_map();
244 Reader->Collection = Collection;
245 } else {
246 value_handler(Reader, ml_map());
247 }
248 }
249
ml_cbor_read_tag_fn(ml_cbor_reader_t * Reader,uint64_t Tag)250 void ml_cbor_read_tag_fn(ml_cbor_reader_t *Reader, uint64_t Tag) {
251 void *Data;
252 ml_tag_t Handler = Reader->TagFn(Tag, Reader->TagFnData, &Data);
253 if (Handler) {
254 tag_t *Tag = new(tag_t);
255 Tag->Prev = Reader->Tags;
256 Tag->Handler = Handler;
257 Tag->Data = Data;
258 Reader->Tags = Tag;
259 }
260 }
261
ml_cbor_read_float_fn(ml_cbor_reader_t * Reader,double Value)262 void ml_cbor_read_float_fn(ml_cbor_reader_t *Reader, double Value) {
263 value_handler(Reader, ml_real(Value));
264 }
265
ml_cbor_read_simple_fn(ml_cbor_reader_t * Reader,int Value)266 void ml_cbor_read_simple_fn(ml_cbor_reader_t *Reader, int Value) {
267 switch (Value) {
268 case CBOR_SIMPLE_FALSE:
269 value_handler(Reader, (ml_value_t *)MLFalse);
270 break;
271 case CBOR_SIMPLE_TRUE:
272 value_handler(Reader, (ml_value_t *)MLTrue);
273 break;
274 case CBOR_SIMPLE_NULL:
275 value_handler(Reader, MLNil);
276 break;
277 default:
278 value_handler(Reader, MLNil);
279 break;
280 }
281 }
282
ml_cbor_read_break_fn(ml_cbor_reader_t * Reader)283 void ml_cbor_read_break_fn(ml_cbor_reader_t *Reader) {
284 collection_t *Collection = Reader->Collection;
285 Reader->Collection = Collection->Prev;
286 Reader->Tags = Collection->Tags;
287 value_handler(Reader, Collection->Collection);
288 }
289
ml_cbor_read_error_fn(ml_cbor_reader_t * Reader,int Position,const char * Message)290 void ml_cbor_read_error_fn(ml_cbor_reader_t *Reader, int Position, const char *Message) {
291 value_handler(Reader, ml_error("CBORError", "Read error: %s at %d", Message, Position));
292 }
293
ml_value_fn(ml_value_t * Callback,ml_value_t * Value)294 static ml_value_t *ml_value_fn(ml_value_t *Callback, ml_value_t *Value) {
295 return ml_simple_inline(Callback, 1, Value);
296 }
297
ml_value_tag_fn(uint64_t Tag,ml_value_t * Callback,void ** Data)298 static ml_tag_t ml_value_tag_fn(uint64_t Tag, ml_value_t *Callback, void **Data) {
299 Data[0] = ml_simple_inline(Callback, 1, ml_integer(Tag));
300 return (ml_tag_t)ml_value_fn;
301 }
302
303 ml_value_t *CborDefaultTags;
304
ML_FUNCTION(DefaultTagFn)305 ML_FUNCTION(DefaultTagFn) {
306 return ml_map_search(CborDefaultTags, Args[0]);
307 }
308
ml_from_cbor(ml_cbor_t Cbor,void * TagFnData,ml_tag_t (* TagFn)(uint64_t,void *,void **))309 ml_value_t *ml_from_cbor(ml_cbor_t Cbor, void *TagFnData, ml_tag_t (*TagFn)(uint64_t, void *, void **)) {
310 ml_cbor_reader_t Reader[1];
311 Reader->TagFnData = TagFnData ?: DefaultTagFn;
312 Reader->TagFn = TagFn ?: (void *)ml_value_tag_fn;
313 ml_cbor_reader_init(Reader->Reader);
314 Reader->Reader->UserData = Reader;
315 Reader->Collection = 0;
316 Reader->Tags = 0;
317 Reader->Value = 0;
318 ml_cbor_read(Reader->Reader, Cbor.Data, Cbor.Length);
319 int Extra = ml_cbor_reader_extra(Reader);
320 if (Extra) return ml_error("CBORError", "Extra bytes after decoding: %d", Extra);
321 return ml_cbor_reader_get(Reader);
322 }
323
ml_from_cbor_extra(ml_cbor_t Cbor,void * TagFnData,ml_tag_t (* TagFn)(uint64_t,void *,void **))324 ml_cbor_result_t ml_from_cbor_extra(ml_cbor_t Cbor, void *TagFnData, ml_tag_t (*TagFn)(uint64_t, void *, void **)) {
325 ml_cbor_reader_t Reader[1];
326 Reader->TagFnData = TagFnData ?: DefaultTagFn;
327 Reader->TagFn = TagFn ?: (void *)ml_value_tag_fn;
328 ml_cbor_reader_init(Reader->Reader);
329 Reader->Reader->UserData = Reader;
330 Reader->Collection = 0;
331 Reader->Tags = 0;
332 Reader->Value = 0;
333 ml_cbor_read(Reader->Reader, Cbor.Data, Cbor.Length);
334 return (ml_cbor_result_t){ml_cbor_reader_get(Reader), ml_cbor_reader_extra(Reader)};
335 }
336
ml_to_cbor_fn(void * Data,int Count,ml_value_t ** Args)337 static ml_value_t *ml_to_cbor_fn(void *Data, int Count, ml_value_t **Args) {
338 ml_cbor_t Cbor = ml_to_cbor(Args[0]);
339 if (Cbor.Data) return ml_string(Cbor.Data, Cbor.Length);
340 return ml_error("CborError", "Error encoding to cbor");
341 }
342
ml_from_cbor_fn(void * Data,int Count,ml_value_t ** Args)343 static ml_value_t *ml_from_cbor_fn(void *Data, int Count, ml_value_t **Args) {
344 ML_CHECK_ARG_COUNT(1);
345 ML_CHECK_ARG_TYPE(0, MLStringT);
346 ml_cbor_t Cbor = {{ml_string_value(Args[0])}, ml_string_length(Args[0])};
347 return ml_from_cbor(Cbor, Count > 1 ? Args[1] : (ml_value_t *)DefaultTagFn, (void *)ml_value_tag_fn);
348 }
349
ML_TYPED_FN(ml_cbor_write,MLIntegerT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)350 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLIntegerT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
351 //printf("%s()\n", __func__);
352 int64_t Value = ml_integer_value_fast(Arg);
353 if (Value < 0) {
354 ml_cbor_write_negative(Data, WriteFn, ~Value);
355 } else {
356 ml_cbor_write_positive(Data, WriteFn, Value);
357 }
358 return NULL;
359 }
360
ML_TYPED_FN(ml_cbor_write,MLStringT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)361 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLStringT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
362 //printf("%s()\n", __func__);
363 ml_cbor_write_string(Data, WriteFn, ml_string_length(Arg));
364 WriteFn(Data, (const unsigned char *)ml_string_value(Arg), ml_string_length(Arg));
365 return NULL;
366 }
367
ML_TYPED_FN(ml_cbor_write,MLListT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)368 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLListT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
369 ml_cbor_write_array(Data, WriteFn, ml_list_length(Arg));
370 ML_LIST_FOREACH(Arg, Node) {
371 ml_value_t *Error = ml_cbor_write(Node->Value, Data, WriteFn);
372 if (Error) return Error;
373 }
374 return NULL;
375 }
376
ML_TYPED_FN(ml_cbor_write,MLMapT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)377 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLMapT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
378 ml_cbor_write_map(Data, WriteFn, ml_map_size(Arg));
379 ML_MAP_FOREACH(Arg, Node) {
380 ml_value_t *Error = ml_cbor_write(Node->Key, Data, WriteFn);
381 if (Error) return Error;
382 Error = ml_cbor_write(Node->Value, Data, WriteFn);
383 if (Error) return Error;
384 }
385 return NULL;
386 }
387
ML_TYPED_FN(ml_cbor_write,MLDoubleT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)388 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLDoubleT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
389 ml_cbor_write_float8(Data, WriteFn, ml_double_value_fast(Arg));
390 return NULL;
391 }
392
ML_TYPED_FN(ml_cbor_write,MLNilT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)393 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLNilT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
394 ml_cbor_write_simple(Data, WriteFn, CBOR_SIMPLE_NULL);
395 return NULL;
396 }
397
ML_TYPED_FN(ml_cbor_write,MLBooleanT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)398 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLBooleanT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
399 ml_cbor_write_simple(Data, WriteFn, ml_boolean_value(Arg) ? CBOR_SIMPLE_TRUE : CBOR_SIMPLE_FALSE);
400 return NULL;
401 }
402
ML_TYPED_FN(ml_cbor_write,MLMethodT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)403 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLMethodT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
404 const char *Name = ml_method_name(Arg);
405 ml_cbor_write_tag(Data, WriteFn, 26); // TODO: Change this to a proper tag
406 ml_cbor_write_string(Data, WriteFn, strlen(Name));
407 WriteFn(Data, (void *)Name, strlen(Name));
408 return NULL;
409 }
410
ML_TYPED_FN(ml_cbor_write,MLObjectT,ml_value_t * Arg,void * Data,ml_cbor_write_fn WriteFn)411 static ml_value_t *ML_TYPED_FN(ml_cbor_write, MLObjectT, ml_value_t *Arg, void *Data, ml_cbor_write_fn WriteFn) {
412 ml_cbor_write_tag(Data, WriteFn, 27);
413 int Size = ml_object_size(Arg);
414 ml_cbor_write_array(Data, WriteFn, 1 + Size);
415 const char *Name = ml_typeof(Arg)->Name;
416 ml_cbor_write_string(Data, WriteFn, strlen(Name));
417 WriteFn(Data, (void *)Name, strlen(Name));
418 for (int I = 0; I < Size; ++I) {
419 ml_value_t *Error = ml_cbor_write(ml_object_field(Arg, I), Data, WriteFn);
420 if (Error) return Error;
421 }
422 return NULL;
423 }
424
ml_cbor_read_method(void * Data,int Count,ml_value_t ** Args)425 ml_value_t *ml_cbor_read_method(void *Data, int Count, ml_value_t **Args) {
426 ML_CHECK_ARG_TYPE(0, MLStringT);
427 return ml_method(ml_string_value(Args[0]));
428 }
429
430 ml_value_t *CborObjects;
431
ml_cbor_read_object(void * Data,int Count,ml_value_t ** Args)432 ml_value_t *ml_cbor_read_object(void *Data, int Count, ml_value_t **Args) {
433 ML_CHECK_ARG_COUNT(1);
434 ML_CHECK_ARG_TYPE(0, MLListT);
435 ml_list_iter_t Iter[1];
436 ml_list_iter_forward(Args[0], Iter);
437 if (!ml_list_iter_valid(Iter)) return ml_error("CBORError", "Object tag requires type name");
438 ml_value_t *TypeName = Iter->Value;
439 if (ml_typeof(TypeName) != MLStringT) return ml_error("CBORError", "Object tag requires type name");
440 ml_value_t *Constructor = ml_map_search(CborObjects, TypeName);
441 if (Constructor == MLNil) return ml_error("CBORError", "Object %s not found", ml_string_value(TypeName));
442 int Count2 = ml_list_length(Args[0]) - 1;
443 ml_value_t **Args2 = anew(ml_value_t *, Count2);
444 for (int I = 0; I < Count2; ++I) {
445 ml_list_iter_next(Iter);
446 Args2[I] = Iter->Value;
447 }
448 return ml_simple_call(Constructor, Count2, Args2);
449 }
450
ml_library_entry(ml_value_t * Module,ml_getter_t GlobalGet,void * Globals)451 void ml_library_entry(ml_value_t *Module, ml_getter_t GlobalGet, void *Globals) {
452 CborDefaultTags = ml_map();
453 CborObjects = ml_map();
454 ml_map_insert(CborDefaultTags, ml_integer(26), ml_cfunction(NULL, ml_cbor_read_method)); // TODO: Change this to a proper tag
455 ml_map_insert(CborDefaultTags, ml_integer(27), ml_cfunction(NULL, ml_cbor_read_object));
456 #ifdef ML_CBOR_BYTECODE
457 ml_map_insert(CborDefaultTags, ml_integer(36), ml_cfunction(NULL, ml_cbor_read_closure));
458 #endif
459 #include "ml_cbor_init.c"
460 ml_module_export(Module, "encode", ml_cfunction(NULL, ml_to_cbor_fn));
461 ml_module_export(Module, "decode", ml_cfunction(NULL, ml_from_cbor_fn));
462 ml_module_export(Module, "Default", CborDefaultTags);
463 }
464