@@ -17,72 +17,163 @@ using namespace facebook::jsi;
17
17
namespace facebook {
18
18
namespace jsi {
19
19
20
- Value valueFromDynamic (Runtime& runtime, const folly::dynamic& dyn) {
20
+ namespace {
21
+
22
+ struct FromDynamic {
23
+ FromDynamic (const folly::dynamic* dynArg, Object objArg)
24
+ : dyn(dynArg), obj(std::move(objArg)) {}
25
+
26
+ const folly::dynamic* dyn;
27
+ Object obj;
28
+ };
29
+
30
+ // This converts one element. If it's a collection, it gets pushed onto
31
+ // the stack for later processing.
32
+ Value valueFromDynamicShallow (
33
+ Runtime& runtime,
34
+ std::vector<FromDynamic>& stack,
35
+ const folly::dynamic& dyn) {
21
36
switch (dyn.type ()) {
22
37
case folly::dynamic::NULLT:
23
38
return Value::null ();
24
39
case folly::dynamic::ARRAY: {
25
- Array ret = Array (runtime, dyn.size ());
26
- for (size_t i = 0 ; i < dyn.size (); ++i) {
27
- ret.setValueAtIndex (runtime, i, valueFromDynamic (runtime, dyn[i]));
28
- }
29
- return std::move (ret);
40
+ Object arr = Array (runtime, dyn.size ());
41
+ Value ret = Value (runtime, arr);
42
+ stack.emplace_back (&dyn, std::move (arr));
43
+ return ret;
30
44
}
31
45
case folly::dynamic::BOOL:
32
- return dyn.getBool ();
46
+ return Value ( dyn.getBool () );
33
47
case folly::dynamic::DOUBLE:
34
48
return dyn.getDouble ();
35
49
case folly::dynamic::INT64:
36
- // Can't use asDouble() here. If the int64 value is too bit to be
37
- // represented precisely as a double, folly will throw an
38
- // exception.
39
- return (double )dyn.getInt ();
50
+ return Value ((double )dyn.getInt ());
40
51
case folly::dynamic::OBJECT: {
41
- Object ret (runtime);
42
- for (const auto & element : dyn.items ()) {
43
- Value value = valueFromDynamic (runtime, element.second );
44
- if (element.first .isNumber () || element.first .isString ()) {
45
- ret.setProperty (
52
+ auto obj = Object (runtime);
53
+ Value ret = Value (runtime, obj);
54
+ stack.emplace_back (&dyn, std::move (obj));
55
+ return ret;
56
+ }
57
+ case folly::dynamic::STRING:
58
+ return Value (String::createFromUtf8 (runtime, dyn.getString ()));
59
+ }
60
+ CHECK (false );
61
+ }
62
+
63
+ } // namespace
64
+
65
+ Value valueFromDynamic (Runtime& runtime, const folly::dynamic& dynInput) {
66
+ std::vector<FromDynamic> stack;
67
+
68
+ Value ret = valueFromDynamicShallow (runtime, stack, dynInput);
69
+
70
+ while (!stack.empty ()) {
71
+ auto top = std::move (stack.back ());
72
+ stack.pop_back ();
73
+
74
+ switch (top.dyn ->type ()) {
75
+ case folly::dynamic::ARRAY: {
76
+ Array arr = std::move (top.obj ).getArray (runtime);
77
+ for (size_t i = 0 ; i < top.dyn ->size (); ++i) {
78
+ arr.setValueAtIndex (
46
79
runtime,
47
- PropNameID::forUtf8 (runtime, element.first .asString ()),
48
- value);
80
+ i,
81
+ valueFromDynamicShallow (runtime, stack, (*top.dyn )[i]));
82
+ }
83
+ break ;
84
+ }
85
+ case folly::dynamic::OBJECT: {
86
+ Object obj = std::move (top.obj );
87
+ for (const auto & element : top.dyn ->items ()) {
88
+ if (element.first .isNumber () || element.first .isString ()) {
89
+ obj.setProperty (
90
+ runtime,
91
+ PropNameID::forUtf8 (runtime, element.first .asString ()),
92
+ valueFromDynamicShallow (runtime, stack, element.second ));
93
+ }
49
94
}
95
+ break ;
50
96
}
51
- return std::move (ret);
97
+ default :
98
+ CHECK (false );
52
99
}
53
- case folly::dynamic::STRING:
54
- return String::createFromUtf8 (runtime, dyn.getString ());
55
100
}
56
- CHECK (false );
101
+
102
+ return ret;
57
103
}
58
104
59
- folly::dynamic dynamicFromValue (Runtime& runtime, const Value& value) {
105
+ namespace {
106
+
107
+ struct FromValue {
108
+ FromValue (folly::dynamic* dynArg, Object objArg)
109
+ : dyn(dynArg), obj(std::move(objArg)) {}
110
+
111
+ folly::dynamic* dyn;
112
+ Object obj;
113
+ };
114
+
115
+ // This converts one element. If it's a collection, it gets pushed
116
+ // onto the stack for later processing. The output is created by
117
+ // mutating the output argument, because we need its actual pointer to
118
+ // push onto the stack.
119
+ void dynamicFromValueShallow (
120
+ Runtime& runtime,
121
+ std::vector<FromValue>& stack,
122
+ const jsi::Value& value,
123
+ folly::dynamic& output) {
60
124
if (value.isUndefined () || value.isNull ()) {
61
- return nullptr ;
125
+ output = nullptr ;
62
126
} else if (value.isBool ()) {
63
- return value.getBool ();
127
+ output = value.getBool ();
64
128
} else if (value.isNumber ()) {
65
- return value.getNumber ();
129
+ output = value.getNumber ();
66
130
} else if (value.isString ()) {
67
- return value.getString (runtime).utf8 (runtime);
131
+ output = value.getString (runtime).utf8 (runtime);
68
132
} else {
133
+ CHECK (value.isObject ());
69
134
Object obj = value.getObject (runtime);
70
135
if (obj.isArray (runtime)) {
71
- Array array = obj.getArray (runtime);
72
- folly::dynamic ret = folly::dynamic::array ();
73
- for (size_t i = 0 ; i < array.size (runtime); ++i) {
74
- ret.push_back (
75
- dynamicFromValue (runtime, array.getValueAtIndex (runtime, i)));
76
- }
77
- return ret;
136
+ output = folly::dynamic::array ();
78
137
} else if (obj.isFunction (runtime)) {
79
138
throw JSError (runtime, " JS Functions are not convertible to dynamic" );
80
139
} else {
81
- folly::dynamic ret = folly::dynamic::object ();
82
- Array names = obj.getPropertyNames (runtime);
140
+ output = folly::dynamic::object ();
141
+ }
142
+ stack.emplace_back (&output, std::move (obj));
143
+ }
144
+ }
145
+
146
+ } // namespace
147
+
148
+ folly::dynamic dynamicFromValue (Runtime& runtime, const Value& valueInput) {
149
+ std::vector<FromValue> stack;
150
+ folly::dynamic ret;
151
+
152
+ dynamicFromValueShallow (runtime, stack, valueInput, ret);
153
+
154
+ while (!stack.empty ()) {
155
+ auto top = std::move (stack.back ());
156
+ stack.pop_back ();
157
+
158
+ if (top.obj .isArray (runtime)) {
159
+ // Inserting into a dyn can invalidate references into it, so we
160
+ // need to insert new elements up front, then push stuff onto
161
+ // the stack.
162
+ Array array = top.obj .getArray (runtime);
163
+ size_t arraySize = array.size (runtime);
164
+ for (size_t i = 0 ; i < arraySize; ++i) {
165
+ top.dyn ->push_back (nullptr );
166
+ }
167
+ for (size_t i = 0 ; i < arraySize; ++i) {
168
+ dynamicFromValueShallow (
169
+ runtime, stack, array.getValueAtIndex (runtime, i), top.dyn ->at (i));
170
+ }
171
+ } else {
172
+ Array names = top.obj .getPropertyNames (runtime);
173
+ std::vector<std::pair<std::string, jsi::Value>> props;
83
174
for (size_t i = 0 ; i < names.size (runtime); ++i) {
84
175
String name = names.getValueAtIndex (runtime, i).getString (runtime);
85
- Value prop = obj.getProperty (runtime, name);
176
+ Value prop = top. obj .getProperty (runtime, name);
86
177
if (prop.isUndefined ()) {
87
178
continue ;
88
179
}
@@ -92,12 +183,17 @@ folly::dynamic dynamicFromValue(Runtime& runtime, const Value& value) {
92
183
if (prop.isObject () && prop.getObject (runtime).isFunction (runtime)) {
93
184
prop = Value::null ();
94
185
}
95
- ret.insert (
96
- name.utf8 (runtime), dynamicFromValue (runtime, std::move (prop)));
186
+ props.emplace_back (name.utf8 (runtime), std::move (prop));
187
+ top.dyn ->insert (props.back ().first , nullptr );
188
+ }
189
+ for (const auto & prop : props) {
190
+ dynamicFromValueShallow (
191
+ runtime, stack, prop.second , (*top.dyn )[prop.first ]);
97
192
}
98
- return ret;
99
193
}
100
194
}
195
+
196
+ return ret;
101
197
}
102
198
103
199
} // namespace jsi
0 commit comments