MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

improve FormData

+357 -237
-2
include/modules/globals.h
··· 5 5 6 6 void init_globals_module(void); 7 7 8 - ant_value_t js_structured_clone(ant_t *js, ant_value_t *args, int nargs); 9 8 ant_value_t js_report_error(ant_t *js, ant_value_t *args, int nargs); 10 - 11 9 bool js_fire_unhandled_rejection(ant_t *js, ant_value_t promise_val, ant_value_t reason); 12 10 void js_fire_rejection_handled(ant_t *js, ant_value_t promise_val, ant_value_t reason); 13 11
+9
include/modules/structured-clone.h
··· 1 + #ifndef STRUCTURED_CLONE_H 2 + #define STRUCTURED_CLONE_H 3 + 4 + #include "types.h" 5 + 6 + void init_structured_clone_module(void); 7 + ant_value_t js_structured_clone(ant_t *js, ant_value_t *args, int nargs); 8 + 9 + #endif
+2
src/main.c
··· 73 73 #include "modules/domexception.h" 74 74 #include "modules/abort.h" 75 75 #include "modules/globals.h" 76 + #include "modules/structured-clone.h" 76 77 #include "modules/v8.h" 77 78 #include "modules/worker_threads.h" 78 79 #include "modules/headers.h" ··· 584 585 init_timer_module(); 585 586 init_domexception_module(); 586 587 init_globals_module(); 588 + init_structured_clone_module(); 587 589 init_abort_module(); 588 590 init_headers_module(); 589 591 init_blob_module();
+40 -29
src/modules/formdata.c
··· 156 156 blob_data_t *bd = blob_get_data(val); 157 157 if (!bd) return js_mkerr_typed(js, JS_ERR_TYPE, "FormData value must be a string, Blob, or File"); 158 158 159 - const char *fname = NULL; 160 - char *fname_owned = NULL; 159 + bool is_file = (bd->name != NULL); 160 + bool no_filename_override = (vtype(filename_v) == T_UNDEF); 161 161 162 - if (vtype(filename_v) != T_UNDEF) { 163 - ant_value_t fv = filename_v; 164 - if (vtype(fv) != T_STR) { fv = js_tostring_val(js, fv); if (is_err(fv)) return fv; } 165 - fname_owned = strdup(js_getstr(js, fv, NULL)); 166 - fname = fname_owned; 167 - } 168 - 169 - else if (bd->name && bd->name[0]) fname = bd->name; 170 - else fname = "blob"; 162 + ant_value_t stored_val; 171 163 172 - int64_t last_modified = bd->last_modified; 173 - if (!last_modified) { 174 - struct timespec ts; 175 - clock_gettime(CLOCK_REALTIME, &ts); 176 - last_modified = (int64_t)ts.tv_sec * 1000LL + (int64_t)(ts.tv_nsec / 1000000); 164 + if (is_file && no_filename_override) { 165 + stored_val = val; 166 + } else { 167 + const char *fname = NULL; 168 + char *fname_owned = NULL; 169 + 170 + if (!no_filename_override) { 171 + ant_value_t fv = filename_v; 172 + if (vtype(fv) != T_STR) { fv = js_tostring_val(js, fv); if (is_err(fv)) return fv; } 173 + fname_owned = strdup(js_getstr(js, fv, NULL)); 174 + fname = fname_owned; 175 + } 176 + 177 + else if (bd->name && bd->name[0]) fname = bd->name; 178 + else fname = "blob"; 179 + 180 + int64_t last_modified = bd->last_modified; 181 + if (!last_modified) { 182 + struct timespec ts; 183 + clock_gettime(CLOCK_REALTIME, &ts); 184 + last_modified = (int64_t)ts.tv_sec * 1000LL + (int64_t)(ts.tv_nsec / 1000000); 185 + } 186 + 187 + ant_value_t file_obj = blob_create(js, bd->data, bd->size, bd->type); 188 + if (is_err(file_obj)) { free(fname_owned); return file_obj; } 189 + 190 + blob_data_t *nbd = blob_get_data(file_obj); 191 + if (nbd) { 192 + nbd->name = strdup(fname); 193 + nbd->last_modified = last_modified; 194 + } 195 + 196 + free(fname_owned); 197 + js_set_proto_init(file_obj, g_file_proto); 198 + stored_val = file_obj; 177 199 } 178 200 179 - ant_value_t file_obj = blob_create(js, bd->data, bd->size, bd->type); 180 - if (is_err(file_obj)) { free(fname_owned); return file_obj; } 181 - 182 - blob_data_t *nbd = blob_get_data(file_obj); 183 - if (nbd) { 184 - nbd->name = strdup(fname); 185 - nbd->last_modified = last_modified; 186 - } free(fname_owned); 187 - 188 - js_set_proto_init(file_obj, g_file_proto); 189 201 if (is_set) fd_delete_name(d, name); 190 - 191 202 size_t idx = (size_t)js_arr_len(js, values_arr); 192 - js_arr_push(js, values_arr, file_obj); 203 + js_arr_push(js, values_arr, stored_val); 193 204 194 205 return fd_append_file(d, name, idx) ? js_mkundef() : js_mkerr(js, "out of memory"); 195 206 } ··· 400 411 static ant_value_t js_formdata_ctor(ant_t *js, ant_value_t *args, int nargs) { 401 412 if (vtype(js->new_target) == T_UNDEF) 402 413 return js_mkerr_typed(js, JS_ERR_TYPE, "FormData constructor requires 'new'"); 403 - if (nargs >= 1 && vtype(args[0]) != T_UNDEF && vtype(args[0]) != T_NULL) 414 + if (nargs >= 1 && vtype(args[0]) != T_UNDEF) 404 415 return js_mkerr_typed(js, JS_ERR_TYPE, "FormData does not support a form element argument"); 405 416 406 417 fd_data_t *d = fd_data_new();
-206
src/modules/globals.c
··· 1 1 #include <string.h> 2 2 #include <stdio.h> 3 3 #include <stdlib.h> 4 - #include <inttypes.h> 5 4 6 5 #include "ant.h" 7 6 #include "errors.h" ··· 10 9 #include "descriptors.h" 11 10 #include "silver/engine.h" 12 11 13 - #include "modules/buffer.h" 14 12 #include "modules/events.h" 15 - #include "modules/collections.h" 16 - #include "modules/domexception.h" 17 13 #include "modules/globals.h" 18 14 19 15 ant_value_t js_report_error(ant_t *js, ant_value_t *args, int nargs) { ··· 104 100 sv_vm_call(js->vm, js, handler, global, call_args, 1, NULL, false); 105 101 } 106 102 107 - static void sc_add_seen(ant_t *js, ant_value_t seen, ant_value_t val, ant_value_t clone) { 108 - char key[24]; 109 - snprintf(key, sizeof(key), "%" PRIxPTR, (uintptr_t)vdata(val)); 110 - js_set(js, seen, key, clone); 111 - } 112 - 113 - static ant_value_t sc_lookup_seen(ant_t *js, ant_value_t seen, ant_value_t val) { 114 - char key[24]; 115 - snprintf(key, sizeof(key), "%" PRIxPTR, (uintptr_t)vdata(val)); 116 - ant_value_t found = js_get(js, seen, key); 117 - return (vtype(found) == T_UNDEF) ? js_mkundef() : found; 118 - } 119 - 120 - static const char *sc_ta_type_name(TypedArrayType type) { 121 - static const char *names[] = { 122 - "Int8Array", "Uint8Array", "Uint8ClampedArray", 123 - "Int16Array", "Uint16Array", 124 - "Int32Array", "Uint32Array", 125 - "Float32Array", "Float64Array", 126 - "BigInt64Array", "BigUint64Array" 127 - }; 128 - int i = (int)type; 129 - if (i < 0 || i > 10) return "Uint8Array"; 130 - return names[i]; 131 - } 132 - 133 - static ant_value_t sc_clone_rec(ant_t *js, ant_value_t val, ant_value_t seen) { 134 - uint8_t t = vtype(val); 135 - 136 - if (t == T_UNDEF || t == T_NULL || t == T_BOOL || t == T_NUM || t == T_BIGINT || t == T_STR) return val; 137 - if (t == T_SYMBOL) return js_throw(js, make_dom_exception(js, "Symbol cannot be serialized", "DataCloneError")); 138 - 139 - if (t == T_TYPEDARRAY) { 140 - ant_value_t existing = sc_lookup_seen(js, seen, val); 141 - if (vtype(existing) != T_UNDEF) return existing; 142 - 143 - TypedArrayData *ta = (TypedArrayData *)js_gettypedarray(val); 144 - if (!ta || !ta->buffer) 145 - return js_throw(js, make_dom_exception(js, "TypedArray could not be cloned", "DataCloneError")); 146 - 147 - ArrayBufferData *new_buf = create_array_buffer_data(ta->byte_length); 148 - if (!new_buf) return js_mkerr(js, "out of memory"); 149 - if (ta->byte_length > 0) memcpy(new_buf->data, ta->buffer->data + ta->byte_offset, ta->byte_length); 150 - 151 - ant_value_t clone = create_typed_array(js, ta->type, new_buf, 0, ta->length, sc_ta_type_name(ta->type)); 152 - sc_add_seen(js, seen, val, clone); 153 - 154 - return clone; 155 - } 156 - 157 - if (t == T_FUNC || t == T_CFUNC || t == T_CLOSURE) 158 - return js_throw(js, make_dom_exception(js, "() => {} could not be cloned", "DataCloneError")); 159 - if (t == T_PROMISE || t == T_GENERATOR) 160 - return js_throw(js, make_dom_exception(js, "Value could not be cloned", "DataCloneError")); 161 - if (!is_object_type(val)) 162 - return js_throw(js, make_dom_exception(js, "Value could not be cloned", "DataCloneError")); 163 - 164 - ant_value_t existing = sc_lookup_seen(js, seen, val); 165 - if (vtype(existing) != T_UNDEF) return existing; 166 - 167 - if (t == T_ARR) { 168 - ant_value_t clone = js_mkarr(js); 169 - sc_add_seen(js, seen, val, clone); 170 - 171 - ant_offset_t len = js_arr_len(js, val); 172 - for (ant_offset_t i = 0; i < len; i++) { 173 - ant_value_t ic = sc_clone_rec(js, js_arr_get(js, val, i), seen); 174 - if (is_err(ic)) return ic; 175 - js_arr_push(js, clone, ic); 176 - } 177 - 178 - return clone; 179 - } 180 - 181 - ant_object_t *obj_ptr = js_obj_ptr(val); 182 - if (!obj_ptr) 183 - return js_throw(js, make_dom_exception(js, "Value could not be cloned", "DataCloneError")); 184 - 185 - if (obj_ptr->type_tag == T_WEAKMAP || obj_ptr->type_tag == T_WEAKSET) 186 - return js_throw(js, make_dom_exception(js, "WeakMap/WeakSet could not be cloned", "DataCloneError")); 187 - 188 - if (obj_ptr->type_tag == T_MAP) { 189 - ant_value_t clone = js_mkobj(js); 190 - js_obj_ptr(clone)->type_tag = T_MAP; 191 - 192 - ant_value_t map_proto = js_get_ctor_proto(js, "Map", 3); 193 - if (is_special_object(map_proto)) js_set_proto_init(clone, map_proto); 194 - 195 - map_entry_t **new_head = ant_calloc(sizeof(map_entry_t *)); 196 - if (!new_head) return js_mkerr(js, "out of memory"); 197 - 198 - *new_head = NULL; 199 - js_set_slot(clone, SLOT_DATA, ANT_PTR(new_head)); 200 - sc_add_seen(js, seen, val, clone); 201 - 202 - map_entry_t **src_head = get_map_from_obj(js, val); 203 - if (src_head && *src_head) { 204 - map_entry_t *e, *tmp; 205 - HASH_ITER(hh, *src_head, e, tmp) { 206 - ant_value_t vc = sc_clone_rec(js, e->value, seen); 207 - if (is_err(vc)) return vc; 208 - 209 - map_entry_t *ne = ant_calloc(sizeof(map_entry_t)); 210 - if (!ne) return js_mkerr(js, "out of memory"); 211 - ne->key = strdup(e->key); 212 - ne->value = vc; 213 - HASH_ADD_STR(*new_head, key, ne); 214 - }} 215 - 216 - return clone; 217 - } 218 - 219 - if (obj_ptr->type_tag == T_SET) { 220 - ant_value_t clone = js_mkobj(js); 221 - js_obj_ptr(clone)->type_tag = T_SET; 222 - 223 - ant_value_t set_proto = js_get_ctor_proto(js, "Set", 3); 224 - if (is_special_object(set_proto)) js_set_proto_init(clone, set_proto); 225 - 226 - set_entry_t **new_head = ant_calloc(sizeof(set_entry_t *)); 227 - if (!new_head) return js_mkerr(js, "out of memory"); 228 - *new_head = NULL; 229 - js_set_slot(clone, SLOT_DATA, ANT_PTR(new_head)); 230 - sc_add_seen(js, seen, val, clone); 231 - 232 - set_entry_t **src_head = get_set_from_obj(js, val); 233 - if (src_head && *src_head) { 234 - set_entry_t *e, *tmp; 235 - HASH_ITER(hh, *src_head, e, tmp) { 236 - ant_value_t vc = sc_clone_rec(js, e->value, seen); 237 - if (is_err(vc)) return vc; 238 - 239 - set_entry_t *ne = ant_calloc(sizeof(set_entry_t)); 240 - if (!ne) return js_mkerr(js, "out of memory"); 241 - ne->key = strdup(e->key); 242 - ne->value = vc; 243 - HASH_ADD_STR(*new_head, key, ne); 244 - }} 245 - 246 - return clone; 247 - } 248 - 249 - if (js_get_slot(val, SLOT_ERROR_BRAND) == js_true) { 250 - ant_value_t clone = js_mkobj(js); 251 - sc_add_seen(js, seen, val, clone); 252 - 253 - const char *msg = get_str_prop(js, val, "message", 7, NULL); 254 - const char *name = get_str_prop(js, val, "name", 4, NULL); 255 - const char *stack = get_str_prop(js, val, "stack", 5, NULL); 256 - 257 - if (msg) js_set(js, clone, "message", js_mkstr(js, msg, strlen(msg))); 258 - if (name) js_set(js, clone, "name", js_mkstr(js, name, strlen(name))); 259 - if (stack) js_set(js, clone, "stack", js_mkstr(js, stack, strlen(stack))); 260 - js_set_slot(clone, SLOT_ERROR_BRAND, js_true); 261 - 262 - ant_value_t err_type = js_get_slot(val, SLOT_ERR_TYPE); 263 - if (vtype(err_type) != T_UNDEF) js_set_slot(clone, SLOT_ERR_TYPE, err_type); 264 - 265 - return clone; 266 - } 267 - 268 - ant_value_t date_proto = js_get_ctor_proto(js, "Date", 4); 269 - if ( 270 - vtype(date_proto) != T_UNDEF 271 - && is_object_type(date_proto) 272 - && js_is_prototype_of(js, date_proto, val) 273 - ) { 274 - ant_value_t clone = js_mkobj(js); 275 - js_set_proto_init(clone, date_proto); 276 - js_set_slot(clone, SLOT_DATA, js_get_slot(val, SLOT_DATA)); 277 - sc_add_seen(js, seen, val, clone); 278 - 279 - return clone; 280 - } 281 - 282 - ant_value_t clone = js_mkobj(js); 283 - sc_add_seen(js, seen, val, clone); 284 - 285 - ant_iter_t iter = js_prop_iter_begin(js, val); 286 - const char *key; 287 - size_t key_len; 288 - ant_value_t pval; 289 - 290 - while (js_prop_iter_next(&iter, &key, &key_len, &pval)) { 291 - ant_value_t pc = sc_clone_rec(js, pval, seen); 292 - if (is_err(pc)) { js_prop_iter_end(&iter); return pc; } 293 - js_set(js, clone, key, pc); 294 - } 295 - 296 - js_prop_iter_end(&iter); 297 - return clone; 298 - } 299 - 300 - ant_value_t js_structured_clone(ant_t *js, ant_value_t *args, int nargs) { 301 - if (nargs < 1) return js_mkundef(); 302 - // TODO: transfer option (args[1]) accepted but not yet implemented 303 - ant_value_t seen = js_mkobj(js); 304 - return sc_clone_rec(js, args[0], seen); 305 - } 306 - 307 103 void init_globals_module(void) { 308 104 ant_t *js = rt->js; 309 105 ant_value_t global = js_glob(js); ··· 311 107 js_set(js, global, "reportError", js_mkfun(js_report_error)); 312 108 js_set_descriptor(js, global, "reportError", 11, JS_DESC_W | JS_DESC_C); 313 109 314 - js_set(js, global, "structuredClone", js_mkfun(js_structured_clone)); 315 - js_set_descriptor(js, global, "structuredClone", 15, JS_DESC_W | JS_DESC_C); 316 110 }
+306
src/modules/structured-clone.c
··· 1 + #include <string.h> 2 + #include <stdlib.h> 3 + 4 + #include <uthash.h> 5 + 6 + #include "ant.h" 7 + #include "errors.h" 8 + #include "runtime.h" 9 + #include "internal.h" 10 + #include "descriptors.h" 11 + 12 + #include "modules/buffer.h" 13 + #include "modules/collections.h" 14 + #include "modules/domexception.h" 15 + #include "modules/blob.h" 16 + #include "modules/structured-clone.h" 17 + 18 + typedef struct sc_entry { 19 + ant_value_t key; 20 + ant_value_t value; 21 + UT_hash_handle hh; 22 + } sc_entry_t; 23 + 24 + static void sc_add(sc_entry_t **table, ant_value_t key, ant_value_t value) { 25 + sc_entry_t *e = calloc(1, sizeof(sc_entry_t)); 26 + if (!e) return; 27 + e->key = key; 28 + e->value = value; 29 + HASH_ADD(hh, *table, key, sizeof(ant_value_t), e); 30 + } 31 + 32 + static ant_value_t sc_lookup(sc_entry_t **table, ant_value_t key) { 33 + sc_entry_t *e; 34 + HASH_FIND(hh, *table, &key, sizeof(ant_value_t), e); 35 + return e ? e->value : js_mkundef(); 36 + } 37 + 38 + static bool sc_has(sc_entry_t **table, ant_value_t key) { 39 + sc_entry_t *e; 40 + HASH_FIND(hh, *table, &key, sizeof(ant_value_t), e); 41 + return e != NULL; 42 + } 43 + 44 + static void sc_free(sc_entry_t **table) { 45 + sc_entry_t *e, *tmp; 46 + HASH_ITER(hh, *table, e, tmp) { 47 + HASH_DEL(*table, e); 48 + free(e); 49 + } 50 + } 51 + 52 + static const char *sc_ta_type_name(TypedArrayType type) { 53 + static const char *names[] = { 54 + "Int8Array", "Uint8Array", "Uint8ClampedArray", 55 + "Int16Array", "Uint16Array", 56 + "Int32Array", "Uint32Array", 57 + "Float32Array", "Float64Array", 58 + "BigInt64Array", "BigUint64Array" 59 + }; 60 + int i = (int)type; 61 + if (i < 0 || i > 10) return "Uint8Array"; 62 + return names[i]; 63 + } 64 + 65 + static ant_value_t sc_clone_rec(ant_t *js, ant_value_t val, sc_entry_t **seen, sc_entry_t **transfer) { 66 + uint8_t t = vtype(val); 67 + 68 + if (t == T_UNDEF || t == T_NULL || t == T_BOOL || t == T_NUM || t == T_BIGINT || t == T_STR) return val; 69 + if (t == T_SYMBOL) return js_throw(js, make_dom_exception(js, "Symbol cannot be serialized", "DataCloneError")); 70 + 71 + if (t == T_TYPEDARRAY) { 72 + ant_value_t existing = sc_lookup(seen, val); 73 + if (vtype(existing) != T_UNDEF) return existing; 74 + 75 + TypedArrayData *ta = (TypedArrayData *)js_gettypedarray(val); 76 + if (!ta || !ta->buffer) 77 + return js_throw(js, make_dom_exception(js, "TypedArray could not be cloned", "DataCloneError")); 78 + 79 + ArrayBufferData *new_buf = create_array_buffer_data(ta->byte_length); 80 + if (!new_buf) return js_mkerr(js, "out of memory"); 81 + if (ta->byte_length > 0) memcpy(new_buf->data, ta->buffer->data + ta->byte_offset, ta->byte_length); 82 + 83 + ant_value_t clone = create_typed_array(js, ta->type, new_buf, 0, ta->length, sc_ta_type_name(ta->type)); 84 + sc_add(seen, val, clone); 85 + 86 + return clone; 87 + } 88 + 89 + if (t == T_FUNC || t == T_CFUNC || t == T_CLOSURE) 90 + return js_throw(js, make_dom_exception(js, "() => {} could not be cloned", "DataCloneError")); 91 + if (t == T_PROMISE || t == T_GENERATOR) 92 + return js_throw(js, make_dom_exception(js, "Value could not be cloned", "DataCloneError")); 93 + if (!is_object_type(val)) 94 + return js_throw(js, make_dom_exception(js, "Value could not be cloned", "DataCloneError")); 95 + 96 + ant_value_t existing = sc_lookup(seen, val); 97 + if (vtype(existing) != T_UNDEF) return existing; 98 + 99 + ant_value_t buf_slot_v = js_get_slot(val, SLOT_BUFFER); 100 + if (vtype(buf_slot_v) == T_NUM) { 101 + ArrayBufferData *abd = (ArrayBufferData *)(uintptr_t)(size_t)js_getnum(buf_slot_v); 102 + if (abd && !abd->is_detached) { 103 + if (transfer && sc_has(transfer, val)) { 104 + ArrayBufferData *new_abd = calloc(1, sizeof(ArrayBufferData)); 105 + if (!new_abd) return js_mkerr(js, "out of memory"); 106 + new_abd->data = abd->data; 107 + new_abd->length = abd->length; 108 + new_abd->capacity = abd->capacity; 109 + new_abd->ref_count = 1; 110 + abd->data = NULL; 111 + abd->length = 0; 112 + abd->capacity = 0; 113 + abd->is_detached = 1; 114 + js_set(js, val, "byteLength", js_mknum(0)); 115 + ant_value_t clone = create_arraybuffer_obj(js, new_abd); 116 + sc_add(seen, val, clone); 117 + return clone; 118 + } 119 + ArrayBufferData *new_abd = create_array_buffer_data(abd->length); 120 + if (!new_abd) return js_mkerr(js, "out of memory"); 121 + if (abd->length > 0) memcpy(new_abd->data, abd->data, abd->length); 122 + ant_value_t clone = create_arraybuffer_obj(js, new_abd); 123 + sc_add(seen, val, clone); 124 + return clone; 125 + }} 126 + 127 + if (t == T_ARR) { 128 + ant_value_t clone = js_mkarr(js); 129 + sc_add(seen, val, clone); 130 + 131 + ant_offset_t len = js_arr_len(js, val); 132 + for (ant_offset_t i = 0; i < len; i++) { 133 + ant_value_t ic = sc_clone_rec(js, js_arr_get(js, val, i), seen, transfer); 134 + if (is_err(ic)) return ic; 135 + js_arr_push(js, clone, ic); 136 + } 137 + 138 + return clone; 139 + } 140 + 141 + ant_object_t *obj_ptr = js_obj_ptr(val); 142 + if (!obj_ptr) 143 + return js_throw(js, make_dom_exception(js, "Value could not be cloned", "DataCloneError")); 144 + 145 + if (obj_ptr->type_tag == T_WEAKMAP || obj_ptr->type_tag == T_WEAKSET) 146 + return js_throw(js, make_dom_exception(js, "WeakMap/WeakSet could not be cloned", "DataCloneError")); 147 + 148 + if (obj_ptr->type_tag == T_MAP) { 149 + ant_value_t clone = js_mkobj(js); 150 + js_obj_ptr(clone)->type_tag = T_MAP; 151 + 152 + ant_value_t map_proto = js_get_ctor_proto(js, "Map", 3); 153 + if (is_special_object(map_proto)) js_set_proto_init(clone, map_proto); 154 + 155 + map_entry_t **new_head = ant_calloc(sizeof(map_entry_t *)); 156 + if (!new_head) return js_mkerr(js, "out of memory"); 157 + 158 + *new_head = NULL; 159 + js_set_slot(clone, SLOT_DATA, ANT_PTR(new_head)); 160 + sc_add(seen, val, clone); 161 + 162 + map_entry_t **src_head = get_map_from_obj(js, val); 163 + if (src_head && *src_head) { 164 + map_entry_t *e, *tmp; 165 + HASH_ITER(hh, *src_head, e, tmp) { 166 + ant_value_t vc = sc_clone_rec(js, e->value, seen, transfer); 167 + if (is_err(vc)) return vc; 168 + 169 + map_entry_t *ne = ant_calloc(sizeof(map_entry_t)); 170 + if (!ne) return js_mkerr(js, "out of memory"); 171 + ne->key = strdup(e->key); 172 + ne->value = vc; 173 + HASH_ADD_STR(*new_head, key, ne); 174 + }} 175 + 176 + return clone; 177 + } 178 + 179 + if (obj_ptr->type_tag == T_SET) { 180 + ant_value_t clone = js_mkobj(js); 181 + js_obj_ptr(clone)->type_tag = T_SET; 182 + 183 + ant_value_t set_proto = js_get_ctor_proto(js, "Set", 3); 184 + if (is_special_object(set_proto)) js_set_proto_init(clone, set_proto); 185 + 186 + set_entry_t **new_head = ant_calloc(sizeof(set_entry_t *)); 187 + if (!new_head) return js_mkerr(js, "out of memory"); 188 + *new_head = NULL; 189 + js_set_slot(clone, SLOT_DATA, ANT_PTR(new_head)); 190 + sc_add(seen, val, clone); 191 + 192 + set_entry_t **src_head = get_set_from_obj(js, val); 193 + if (src_head && *src_head) { 194 + set_entry_t *e, *tmp; 195 + HASH_ITER(hh, *src_head, e, tmp) { 196 + ant_value_t vc = sc_clone_rec(js, e->value, seen, transfer); 197 + if (is_err(vc)) return vc; 198 + 199 + set_entry_t *ne = ant_calloc(sizeof(set_entry_t)); 200 + if (!ne) return js_mkerr(js, "out of memory"); 201 + ne->key = strdup(e->key); 202 + ne->value = vc; 203 + HASH_ADD_STR(*new_head, key, ne); 204 + }} 205 + 206 + return clone; 207 + } 208 + 209 + if (js_get_slot(val, SLOT_ERROR_BRAND) == js_true) { 210 + ant_value_t clone = js_mkobj(js); 211 + sc_add(seen, val, clone); 212 + 213 + const char *msg = get_str_prop(js, val, "message", 7, NULL); 214 + const char *name = get_str_prop(js, val, "name", 4, NULL); 215 + const char *stack = get_str_prop(js, val, "stack", 5, NULL); 216 + 217 + if (msg) js_set(js, clone, "message", js_mkstr(js, msg, strlen(msg))); 218 + if (name) js_set(js, clone, "name", js_mkstr(js, name, strlen(name))); 219 + if (stack) js_set(js, clone, "stack", js_mkstr(js, stack, strlen(stack))); 220 + js_set_slot(clone, SLOT_ERROR_BRAND, js_true); 221 + 222 + ant_value_t err_type = js_get_slot(val, SLOT_ERR_TYPE); 223 + if (vtype(err_type) != T_UNDEF) js_set_slot(clone, SLOT_ERR_TYPE, err_type); 224 + 225 + return clone; 226 + } 227 + 228 + ant_value_t date_proto = js_get_ctor_proto(js, "Date", 4); 229 + if ( 230 + vtype(date_proto) != T_UNDEF 231 + && is_object_type(date_proto) 232 + && js_is_prototype_of(js, date_proto, val) 233 + ) { 234 + ant_value_t clone = js_mkobj(js); 235 + js_set_proto_init(clone, date_proto); 236 + js_set_slot(clone, SLOT_DATA, js_get_slot(val, SLOT_DATA)); 237 + sc_add(seen, val, clone); 238 + 239 + return clone; 240 + } 241 + 242 + blob_data_t *bd = js_is_prototype_of(js, g_blob_proto, val) ? blob_get_data(val) : NULL; 243 + if (bd) { 244 + ant_value_t clone = blob_create(js, bd->data, bd->size, bd->type); 245 + if (is_err(clone)) return clone; 246 + sc_add(seen, val, clone); 247 + if (bd->name) { 248 + blob_data_t *nbd = blob_get_data(clone); 249 + if (nbd) { 250 + nbd->name = strdup(bd->name); 251 + nbd->last_modified = bd->last_modified; 252 + } 253 + js_set_proto_init(clone, g_file_proto); 254 + } 255 + return clone; 256 + } 257 + 258 + ant_value_t clone = js_mkobj(js); 259 + sc_add(seen, val, clone); 260 + 261 + ant_iter_t iter = js_prop_iter_begin(js, val); 262 + const char *key; 263 + size_t key_len; 264 + ant_value_t pval; 265 + 266 + while (js_prop_iter_next(&iter, &key, &key_len, &pval)) { 267 + ant_value_t pc = sc_clone_rec(js, pval, seen, transfer); 268 + if (is_err(pc)) { js_prop_iter_end(&iter); return pc; } 269 + js_set(js, clone, key, pc); 270 + } 271 + 272 + js_prop_iter_end(&iter); 273 + return clone; 274 + } 275 + 276 + ant_value_t js_structured_clone(ant_t *js, ant_value_t *args, int nargs) { 277 + if (nargs < 1) return js_mkundef(); 278 + 279 + sc_entry_t *transfer = NULL; 280 + 281 + if (nargs < 2 || !is_object_type(args[1])) goto clone; 282 + ant_value_t xfer_arr = js_get(js, args[1], "transfer"); 283 + if (vtype(xfer_arr) != T_ARR) goto clone; 284 + 285 + ant_offset_t xfer_len = js_arr_len(js, xfer_arr); 286 + for (ant_offset_t i = 0; i < xfer_len; i++) { 287 + ant_value_t item = js_arr_get(js, xfer_arr, i); 288 + if (is_object_type(item)) sc_add(&transfer, item, js_true); 289 + } 290 + 291 + clone:; 292 + 293 + sc_entry_t *seen = NULL; 294 + ant_value_t result = sc_clone_rec(js, args[0], &seen, &transfer); 295 + sc_free(&seen); 296 + sc_free(&transfer); 297 + return result; 298 + } 299 + 300 + void init_structured_clone_module(void) { 301 + ant_t *js = rt->js; 302 + ant_value_t global = js_glob(js); 303 + 304 + js_set(js, global, "structuredClone", js_mkfun(js_structured_clone)); 305 + js_set_descriptor(js, global, "structuredClone", 15, JS_DESC_W | JS_DESC_C); 306 + }