1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtCore/qstring.h>
5#include <QtCore/qvarlengtharray.h>
6#include <QtCore/qdatetime.h>
7#include "qjsvalue.h"
8#include "qjsprimitivevalue.h"
9#include "qjsmanagedvalue.h"
10#include "qjsvalue_p.h"
11#include "qv4value_p.h"
12#include "qv4object_p.h"
13#include "qv4functionobject_p.h"
14#include "qv4dateobject_p.h"
15#include "qv4runtime_p.h"
16#include "qv4variantobject_p.h"
17#include "qv4regexpobject_p.h"
18#include "qv4errorobject_p.h"
19#include <private/qv4mm_p.h>
20#include <private/qv4jscall_p.h>
21#include <private/qv4qobjectwrapper_p.h>
22#include <private/qv4urlobject_p.h>
23
24/*!
25 \since 5.0
26 \class QJSValue
27
28 \brief The QJSValue class acts as a container for Qt/JavaScript data types.
29
30 \ingroup qtjavascript
31 \inmodule QtQml
32
33 QJSValue supports the types defined in the \l{ECMA-262}
34 standard: The primitive types, which are Undefined, Null, Boolean,
35 Number, and String; and the Object and Array types. Additionally, built-in
36 support is provided for Qt/C++ types such as QVariant and QObject.
37
38 For the object-based types (including Date and RegExp), use the
39 newT() functions in QJSEngine (e.g. QJSEngine::newObject())
40 to create a QJSValue of the desired type. For the primitive types,
41 use one of the QJSValue constructor overloads. For other types, e.g.
42 registered gadget types such as QPoint, you can use QJSEngine::toScriptValue.
43
44 The methods named isT() (e.g. isBool(), isUndefined()) can be
45 used to test if a value is of a certain type. The methods named
46 toT() (e.g. toBool(), toString()) can be used to convert a
47 QJSValue to another type. You can also use the generic
48 qjsvalue_cast() function.
49
50 Object values have zero or more properties which are themselves
51 QJSValues. Use setProperty() to set a property of an object, and
52 call property() to retrieve the value of a property.
53
54 \snippet code/src_script_qjsvalue.cpp 0
55
56 If you want to iterate over the properties of a script object, use
57 the QJSValueIterator class.
58
59 Object values have an internal \c{prototype} property, which can be
60 accessed with prototype() and setPrototype().
61
62 Function objects (objects for which isCallable()) returns true) can
63 be invoked by calling call(). Constructor functions can be used to
64 construct new objects by calling callAsConstructor().
65
66 Use equals() or strictlyEquals() to compare a QJSValue to another.
67
68 Note that a QJSValue for which isObject() is true only carries a
69 reference to an actual object; copying the QJSValue will only
70 copy the object reference, not the object itself. If you want to
71 clone an object (i.e. copy an object's properties to another
72 object), you can do so with the help of a \c{for-in} statement in
73 script code, or QJSValueIterator in C++.
74
75 \sa QJSEngine, QJSValueIterator
76
77 \section1 Working With Arrays
78
79 To create an array using QJSValue, use \l QJSEngine::newArray():
80
81 \code
82 // Assumes that this class was declared in QML.
83 QJSValue jsArray = engine->newArray(3);
84 \endcode
85
86 To set individual elements in the array, use
87 the \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)}
88 overload. For example, to fill the array above with integers:
89
90 \code
91 for (int i = 0; i < 3; ++i) {
92 jsArray.setProperty(i, QRandomGenerator::global().generate());
93 }
94 \endcode
95
96 To determine the length of the array, access the \c "length" property.
97 To access array elements, use the
98 \l {QJSValue::}{property(quint32 arrayIndex)} overload. The following code
99 reads the array we created above back into a list:
100
101 \code
102 QVector<int> integers;
103 const int length = jsArray.property("length").toInt();
104 for (int i = 0; i < length; ++i) {
105 integers.append(jsArray.property(i).toInt());
106 }
107 \endcode
108
109 \section2 Converting to JSON
110
111 It's possible to convert a QJSValue to a JSON type. For example,
112 to convert to an array, use \l QJSEngine::fromScriptValue():
113
114 \code
115 const QJsonValue jsonValue = engine.fromScriptValue<QJsonValue>(jsValue);
116 const QJsonArray jsonArray = jsonValue.toArray();
117 \endcode
118*/
119
120/*!
121 \enum QJSValue::SpecialValue
122
123 This enum is used to specify a single-valued type.
124
125 \value UndefinedValue An undefined value.
126
127 \value NullValue A null value.
128*/
129
130/*!
131 \typedef QJSValueList
132 \relates QJSValue
133
134 This is a typedef for a QList<QJSValue>.
135*/
136
137/*!
138 \enum QJSValue::ErrorType
139 \since 5.12
140
141 Use this enum for JavaScript language-specific types of Error objects.
142
143 They may be useful when emulating language features in C++ requires the use
144 of specialized exception types. In addition, they may help to more clearly
145 communicate certain typical conditions, instead of throwing a generic
146 JavaScript exception. For example, code that deals with networking and
147 resource locators may find it useful to propagate errors related to
148 malformed locators using the URIError type.
149
150 \omitvalue NoError
151 \value GenericError A generic Error object, but not of a specific sub-type.
152 \omitvalue EvalError
153 \value RangeError A value did not match the expected set or range.
154 \value ReferenceError A non-existing variable referenced.
155 \value SyntaxError An invalid token or sequence of tokens was encountered
156 that does not conform with the syntax of the language.
157 \value TypeError An operand or argument is incompatible with the type
158 expected.
159 \value URIError A URI handling function was used incorrectly or the URI
160 provided is malformed.
161*/
162
163/*!
164 \enum QJSValue::ObjectConversionBehavior
165
166 This enum is used to specify how JavaScript objects and symbols without an equivalent
167 native Qt type should be treated when converting to QVariant.
168
169 \value ConvertJSObjects A best-effort, possibly lossy, conversion is attempted.
170 Symbols are converted to QString.
171
172 \value RetainJSObjects The value is retained as QJSValue wrapped in QVariant.
173*/
174
175QT_BEGIN_NAMESPACE
176
177using namespace QV4;
178
179/*!
180 Constructs a new QJSValue with a boolean \a value.
181*/
182QJSValue::QJSValue(bool value) : d(QJSValuePrivate::encode(boolValue: value))
183{
184}
185
186/*!
187 Constructs a new QJSValue with a number \a value.
188*/
189QJSValue::QJSValue(int value) : d(QJSValuePrivate::encode(intValue: value))
190{
191}
192
193/*!
194 Constructs a new QJSValue with a number \a value.
195*/
196QJSValue::QJSValue(uint value) : d(QJSValuePrivate::encode(uintValue: value))
197{
198}
199
200/*!
201 Constructs a new QJSValue with a number \a value.
202*/
203QJSValue::QJSValue(double value) : d(QJSValuePrivate::encode(doubleValue: value))
204{
205}
206
207/*!
208 Constructs a new QJSValue with a string \a value.
209*/
210QJSValue::QJSValue(const QString &value) : d(QJSValuePrivate::encode(stringValue: value))
211{
212}
213
214/*!
215 Constructs a new QJSValue with a special \a value.
216*/
217QJSValue::QJSValue(SpecialValue value)
218 : d(value == NullValue ? QJSValuePrivate::encodeNull() : QJSValuePrivate::encodeUndefined())
219{
220}
221
222/*!
223 Constructs a new QJSValue with a string \a value.
224*/
225QJSValue::QJSValue(const QLatin1String &value) : d(QJSValuePrivate::encode(stringValue: value))
226{
227}
228
229/*!
230 Constructs a new QJSValue with a string \a value.
231*/
232#ifndef QT_NO_CAST_FROM_ASCII
233QJSValue::QJSValue(const char *value) : d(QJSValuePrivate::encode(stringValue: QString::fromUtf8(utf8: value)))
234{
235}
236#endif
237
238/*!
239 Constructs a new QJSValue that is a copy of \a other.
240
241 Note that if \a other is an object (i.e., isObject() would return
242 true), then only a reference to the underlying object is copied into
243 the new script value (i.e., the object itself is not copied).
244*/
245QJSValue::QJSValue(const QJSValue &other) : d(other.d)
246{
247 switch (QJSValuePrivate::tag(raw: d)) {
248 case QJSValuePrivate::Kind::Undefined:
249 case QJSValuePrivate::Kind::Null:
250 case QJSValuePrivate::Kind::IntValue:
251 case QJSValuePrivate::Kind::BoolValue:
252 return;
253 case QJSValuePrivate::Kind::DoublePtr:
254 d = QJSValuePrivate::encode(doubleValue: *QJSValuePrivate::doublePtr(v: d));
255 return;
256 case QJSValuePrivate::Kind::QV4ValuePtr:
257 d = QJSValuePrivate::encode(qv4Value: *QJSValuePrivate::qv4ValuePtr(v: d));
258 return;
259 case QJSValuePrivate::Kind::QStringPtr:
260 d = QJSValuePrivate::encode(stringValue: *QJSValuePrivate::qStringPtr(v: d));
261 break;
262 }
263}
264
265/*!
266 \fn QJSValue::QJSValue(QJSValue && other)
267
268 Move constructor. Moves from \a other into this QJSValue object.
269*/
270
271/*!
272 \fn QJSValue &QJSValue::operator=(QJSValue && other)
273
274 Move-assigns \a other to this QJSValue object.
275*/
276
277/*!
278 Destroys this QJSValue.
279*/
280QJSValue::~QJSValue()
281{
282 QJSValuePrivate::free(jsval: this);
283}
284
285/*!
286 Returns true if this QJSValue is of the primitive type Boolean;
287 otherwise returns false.
288
289 \sa toBool()
290*/
291bool QJSValue::isBool() const
292{
293 return QJSValuePrivate::tag(raw: d) == QJSValuePrivate::Kind::BoolValue;
294}
295
296/*!
297 Returns true if this QJSValue is of the primitive type Number;
298 otherwise returns false.
299
300 \sa toNumber()
301*/
302bool QJSValue::isNumber() const
303{
304 switch (QJSValuePrivate::tag(raw: d)) {
305 case QJSValuePrivate::Kind::IntValue:
306 case QJSValuePrivate::Kind::DoublePtr:
307 return true;
308 default:
309 break;
310 }
311
312 return false;
313}
314
315/*!
316 Returns true if this QJSValue is of the primitive type Null;
317 otherwise returns false.
318*/
319bool QJSValue::isNull() const
320{
321 return QJSValuePrivate::tag(raw: d) == QJSValuePrivate::Kind::Null;
322}
323
324/*!
325 Returns true if this QJSValue is of the primitive type String;
326 otherwise returns false.
327
328 \sa toString()
329*/
330bool QJSValue::isString() const
331{
332 switch (QJSValuePrivate::tag(raw: d)) {
333 case QJSValuePrivate::Kind::QStringPtr:
334 return true;
335 case QJSValuePrivate::Kind::QV4ValuePtr: {
336 return QJSValuePrivate::qv4ValuePtr(v: d)->isString();
337 }
338 default:
339 break;
340 }
341
342 return false;
343}
344
345/*!
346 Returns true if this QJSValue is of the primitive type Undefined or if the managed value
347 has been cleared (by deleting the engine). Otherwise returns false.
348*/
349bool QJSValue::isUndefined() const
350{
351 switch (QJSValuePrivate::tag(raw: d)) {
352 case QJSValuePrivate::Kind::Undefined:
353 return true;
354 case QJSValuePrivate::Kind::QV4ValuePtr:
355 return QJSValuePrivate::qv4ValuePtr(v: d)->isUndefined();
356 default:
357 break;
358 }
359
360 return false;
361}
362
363/*!
364 Returns true if this QJSValue is an object of the Error class;
365 otherwise returns false.
366
367 \sa errorType(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions}
368*/
369bool QJSValue::isError() const
370{
371 return QJSValuePrivate::asManagedType<ErrorObject>(jsval: this);
372}
373
374/*!
375 Returns true if this QJSValue is an object of the URL class;
376 otherwise returns false.
377*/
378bool QJSValue::isUrl() const
379{
380 return QJSValuePrivate::asManagedType<UrlObject>(jsval: this);
381}
382
383/*!
384 \since 5.12
385 Returns the error type this QJSValue represents if it is an Error object.
386 Otherwise, returns \c NoError."
387
388 \sa isError(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions}
389*/
390QJSValue::ErrorType QJSValue::errorType() const
391{
392 const QV4::ErrorObject *error = QJSValuePrivate::asManagedType<ErrorObject>(jsval: this);
393 if (!error)
394 return NoError;
395 switch (error->d()->errorType) {
396 case QV4::Heap::ErrorObject::Error:
397 return GenericError;
398 case QV4::Heap::ErrorObject::EvalError:
399 return EvalError;
400 case QV4::Heap::ErrorObject::RangeError:
401 return RangeError;
402 case QV4::Heap::ErrorObject::ReferenceError:
403 return ReferenceError;
404 case QV4::Heap::ErrorObject::SyntaxError:
405 return SyntaxError;
406 case QV4::Heap::ErrorObject::TypeError:
407 return TypeError;
408 case QV4::Heap::ErrorObject::URIError:
409 return URIError;
410 }
411 Q_UNREACHABLE_RETURN(NoError);
412}
413
414/*!
415 Returns true if this QJSValue is an object of the Array class;
416 otherwise returns false.
417
418 \sa QJSEngine::newArray()
419*/
420bool QJSValue::isArray() const
421{
422 return QJSValuePrivate::asManagedType<ArrayObject>(jsval: this);
423}
424
425/*!
426 Returns true if this QJSValue is of the Object type; otherwise
427 returns false.
428
429 Note that function values, variant values, and QObject values are
430 objects, so this function returns true for such values.
431
432 \sa QJSEngine::newObject()
433*/
434bool QJSValue::isObject() const
435{
436 return QJSValuePrivate::asManagedType<QV4::Object>(jsval: this);
437}
438
439/*!
440 Returns true if this QJSValue is a function, otherwise
441 returns false.
442
443 \sa call()
444*/
445bool QJSValue::isCallable() const
446{
447 return QJSValuePrivate::asManagedType<FunctionObject>(jsval: this);
448}
449
450/*!
451 Returns true if this QJSValue is a variant value;
452 otherwise returns false.
453
454 \sa toVariant()
455*/
456bool QJSValue::isVariant() const
457{
458 return QJSValuePrivate::asManagedType<QV4::VariantObject>(jsval: this);
459}
460
461/*!
462 Returns the string value of this QJSValue, as defined in
463 \l{ECMA-262} section 9.8, "ToString".
464
465 Note that if this QJSValue is an object, calling this function
466 has side effects on the script engine, since the engine will call
467 the object's toString() function (and possibly valueOf()) in an
468 attempt to convert the object to a primitive value (possibly
469 resulting in an uncaught script exception).
470
471 \sa isString()
472*/
473QString QJSValue::toString() const
474{
475 if (const QString *string = QJSValuePrivate::asQString(jsval: this))
476 return *string;
477
478 return QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: this)).toQStringNoThrow();
479}
480
481template<typename T>
482T caughtResult(const QJSValue *v, T (QV4::Value::*convert)() const)
483{
484 const T result = (QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: v)).*convert)();
485 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: v);
486 if (engine && engine->hasException) {
487 engine->catchException();
488 return T();
489 }
490 return result;
491}
492
493/*!
494 Returns the number value of this QJSValue, as defined in
495 \l{ECMA-262} section 9.3, "ToNumber".
496
497 Note that if this QJSValue is an object, calling this function
498 has side effects on the script engine, since the engine will call
499 the object's valueOf() function (and possibly toString()) in an
500 attempt to convert the object to a primitive value (possibly
501 resulting in an uncaught script exception).
502
503 \sa isNumber(), toInt(), toUInt()
504*/
505double QJSValue::toNumber() const
506{
507 if (const QString *string = QJSValuePrivate::asQString(jsval: this))
508 return RuntimeHelpers::stringToNumber(s: *string);
509
510 return caughtResult<double>(v: this, convert: &QV4::Value::toNumber);
511}
512
513/*!
514 Returns the boolean value of this QJSValue, using the conversion
515 rules described in \l{ECMA-262} section 9.2, "ToBoolean".
516
517 Note that if this QJSValue is an object, calling this function
518 has side effects on the script engine, since the engine will call
519 the object's valueOf() function (and possibly toString()) in an
520 attempt to convert the object to a primitive value (possibly
521 resulting in an uncaught script exception).
522
523 \sa isBool()
524*/
525bool QJSValue::toBool() const
526{
527 if (const QString *string = QJSValuePrivate::asQString(jsval: this))
528 return string->size() > 0;
529
530 return caughtResult<bool>(v: this, convert: &QV4::Value::toBoolean);
531}
532
533/*!
534 Returns the signed 32-bit integer value of this QJSValue, using
535 the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32".
536
537 Note that if this QJSValue is an object, calling this function
538 has side effects on the script engine, since the engine will call
539 the object's valueOf() function (and possibly toString()) in an
540 attempt to convert the object to a primitive value (possibly
541 resulting in an uncaught script exception).
542
543 \sa toNumber(), toUInt()
544*/
545qint32 QJSValue::toInt() const
546{
547 if (const QString *string = QJSValuePrivate::asQString(jsval: this))
548 return QV4::Value::toInt32(d: RuntimeHelpers::stringToNumber(s: *string));
549
550 return caughtResult<qint32>(v: this, convert: &QV4::Value::toInt32);
551}
552
553/*!
554 Returns the unsigned 32-bit integer value of this QJSValue, using
555 the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32".
556
557 Note that if this QJSValue is an object, calling this function
558 has side effects on the script engine, since the engine will call
559 the object's valueOf() function (and possibly toString()) in an
560 attempt to convert the object to a primitive value (possibly
561 resulting in an uncaught script exception).
562
563 \sa toNumber(), toInt()
564*/
565quint32 QJSValue::toUInt() const
566{
567 if (const QString *string = QJSValuePrivate::asQString(jsval: this))
568 return QV4::Value::toUInt32(d: RuntimeHelpers::stringToNumber(s: *string));
569
570 return caughtResult<quint32>(v: this, convert: &QV4::Value::toUInt32);
571}
572
573/*!
574 \overload
575
576 Returns toVariant(ConvertJSObjects).
577
578 \sa isVariant()
579*/
580QVariant QJSValue::toVariant() const
581{
582 return toVariant(behavior: ConvertJSObjects);
583}
584
585/*!
586 Returns the QVariant value of this QJSValue, if it can be
587 converted to a QVariant; otherwise returns an invalid QVariant.
588 Some JavaScript types and objects have native expressions in Qt.
589 Those are converted to their native expressions. For example:
590
591 \table
592 \header \li Input Type \li Result
593 \row \li Undefined \li An invalid QVariant.
594 \row \li Null \li A QVariant containing a null pointer (QMetaType::Nullptr).
595 \row \li Boolean \li A QVariant containing the value of the boolean.
596 \row \li Number \li A QVariant containing the value of the number.
597 \row \li String \li A QVariant containing the value of the string.
598 \row \li QVariant Object \li The result is the QVariant value of the object (no conversion).
599 \row \li QObject Object \li A QVariant containing a pointer to the QObject.
600 \row \li Date Object \li A QVariant containing the date value (toDateTime()).
601 \row \li RegularExpression Object \li A QVariant containing the regular expression value.
602 \endtable
603
604 For other types the \a behavior parameter is relevant. If
605 \c ConvertJSObjects is given, a best effort but possibly lossy conversion is
606 attempted. Generic JavaScript objects are converted to QVariantMap.
607 JavaScript arrays are converted to QVariantList. Each property or element is
608 converted to a QVariant, recursively; cyclic references are not followed.
609 JavaScript function objects are dropped. If \c RetainJSObjects is given, the
610 QJSValue is wrapped into a QVariant via QVariant::fromValue(). The resulting
611 conversion is lossless but the internal structure of the objects is not
612 immediately accessible.
613
614 \sa isVariant()
615*/
616QVariant QJSValue::toVariant(QJSValue::ObjectConversionBehavior behavior) const
617{
618 if (const QString *string = QJSValuePrivate::asQString(jsval: this))
619 return QVariant(*string);
620
621 QV4::Value val = QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: this));
622 if (val.isUndefined())
623 return QVariant();
624 if (val.isNull())
625 return QVariant(QMetaType::fromType<std::nullptr_t>(), nullptr);
626 if (val.isBoolean())
627 return QVariant(val.booleanValue());
628 if (val.isInt32()) // Includes doubles that can be losslessly casted to int
629 return QVariant(val.integerValue());
630 if (val.isNumber())
631 return QVariant(val.doubleValue());
632
633 Q_ASSERT(val.isManaged());
634
635 if (val.isString())
636 return QVariant(val.toQString());
637 if (val.as<QV4::Managed>()) {
638 return QV4::ExecutionEngine::toVariant(
639 value: val, /*typeHint*/ QMetaType{}, createJSValueForObjectsAndSymbols: behavior == RetainJSObjects);
640 }
641
642 Q_ASSERT(false);
643 return QVariant();
644}
645
646/*!
647 * Converts the value to a QJSPrimitiveValue. If the value holds a type
648 * supported by QJSPrimitiveValue, the value is copied. Otherwise the
649 * value is converted to a string, and the string is stored in
650 * QJSPrimitiveValue.
651 *
652 * \note Conversion of a managed value to a string can throw an exception. In
653 * particular, symbols cannot be coerced into strings, or a custom
654 * toString() method may throw. In this case the result is the undefined
655 * value and the engine carries an error after the conversion.
656 */
657QJSPrimitiveValue QJSValue::toPrimitive() const
658{
659 if (const QString *string = QJSValuePrivate::asQString(jsval: this))
660 return *string;
661
662 const QV4::Value val = QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: this));
663 return QV4::ExecutionEngine::createPrimitive(v: &val);
664}
665
666/*!
667 Calls this QJSValue as a function, passing \a args as arguments
668 to the function, and using the globalObject() as the "this"-object.
669 Returns the value returned from the function.
670
671 If this QJSValue is not callable, call() does nothing and
672 returns an undefined QJSValue.
673
674 Calling call() can cause an exception to occur in the script engine;
675 in that case, call() returns the value that was thrown (typically an
676 \c{Error} object). You can call isError() on the return value to
677 determine whether an exception occurred.
678
679 \sa isCallable(), callWithInstance(), callAsConstructor()
680*/
681QJSValue QJSValue::call(const QJSValueList &args) const
682{
683 const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(jsval: this);
684 if (!f)
685 return QJSValue();
686
687 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
688 Q_ASSERT(engine);
689
690 Scope scope(engine);
691 JSCallArguments jsCallData(scope, args.size());
692 *jsCallData.thisObject = engine->globalObject;
693 for (int i = 0; i < args.size(); ++i) {
694 if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) {
695 qWarning(msg: "QJSValue::call() failed: cannot call function with argument created in a different engine");
696 return QJSValue();
697 }
698 jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(e: engine, jsval: args.at(i));
699 }
700
701 ScopedValue result(scope, f->call(data: jsCallData));
702 if (engine->hasException)
703 result = engine->catchException();
704 if (engine->isInterrupted.loadRelaxed())
705 result = engine->newErrorObject(QStringLiteral("Interrupted"));
706
707 return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue());
708}
709
710/*!
711 Calls this QJSValue as a function, using \a instance as
712 the `this' object in the function call, and passing \a args
713 as arguments to the function. Returns the value returned from
714 the function.
715
716 If this QJSValue is not a function, call() does nothing
717 and returns an undefined QJSValue.
718
719 Note that if \a instance is not an object, the global object
720 (see \l{QJSEngine::globalObject()}) will be used as the
721 `this' object.
722
723 Calling call() can cause an exception to occur in the script engine;
724 in that case, call() returns the value that was thrown (typically an
725 \c{Error} object). You can call isError() on the return value to
726 determine whether an exception occurred.
727
728 \sa call()
729*/
730QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args) const
731{
732 const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(jsval: this);
733 if (!f)
734 return QJSValue();
735
736 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
737 Q_ASSERT(engine);
738 Scope scope(engine);
739
740 if (!QJSValuePrivate::checkEngine(e: engine, jsval: instance)) {
741 qWarning(msg: "QJSValue::call() failed: cannot call function with thisObject created in a different engine");
742 return QJSValue();
743 }
744
745 JSCallArguments jsCallData(scope, args.size());
746 *jsCallData.thisObject = QJSValuePrivate::convertToReturnedValue(e: engine, jsval: instance);
747 for (int i = 0; i < args.size(); ++i) {
748 if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) {
749 qWarning(msg: "QJSValue::call() failed: cannot call function with argument created in a different engine");
750 return QJSValue();
751 }
752 jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(e: engine, jsval: args.at(i));
753 }
754
755 ScopedValue result(scope, f->call(data: jsCallData));
756 if (engine->hasException)
757 result = engine->catchException();
758 if (engine->isInterrupted.loadRelaxed())
759 result = engine->newErrorObject(QStringLiteral("Interrupted"));
760
761 return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue());
762}
763
764/*!
765 Creates a new \c{Object} and calls this QJSValue as a
766 constructor, using the created object as the `this' object and
767 passing \a args as arguments. If the return value from the
768 constructor call is an object, then that object is returned;
769 otherwise the default constructed object is returned.
770
771 If this QJSValue is not a function, callAsConstructor() does
772 nothing and returns an undefined QJSValue.
773
774 Calling this function can cause an exception to occur in the
775 script engine; in that case, the value that was thrown
776 (typically an \c{Error} object) is returned. You can call
777 isError() on the return value to determine whether an
778 exception occurred.
779
780 \sa call(), QJSEngine::newObject()
781*/
782QJSValue QJSValue::callAsConstructor(const QJSValueList &args) const
783{
784 const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(jsval: this);
785 if (!f)
786 return QJSValue();
787
788 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
789 Q_ASSERT(engine);
790
791 Scope scope(engine);
792 JSCallArguments jsCallData(scope, args.size());
793 for (int i = 0; i < args.size(); ++i) {
794 if (!QJSValuePrivate::checkEngine(e: engine, jsval: args.at(i))) {
795 qWarning(msg: "QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
796 return QJSValue();
797 }
798 jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(e: engine, jsval: args.at(i));
799 }
800
801 ScopedValue result(scope, f->callAsConstructor(data: jsCallData));
802 if (engine->hasException)
803 result = engine->catchException();
804 if (engine->isInterrupted.loadRelaxed())
805 result = engine->newErrorObject(QStringLiteral("Interrupted"));
806
807 return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue());
808}
809
810/*!
811 If this QJSValue is an object, returns the internal prototype
812 (\c{__proto__} property) of this object; otherwise returns an
813 undefined QJSValue.
814
815 \sa setPrototype(), isObject()
816*/
817QJSValue QJSValue::prototype() const
818{
819 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
820 if (!engine)
821 return QJSValue();
822 QV4::Scope scope(engine);
823 ScopedObject o(scope, QJSValuePrivate::asManagedType<QV4::Object>(jsval: this));
824 if (!o)
825 return QJSValue();
826 ScopedObject p(scope, o->getPrototypeOf());
827 if (!p)
828 return QJSValue(NullValue);
829 return QJSValuePrivate::fromReturnedValue(d: p.asReturnedValue());
830}
831
832/*!
833 If this QJSValue is an object, sets the internal prototype
834 (\c{__proto__} property) of this object to be \a prototype;
835 if the QJSValue is null, it sets the prototype to null;
836 otherwise does nothing.
837
838 The internal prototype should not be confused with the public
839 property with name "prototype"; the public prototype is usually
840 only set on functions that act as constructors.
841
842 \sa prototype(), isObject()
843*/
844void QJSValue::setPrototype(const QJSValue& prototype)
845{
846 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
847 if (!engine)
848 return;
849 Scope scope(engine);
850 ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this));
851 if (!o)
852 return;
853 QV4::Value val = QV4::Value::fromReturnedValue(val: QJSValuePrivate::asReturnedValue(jsval: &prototype));
854 if (val.isNull()) {
855 o->setPrototypeOf(nullptr);
856 return;
857 }
858
859 ScopedObject p(scope, val);
860 if (!p)
861 return;
862 if (o->engine() != p->engine()) {
863 qWarning(msg: "QJSValue::setPrototype() failed: cannot set a prototype created in a different engine");
864 return;
865 }
866 if (!o->setPrototypeOf(p))
867 qWarning(msg: "QJSValue::setPrototype() failed: cyclic prototype value");
868}
869
870/*!
871 Assigns the \a other value to this QJSValue.
872
873 Note that if \a other is an object (isObject() returns true),
874 only a reference to the underlying object will be assigned;
875 the object itself will not be copied.
876*/
877QJSValue& QJSValue::operator=(const QJSValue& other)
878{
879 if (d == other.d)
880 return *this;
881
882 QJSValuePrivate::free(jsval: this);
883 d = 0;
884
885 if (const QString *string = QJSValuePrivate::asQString(jsval: &other))
886 QJSValuePrivate::setString(jsval: this, s: *string);
887 else
888 QJSValuePrivate::setValue(jsval: this, v: QJSValuePrivate::asReturnedValue(jsval: &other));
889
890 return *this;
891}
892
893QJSValue::QJSValue(QJSPrimitiveValue &&value)
894{
895 switch (value.type()) {
896 case QJSPrimitiveValue::Undefined:
897 d = QJSValuePrivate::encodeUndefined();
898 return;
899 case QJSPrimitiveValue::Null:
900 d = QJSValuePrivate::encodeNull();
901 return;
902 case QJSPrimitiveValue::Boolean:
903 d = QJSValuePrivate::encode(boolValue: value.asBoolean());
904 return;
905 case QJSPrimitiveValue::Integer:
906 d = QJSValuePrivate::encode(intValue: value.asInteger());
907 return;
908 case QJSPrimitiveValue::Double:
909 d = QJSValuePrivate::encode(doubleValue: value.asDouble());
910 return;
911 case QJSPrimitiveValue::String:
912 d = QJSValuePrivate::encode(stringValue: value.asString());
913 return;
914 }
915
916 Q_UNREACHABLE();
917}
918
919QJSValue::QJSValue(QJSManagedValue &&value)
920{
921 if (!value.d) {
922 d = QV4::Encode::undefined();
923 } else if (value.d->isManaged()) {
924 // If it's managed, we can adopt the persistent value.
925 QJSValuePrivate::adoptPersistentValue(jsval: this, v: value.d);
926 value.d = nullptr;
927 } else {
928 d = QJSValuePrivate::encode(qv4Value: *value.d);
929 QV4::PersistentValueStorage::free(v: value.d);
930 value.d = nullptr;
931 }
932}
933
934static bool js_equal(const QString &string, const QV4::Value &value)
935{
936 if (String *s = value.stringValue())
937 return string == s->toQString();
938 if (value.isNumber())
939 return RuntimeHelpers::stringToNumber(s: string) == value.asDouble();
940 if (value.isBoolean())
941 return RuntimeHelpers::stringToNumber(s: string) == double(value.booleanValue());
942 if (QV4::Object *o = value.objectValue()) {
943 Scope scope(o->engine());
944 ScopedValue p(scope, RuntimeHelpers::toPrimitive(value, typeHint: PREFERREDTYPE_HINT));
945 return js_equal(string, value: p);
946 }
947 return false;
948}
949
950/*!
951 Returns true if this QJSValue is equal to \a other, otherwise
952 returns false. The comparison follows the behavior described in
953 \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison
954 Algorithm".
955
956 This function can return true even if the type of this QJSValue
957 is different from the type of the \a other value; i.e. the
958 comparison is not strict. For example, comparing the number 9 to
959 the string "9" returns true; comparing an undefined value to a null
960 value returns true; comparing a \c{Number} object whose primitive
961 value is 6 to a \c{String} object whose primitive value is "6"
962 returns true; and comparing the number 1 to the boolean value
963 \c{true} returns true. If you want to perform a comparison
964 without such implicit value conversion, use strictlyEquals().
965
966 Note that if this QJSValue or the \a other value are objects,
967 calling this function has side effects on the script engine, since
968 the engine will call the object's valueOf() function (and possibly
969 toString()) in an attempt to convert the object to a primitive value
970 (possibly resulting in an uncaught script exception).
971
972 \sa strictlyEquals()
973*/
974bool QJSValue::equals(const QJSValue& other) const
975{
976 if (const QString *string = QJSValuePrivate::asQString(jsval: this)) {
977 if (const QString *otherString = QJSValuePrivate::asQString(jsval: &other))
978 return *string == *otherString;
979 return js_equal(string: *string, value: QJSValuePrivate::asReturnedValue(jsval: &other));
980 }
981
982 if (const QString *otherString = QJSValuePrivate::asQString(jsval: &other))
983 return js_equal(string: *otherString, value: QJSValuePrivate::asReturnedValue(jsval: this));
984
985 return Runtime::CompareEqual::call(QJSValuePrivate::asReturnedValue(jsval: this),
986 QJSValuePrivate::asReturnedValue(jsval: &other));
987}
988
989/*!
990 Returns true if this QJSValue is equal to \a other using strict
991 comparison (no conversion), otherwise returns false. The comparison
992 follows the behavior described in \l{ECMA-262} section 11.9.6, "The
993 Strict Equality Comparison Algorithm".
994
995 If the type of this QJSValue is different from the type of the
996 \a other value, this function returns false. If the types are equal,
997 the result depends on the type, as shown in the following table:
998
999 \table
1000 \header \li Type \li Result
1001 \row \li Undefined \li true
1002 \row \li Null \li true
1003 \row \li Boolean \li true if both values are true, false otherwise
1004 \row \li Number \li false if either value is NaN (Not-a-Number); true if values are equal, false otherwise
1005 \row \li String \li true if both values are exactly the same sequence of characters, false otherwise
1006 \row \li Object \li true if both values refer to the same object, false otherwise
1007 \endtable
1008
1009 \sa equals()
1010*/
1011bool QJSValue::strictlyEquals(const QJSValue& other) const
1012{
1013 if (const QString *string = QJSValuePrivate::asQString(jsval: this)) {
1014 if (const QString *otherString = QJSValuePrivate::asQString(jsval: &other))
1015 return *string == *otherString;
1016 if (const String *s = QJSValuePrivate::asManagedType<String>(jsval: &other))
1017 return *string == s->toQString();
1018 return false;
1019 }
1020
1021 if (const QString *otherString = QJSValuePrivate::asQString(jsval: &other)) {
1022 if (const String *s = QJSValuePrivate::asManagedType<String>(jsval: this))
1023 return *otherString == s->toQString();
1024 return false;
1025 }
1026
1027 return RuntimeHelpers::strictEqual(x: QJSValuePrivate::asReturnedValue(jsval: this),
1028 y: QJSValuePrivate::asReturnedValue(jsval: &other));
1029}
1030
1031/*!
1032 Returns the value of this QJSValue's property with the given \a name.
1033 If no such property exists, an undefined QJSValue is returned.
1034
1035 If the property is implemented using a getter function (i.e. has the
1036 PropertyGetter flag set), calling property() has side-effects on the
1037 script engine, since the getter function will be called (possibly
1038 resulting in an uncaught script exception). If an exception
1039 occurred, property() returns the value that was thrown (typically
1040 an \c{Error} object).
1041
1042 To access array elements, use the
1043 \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)}
1044 overload instead.
1045
1046 \sa setProperty(), hasProperty(), QJSValueIterator
1047*/
1048QJSValue QJSValue::property(const QString& name) const
1049{
1050 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1051 if (!engine)
1052 return QJSValue();
1053
1054 QV4::Scope scope(engine);
1055 ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1056 if (!o)
1057 return QJSValue();
1058
1059 ScopedString s(scope, engine->newString(s: name));
1060 QV4::ScopedValue result(scope, o->get(id: s->toPropertyKey()));
1061 if (engine->hasException)
1062 result = engine->catchException();
1063
1064 return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue());
1065}
1066
1067/*!
1068 \overload
1069
1070 Returns the property at the given \a arrayIndex.
1071
1072 It is possible to access elements in an array in two ways. The first is to
1073 use the array index as the property name:
1074
1075 \code
1076 qDebug() << jsValueArray.property(QLatin1String("4")).toString();
1077 \endcode
1078
1079 The second is to use the overload that takes an index:
1080
1081 \code
1082 qDebug() << jsValueArray.property(4).toString();
1083 \endcode
1084
1085 Both of these approaches achieve the same result, except that the latter:
1086
1087 \list
1088 \li Is easier to use (can use an integer directly)
1089 \li Is faster (no conversion to integer)
1090 \endlist
1091
1092 If this QJSValue is not an Array object, this function behaves
1093 as if property() was called with the string representation of \a
1094 arrayIndex.
1095*/
1096QJSValue QJSValue::property(quint32 arrayIndex) const
1097{
1098 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1099 if (!engine)
1100 return QJSValue();
1101
1102 QV4::Scope scope(engine);
1103 ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1104 if (!o)
1105 return QJSValue();
1106
1107 QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(name: engine->id_uintMax()) : o->get(idx: arrayIndex));
1108 if (engine->hasException)
1109 engine->catchException();
1110 return QJSValuePrivate::fromReturnedValue(d: result->asReturnedValue());
1111}
1112
1113/*!
1114 Sets the value of this QJSValue's property with the given \a name to
1115 the given \a value.
1116
1117 If this QJSValue is not an object, this function does nothing.
1118
1119 If this QJSValue does not already have a property with name \a name,
1120 a new property is created.
1121
1122 To modify array elements, use the
1123 \l {QJSValue::}{setProperty(quint32 arrayIndex, const QJSValue &value)}
1124 overload instead.
1125
1126 \sa property(), deleteProperty()
1127*/
1128void QJSValue::setProperty(const QString& name, const QJSValue& value)
1129{
1130 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1131 if (!engine)
1132 return;
1133 Scope scope(engine);
1134
1135 ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1136 if (!o)
1137 return;
1138
1139 if (!QJSValuePrivate::checkEngine(e: engine, jsval: value)) {
1140 qWarning(msg: "QJSValue::setProperty(%s) failed: cannot set value created in a different engine", name.toUtf8().constData());
1141 return;
1142 }
1143
1144 ScopedString s(scope, engine->newString(s: name));
1145 QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(e: engine, jsval: value));
1146 o->put(id: s->toPropertyKey(), v);
1147 if (engine->hasException)
1148 engine->catchException();
1149}
1150
1151/*!
1152 \overload
1153
1154 Sets the property at the given \a arrayIndex to the given \a value.
1155
1156 It is possible to modify elements in an array in two ways. The first is to
1157 use the array index as the property name:
1158
1159 \code
1160 jsValueArray.setProperty(QLatin1String("4"), value);
1161 \endcode
1162
1163 The second is to use the overload that takes an index:
1164
1165 \code
1166 jsValueArray.setProperty(4, value);
1167 \endcode
1168
1169 Both of these approaches achieve the same result, except that the latter:
1170
1171 \list
1172 \li Is easier to use (can use an integer directly)
1173 \li Is faster (no conversion to integer)
1174 \endlist
1175
1176 If this QJSValue is not an Array object, this function behaves
1177 as if setProperty() was called with the string representation of \a
1178 arrayIndex.
1179
1180 \sa {QJSValue::}{property(quint32 arrayIndex)}, {Working With Arrays}
1181*/
1182void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
1183{
1184 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1185 if (!engine)
1186 return;
1187 Scope scope(engine);
1188
1189 ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1190 if (!o)
1191 return;
1192
1193 if (!QJSValuePrivate::checkEngine(e: engine, jsval: value)) {
1194 qWarning(msg: "QJSValue::setProperty(%d) failed: cannot set value created in a different engine", arrayIndex);
1195 return;
1196 }
1197
1198 QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(e: engine, jsval: value));
1199 PropertyKey id = arrayIndex != UINT_MAX ? PropertyKey::fromArrayIndex(idx: arrayIndex) : engine->id_uintMax()->propertyKey();
1200 o->put(id, v);
1201 if (engine->hasException)
1202 engine->catchException();
1203}
1204
1205/*!
1206 Attempts to delete this object's property of the given \a name.
1207 Returns true if the property was deleted, otherwise returns false.
1208
1209 The behavior of this function is consistent with the JavaScript
1210 delete operator. In particular:
1211
1212 \list
1213 \li Non-configurable properties cannot be deleted.
1214 \li This function will return true even if this object doesn't
1215 have a property of the given \a name (i.e., non-existent
1216 properties are "trivially deletable").
1217 \li If this object doesn't have an own property of the given
1218 \a name, but an object in the prototype() chain does, the
1219 prototype object's property is not deleted, and this function
1220 returns true.
1221 \endlist
1222
1223 \sa setProperty(), hasOwnProperty()
1224*/
1225bool QJSValue::deleteProperty(const QString &name)
1226{
1227 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1228 if (!engine)
1229 return false;
1230
1231 Scope scope(engine);
1232 ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1233 if (!o)
1234 return false;
1235
1236 ScopedString s(scope, engine->newString(s: name));
1237 return o->deleteProperty(id: s->toPropertyKey());
1238}
1239
1240/*!
1241 Returns true if this object has a property of the given \a name,
1242 otherwise returns false.
1243
1244 \sa property(), hasOwnProperty()
1245*/
1246bool QJSValue::hasProperty(const QString &name) const
1247{
1248 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1249 if (!engine)
1250 return false;
1251
1252 Scope scope(engine);
1253 ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1254 if (!o)
1255 return false;
1256
1257 ScopedString s(scope, engine->newString(s: name));
1258 return o->hasProperty(id: s->toPropertyKey());
1259}
1260
1261/*!
1262 Returns true if this object has an own (not prototype-inherited)
1263 property of the given \a name, otherwise returns false.
1264
1265 \sa property(), hasProperty()
1266*/
1267bool QJSValue::hasOwnProperty(const QString &name) const
1268{
1269 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1270 if (!engine)
1271 return false;
1272
1273 Scope scope(engine);
1274 ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1275 if (!o)
1276 return false;
1277
1278 ScopedString s(scope, engine->newIdentifier(text: name));
1279 return o->getOwnProperty(id: s->propertyKey()) != Attr_Invalid;
1280}
1281
1282/*!
1283 * If this QJSValue is a QObject, returns the QObject pointer
1284 * that the QJSValue represents; otherwise, returns \nullptr.
1285 *
1286 * If the QObject that this QJSValue wraps has been deleted,
1287 * this function returns \nullptr (i.e. it is possible for toQObject()
1288 * to return \nullptr even when isQObject() returns true).
1289 *
1290 * \sa isQObject()
1291 */
1292QObject *QJSValue::toQObject() const
1293{
1294 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1295 if (!engine)
1296 return nullptr;
1297 QV4::Scope scope(engine);
1298 QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1299 if (!wrapper)
1300 return nullptr;
1301
1302 return wrapper->object();
1303}
1304
1305/*!
1306 \since 5.8
1307
1308 * If this QJSValue is a QMetaObject, returns the QMetaObject pointer
1309 * that the QJSValue represents; otherwise, returns \nullptr.
1310 *
1311 * \sa isQMetaObject()
1312 */
1313const QMetaObject *QJSValue::toQMetaObject() const
1314{
1315 QV4::ExecutionEngine *engine = QJSValuePrivate::engine(jsval: this);
1316 if (!engine)
1317 return nullptr;
1318 QV4::Scope scope(engine);
1319 QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::asReturnedValue(jsval: this));
1320 if (!wrapper)
1321 return nullptr;
1322
1323 return wrapper->metaObject();
1324}
1325
1326
1327/*!
1328 Returns a QDateTime representation of this value, in local time.
1329 If this QJSValue is not a date, or the value of the date is NaN
1330 (Not-a-Number), an invalid QDateTime is returned.
1331
1332 \sa isDate()
1333*/
1334QDateTime QJSValue::toDateTime() const
1335{
1336 if (const QV4::DateObject *date = QJSValuePrivate::asManagedType<DateObject>(jsval: this))
1337 return date->toQDateTime();
1338 return QDateTime();
1339}
1340
1341/*!
1342 Returns true if this QJSValue is an object of the Date class;
1343 otherwise returns false.
1344*/
1345bool QJSValue::isDate() const
1346{
1347 return QJSValuePrivate::asManagedType<DateObject>(jsval: this);
1348}
1349
1350/*!
1351 Returns true if this QJSValue is an object of the RegExp class;
1352 otherwise returns false.
1353*/
1354bool QJSValue::isRegExp() const
1355{
1356 return QJSValuePrivate::asManagedType<RegExpObject>(jsval: this);
1357}
1358
1359/*!
1360 Returns true if this QJSValue is a QObject; otherwise returns
1361 false.
1362
1363 Note: This function returns true even if the QObject that this
1364 QJSValue wraps has been deleted.
1365
1366 \sa toQObject(), QJSEngine::newQObject()
1367*/
1368bool QJSValue::isQObject() const
1369{
1370 return QJSValuePrivate::asManagedType<QV4::QObjectWrapper>(jsval: this);
1371}
1372
1373/*!
1374 \since 5.8
1375
1376 Returns true if this QJSValue is a QMetaObject; otherwise returns
1377 false.
1378
1379 \sa toQMetaObject(), QJSEngine::newQMetaObject()
1380*/
1381bool QJSValue::isQMetaObject() const
1382{
1383 return QJSValuePrivate::asManagedType<QV4::QMetaObjectWrapper>(jsval: this);
1384}
1385
1386#ifndef QT_NO_DATASTREAM
1387QDataStream &operator<<(QDataStream &stream, const QJSValue &jsv)
1388{
1389 quint32 isNullOrUndefined = 0;
1390 if (jsv.isNull())
1391 isNullOrUndefined |= 0x1;
1392 if (jsv.isUndefined())
1393 isNullOrUndefined |= 0x2;
1394 stream << isNullOrUndefined;
1395 if (!isNullOrUndefined) {
1396 const QVariant v = jsv.toVariant();
1397 switch (v.userType()) {
1398 case QMetaType::Bool:
1399 case QMetaType::Double:
1400 case QMetaType::Int:
1401 case QMetaType::QString:
1402 v.save(ds&: stream);
1403 break;
1404 default:
1405 qWarning() << "QDataStream::operator<< was to save a non-trivial QJSValue."
1406 << "This is not supported anymore, please stream a QVariant instead.";
1407 QVariant().save(ds&: stream);
1408 break;
1409 }
1410
1411 }
1412 return stream;
1413}
1414
1415QDataStream &operator>>(QDataStream &stream, QJSValue &jsv)
1416{
1417 quint32 isNullOrUndefined;
1418 stream >> isNullOrUndefined;
1419
1420 if (isNullOrUndefined & 0x1) {
1421 jsv = QJSValue(QJSValue::NullValue);
1422 } else if (isNullOrUndefined & 0x2) {
1423 jsv = QJSValue();
1424 } else {
1425 QVariant v;
1426 v.load(ds&: stream);
1427
1428 switch (v.userType()) {
1429 case QMetaType::Bool:
1430 jsv = QJSValue(v.toBool());
1431 break;
1432 case QMetaType::Double:
1433 jsv = QJSValue(v.toDouble());
1434 break;
1435 case QMetaType::Int:
1436 jsv = QJSValue(v.toInt());
1437 break;
1438 case QMetaType::QString:
1439 jsv = QJSValue(v.toString());
1440 break;
1441 default:
1442 qWarning() << "QDataStream::operator>> to restore a non-trivial QJSValue."
1443 << "This is not supported anymore, please stream a QVariant instead.";
1444 break;
1445 }
1446 }
1447 return stream;
1448}
1449#endif
1450
1451QT_END_NAMESPACE
1452

source code of qtdeclarative/src/qml/jsapi/qjsvalue.cpp