package server-reason-react
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Rendering React components on the server natively
Install
dune-project
Dependency
Authors
Maintainers
Sources
server-reason-react-0.5.1.tbz
sha256=3972f64a3ec22b120b40137f74e7862629b2164e5bbf8b85489d4c7b8bc13288
sha512=24a52537c091c4b278ea5e468aa6786378f8b559ed2128e824b6f84f26c283856a30e7ef01aab6101087bd53b9bdc2ecd8152c00db10bccff67221b9c67318a0
doc/src/server-reason-react.js/Js_obj.ml.html
Source file Js_obj.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178(** Provide utilities for {!Js.t} *) module Internal = struct module Registry = Ephemeron.K1.Make (struct type t = Obj.t let equal (left : t) (right : t) = left == right let hash = Hashtbl.hash end) type entry = { method_name : string; js_name : string; mutable present : bool; get_boxed : unit -> Obj.t; set_boxed : Obj.t -> unit; } type metadata = { mutable order_rev : string list; mutable cached_keys : string array option; entries : (string, entry) Hashtbl.t; } (* Object registration is on the hot path: every [makeProps] (one per component instantiation) and every [%mel.obj] literal registers its entries. Materializing [metadata] eagerly costs a [Hashtbl.create] plus one [Hashtbl.replace] and one list cons per field — and building an [entry] costs a record plus two boxing closures per field — yet the metadata is only ever consulted by [keys]/[assign]/[merge], which almost never run on these objects. So the generated code registers a single [Deferred] thunk that builds all entries on demand instead of paying that cost per object construction. *) type state = Built of metadata | Deferred of (unit -> entry list) type slot = { mutable state : state } let registry : slot Registry.t = Registry.create 16 let empty_metadata () = { order_rev = []; cached_keys = Some [||]; entries = Hashtbl.create 8 } let add_key_in_order metadata js_name = metadata.order_rev <- js_name :: metadata.order_rev; metadata.cached_keys <- None let keys_in_order metadata = match metadata.cached_keys with | Some keys -> keys | None -> let keys = Array.of_list (List.rev metadata.order_rev) in metadata.cached_keys <- Some keys; keys let register_entry metadata entry = let was_present = match Hashtbl.find_opt metadata.entries entry.js_name with Some existing -> existing.present | None -> false in Hashtbl.replace metadata.entries entry.js_name entry; if entry.present && not was_present then add_key_in_order metadata entry.js_name let build_metadata slot entries = let metadata = empty_metadata () in List.iter (register_entry metadata) entries; slot.state <- Built metadata; metadata let force slot = match slot.state with Built metadata -> metadata | Deferred thunk -> build_metadata slot (thunk ()) let get_metadata object_ = match Registry.find_opt registry (Obj.repr object_) with None -> None | Some slot -> Some (force slot) let ensure_metadata object_ = match Registry.find_opt registry (Obj.repr object_) with | Some slot -> force slot | None -> let metadata = empty_metadata () in Registry.add registry (Obj.repr object_) { state = Built metadata }; metadata (* Builds the [entry] for a field cell on demand; only ever called from a [Deferred] thunk, so the record and its two boxing closures are not allocated on the object-construction hot path. *) let deferred_entry ~method_name ~js_name ~present cell = { method_name; js_name; present; get_boxed = (fun () -> Obj.repr !cell); set_boxed = (fun next -> cell := Obj.obj next); } let register_deferred object_ thunk = Registry.replace registry (Obj.repr object_) { state = Deferred thunk }; object_ let clone_entry entry = let cell = ref (entry.get_boxed ()) in { method_name = entry.method_name; js_name = entry.js_name; present = entry.present; get_boxed = (fun () -> !cell); set_boxed = (fun next -> cell := next); } let present_entries metadata = Array.fold_right (fun key acc -> match Hashtbl.find_opt metadata.entries key with | Some entry when entry.present -> entry :: acc | Some _ | None -> acc) (keys_in_order metadata) [] let build metadata = let present_entries = present_entries metadata in let object_ : < .. > = match present_entries with | [] -> ((object end : < >) :> < .. >) | _ -> let table = CamlinternalOO.create_table (Array.of_list (List.map (fun entry -> entry.method_name) present_entries)) in CamlinternalOO.init_class table; let object_ = CamlinternalOO.create_object table in List.iter (fun entry -> let label = CamlinternalOO.get_method_label table entry.method_name in let closure : CamlinternalOO.meth = Obj.obj (Obj.repr (fun (_self : CamlinternalOO.obj) -> entry.get_boxed ())) in CamlinternalOO.set_method table label closure) present_entries; CamlinternalOO.run_initializers object_ table; Obj.obj (Obj.repr object_) in Registry.replace registry (Obj.repr object_) { state = Built metadata }; object_ let copy_present_entries_into target_metadata source = match get_metadata source with | None -> () | Some source_metadata -> Array.iter (fun key -> match Hashtbl.find_opt source_metadata.entries key with | None -> () | Some source_entry -> ( match Hashtbl.find_opt target_metadata.entries key with | Some target_entry -> target_entry.set_boxed (source_entry.get_boxed ()); if not target_entry.present then add_key_in_order target_metadata key; target_entry.present <- true | None -> let cloned_entry = clone_entry source_entry in Hashtbl.add target_metadata.entries key cloned_entry; if cloned_entry.present then add_key_in_order target_metadata key)) (keys_in_order source_metadata) let assign_into target source = let target_metadata = ensure_metadata target in copy_present_entries_into target_metadata source; target let register_deferred_abstract object_ thunk = Obj.obj (Obj.repr (register_deferred object_ thunk)) end let empty () : < .. > = Internal.register_deferred_abstract ((object end : < >) :> < .. >) (fun () -> []) let assign target source = Internal.assign_into target source let merge () left right : < .. > = let metadata = Internal.empty_metadata () in Internal.copy_present_entries_into metadata left; Internal.copy_present_entries_into metadata right; let object_ : < .. > = Internal.build metadata in Obj.obj (Obj.repr object_) let keys object_ = match Internal.get_metadata object_ with | None -> [||] | Some metadata -> Array.copy (Internal.keys_in_order metadata)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>