Coverage Report

Created: 2025-06-16 06:50

/rust/git/checkouts/mozjs-fa11ffc7d4f1cc2d/d90edd1/mozjs-sys/src/jsval.rs
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#![allow(non_camel_case_types)]
6
#![allow(non_snake_case)]
7
8
use crate::jsapi::JSContext;
9
use crate::jsapi::JSObject;
10
use crate::jsapi::JSString;
11
use crate::jsapi::JSValueType;
12
use crate::jsapi::JS::BigInt;
13
use crate::jsapi::JS::Symbol;
14
use crate::jsapi::JS::TraceKind;
15
use crate::jsapi::JS::Value;
16
17
use libc::c_void;
18
use std::default::Default;
19
use std::mem;
20
21
pub type JSVal = Value;
22
23
#[cfg(target_pointer_width = "64")]
24
const JSVAL_TAG_SHIFT: usize = 47;
25
26
#[cfg(target_pointer_width = "64")]
27
const JSVAL_TAG_MAX_DOUBLE: u32 = 0x1FFF0u32;
28
29
#[cfg(target_pointer_width = "32")]
30
const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80;
31
32
#[cfg(target_pointer_width = "64")]
33
#[repr(u32)]
34
#[allow(dead_code)]
35
enum ValueTag {
36
    INT32 = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_INT32 as u32),
37
    UNDEFINED = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_UNDEFINED as u32),
38
    STRING = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_STRING as u32),
39
    SYMBOL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_SYMBOL as u32),
40
    BIGINT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BIGINT as u32),
41
    BOOLEAN = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BOOLEAN as u32),
42
    MAGIC = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_MAGIC as u32),
43
    NULL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_NULL as u32),
44
    OBJECT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_OBJECT as u32),
45
}
46
47
#[cfg(target_pointer_width = "32")]
48
#[repr(u32)]
49
#[allow(dead_code)]
50
enum ValueTag {
51
    PRIVATE = 0,
52
    INT32 = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_INT32 as u32),
53
    UNDEFINED = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_UNDEFINED as u32),
54
    STRING = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_STRING as u32),
55
    SYMBOL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_SYMBOL as u32),
56
    BIGINT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BIGINT as u32),
57
    BOOLEAN = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BOOLEAN as u32),
58
    MAGIC = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_MAGIC as u32),
59
    NULL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_NULL as u32),
60
    OBJECT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_OBJECT as u32),
61
}
62
63
#[cfg(target_pointer_width = "64")]
64
#[repr(u64)]
65
#[allow(dead_code)]
66
enum ValueShiftedTag {
67
    MAX_DOUBLE = ((JSVAL_TAG_MAX_DOUBLE as u64) << JSVAL_TAG_SHIFT) | 0xFFFFFFFFu64,
68
    INT32 = (ValueTag::INT32 as u64) << JSVAL_TAG_SHIFT,
69
    UNDEFINED = (ValueTag::UNDEFINED as u64) << JSVAL_TAG_SHIFT,
70
    STRING = (ValueTag::STRING as u64) << JSVAL_TAG_SHIFT,
71
    SYMBOL = (ValueTag::SYMBOL as u64) << JSVAL_TAG_SHIFT,
72
    BIGINT = (ValueTag::BIGINT as u64) << JSVAL_TAG_SHIFT,
73
    BOOLEAN = (ValueTag::BOOLEAN as u64) << JSVAL_TAG_SHIFT,
74
    MAGIC = (ValueTag::MAGIC as u64) << JSVAL_TAG_SHIFT,
75
    NULL = (ValueTag::NULL as u64) << JSVAL_TAG_SHIFT,
76
    OBJECT = (ValueTag::OBJECT as u64) << JSVAL_TAG_SHIFT,
77
}
78
79
const JSVAL_PAYLOAD_MASK: u64 = 0x00007FFFFFFFFFFF;
80
81
#[inline(always)]
82
118k
fn AsJSVal(val: u64) -> JSVal {
83
118k
    JSVal { asBits_: val }
84
118k
}
85
86
#[cfg(target_pointer_width = "64")]
87
#[inline(always)]
88
118k
fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal {
89
118k
    AsJSVal(((tag as u32 as u64) << JSVAL_TAG_SHIFT) | payload)
90
118k
}
91
92
#[cfg(target_pointer_width = "32")]
93
#[inline(always)]
94
fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal {
95
    AsJSVal(((tag as u32 as u64) << 32) | payload)
96
}
97
98
#[inline(always)]
99
0
pub fn NullValue() -> JSVal {
100
0
    BuildJSVal(ValueTag::NULL, 0)
101
0
}
102
103
#[inline(always)]
104
105k
pub fn UndefinedValue() -> JSVal {
105
105k
    BuildJSVal(ValueTag::UNDEFINED, 0)
106
105k
}
107
108
#[inline(always)]
109
0
pub fn Int32Value(i: i32) -> JSVal {
110
0
    BuildJSVal(ValueTag::INT32, i as u32 as u64)
111
0
}
112
113
#[cfg(target_pointer_width = "64")]
114
#[inline(always)]
115
0
pub fn DoubleValue(f: f64) -> JSVal {
116
0
    let bits: u64 = unsafe { mem::transmute(f) };
117
0
    assert!(bits <= ValueShiftedTag::MAX_DOUBLE as u64);
118
0
    AsJSVal(bits)
119
0
}
120
121
#[cfg(target_pointer_width = "32")]
122
#[inline(always)]
123
pub fn DoubleValue(f: f64) -> JSVal {
124
    let bits: u64 = unsafe { mem::transmute(f) };
125
    let val = AsJSVal(bits);
126
    assert!(val.is_double());
127
    val
128
}
129
130
#[inline(always)]
131
0
pub fn UInt32Value(ui: u32) -> JSVal {
132
0
    if ui > 0x7fffffff {
133
0
        DoubleValue(ui as f64)
134
    } else {
135
0
        Int32Value(ui as i32)
136
    }
137
0
}
138
139
#[cfg(target_pointer_width = "64")]
140
#[inline(always)]
141
13.1k
pub fn StringValue(s: &JSString) -> JSVal {
142
13.1k
    let bits = s as *const JSString as usize as u64;
143
13.1k
    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
144
13.1k
    BuildJSVal(ValueTag::STRING, bits)
145
13.1k
}
146
147
#[cfg(target_pointer_width = "32")]
148
#[inline(always)]
149
pub fn StringValue(s: &JSString) -> JSVal {
150
    let bits = s as *const JSString as usize as u64;
151
    BuildJSVal(ValueTag::STRING, bits)
152
}
153
154
#[inline(always)]
155
0
pub fn BooleanValue(b: bool) -> JSVal {
156
0
    BuildJSVal(ValueTag::BOOLEAN, b as u64)
157
0
}
158
159
#[cfg(target_pointer_width = "64")]
160
#[inline(always)]
161
0
pub fn ObjectValue(o: *mut JSObject) -> JSVal {
162
0
    let bits = o as usize as u64;
163
0
    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
164
0
    BuildJSVal(ValueTag::OBJECT, bits)
165
0
}
166
167
#[cfg(target_pointer_width = "32")]
168
#[inline(always)]
169
pub fn ObjectValue(o: *mut JSObject) -> JSVal {
170
    let bits = o as usize as u64;
171
    BuildJSVal(ValueTag::OBJECT, bits)
172
}
173
174
#[inline(always)]
175
0
pub fn ObjectOrNullValue(o: *mut JSObject) -> JSVal {
176
0
    if o.is_null() {
177
0
        NullValue()
178
    } else {
179
0
        ObjectValue(o)
180
    }
181
0
}
182
183
#[cfg(target_pointer_width = "64")]
184
#[inline(always)]
185
0
pub fn SymbolValue(s: &Symbol) -> JSVal {
186
0
    let bits = s as *const Symbol as usize as u64;
187
0
    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
188
0
    BuildJSVal(ValueTag::SYMBOL, bits)
189
0
}
190
191
#[cfg(target_pointer_width = "32")]
192
#[inline(always)]
193
pub fn SymbolValue(s: &Symbol) -> JSVal {
194
    let bits = s as *const Symbol as usize as u64;
195
    BuildJSVal(ValueTag::SYMBOL, bits)
196
}
197
198
#[cfg(target_pointer_width = "64")]
199
#[inline(always)]
200
0
pub fn BigIntValue(s: &BigInt) -> JSVal {
201
0
    let bits = s as *const BigInt as usize as u64;
202
0
    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
203
0
    BuildJSVal(ValueTag::BIGINT, bits)
204
0
}
205
206
#[cfg(target_pointer_width = "32")]
207
#[inline(always)]
208
pub fn BigIntValue(s: &BigInt) -> JSVal {
209
    let bits = s as *const BigInt as usize as u64;
210
    BuildJSVal(ValueTag::BIGINT, bits)
211
}
212
213
#[inline(always)]
214
0
pub fn PrivateValue(o: *const c_void) -> JSVal {
215
0
    let ptrBits = o as usize as u64;
216
0
    #[cfg(target_pointer_width = "64")]
217
0
    assert_eq!(ptrBits & 0xFFFF000000000000, 0);
218
0
    AsJSVal(ptrBits)
219
0
}
220
221
impl JSVal {
222
    #[inline(always)]
223
26.3k
    fn asBits(&self) -> u64 {
224
26.3k
        self.asBits_
225
26.3k
    }
226
227
    #[inline(always)]
228
    #[cfg(target_pointer_width = "64")]
229
0
    pub fn is_undefined(&self) -> bool {
230
0
        self.asBits() == ValueShiftedTag::UNDEFINED as u64
231
0
    }
232
233
    #[inline(always)]
234
    #[cfg(target_pointer_width = "32")]
235
    pub fn is_undefined(&self) -> bool {
236
        (self.asBits() >> 32) == ValueTag::UNDEFINED as u64
237
    }
238
239
    #[inline(always)]
240
    #[cfg(target_pointer_width = "64")]
241
0
    pub fn is_null(&self) -> bool {
242
0
        self.asBits() == ValueShiftedTag::NULL as u64
243
0
    }
244
245
    #[inline(always)]
246
    #[cfg(target_pointer_width = "32")]
247
    pub fn is_null(&self) -> bool {
248
        (self.asBits() >> 32) == ValueTag::NULL as u64
249
    }
250
251
    #[inline(always)]
252
0
    pub fn is_null_or_undefined(&self) -> bool {
253
0
        self.is_null() || self.is_undefined()
254
0
    }
255
256
    #[inline(always)]
257
    #[cfg(target_pointer_width = "64")]
258
0
    pub fn is_boolean(&self) -> bool {
259
0
        (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BOOLEAN as u64
260
0
    }
261
262
    #[inline(always)]
263
    #[cfg(target_pointer_width = "32")]
264
    pub fn is_boolean(&self) -> bool {
265
        (self.asBits() >> 32) == ValueTag::BOOLEAN as u64
266
    }
267
268
    #[inline(always)]
269
    #[cfg(target_pointer_width = "64")]
270
0
    pub fn is_int32(&self) -> bool {
271
0
        (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::INT32 as u64
272
0
    }
273
274
    #[inline(always)]
275
    #[cfg(target_pointer_width = "32")]
276
    pub fn is_int32(&self) -> bool {
277
        (self.asBits() >> 32) == ValueTag::INT32 as u64
278
    }
279
280
    #[inline(always)]
281
    #[cfg(target_pointer_width = "64")]
282
0
    pub fn is_double(&self) -> bool {
283
0
        self.asBits() <= ValueShiftedTag::MAX_DOUBLE as u64
284
0
    }
285
286
    #[inline(always)]
287
    #[cfg(target_pointer_width = "32")]
288
    pub fn is_double(&self) -> bool {
289
        (self.asBits() >> 32) <= JSVAL_TAG_CLEAR as u64
290
    }
291
292
    #[inline(always)]
293
    #[cfg(target_pointer_width = "64")]
294
0
    pub fn is_number(&self) -> bool {
295
        const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET: u64 = ValueShiftedTag::BOOLEAN as u64;
296
0
        self.asBits() < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET
297
0
    }
298
299
    #[inline(always)]
300
    #[cfg(target_pointer_width = "32")]
301
    pub fn is_number(&self) -> bool {
302
        const JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET: u64 = ValueTag::INT32 as u64;
303
        (self.asBits() >> 32) <= JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET
304
    }
305
306
    #[inline(always)]
307
    #[cfg(target_pointer_width = "64")]
308
0
    pub fn is_primitive(&self) -> bool {
309
        const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET: u64 = ValueShiftedTag::OBJECT as u64;
310
0
        self.asBits() < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET
311
0
    }
312
313
    #[inline(always)]
314
    #[cfg(target_pointer_width = "32")]
315
    pub fn is_primitive(&self) -> bool {
316
        const JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET: u64 = ValueTag::OBJECT as u64;
317
        (self.asBits() >> 32) < JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET
318
    }
319
320
    #[inline(always)]
321
    #[cfg(target_pointer_width = "64")]
322
13.1k
    pub fn is_string(&self) -> bool {
323
13.1k
        (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::STRING as u64
324
13.1k
    }
325
326
    #[inline(always)]
327
    #[cfg(target_pointer_width = "32")]
328
    pub fn is_string(&self) -> bool {
329
        (self.asBits() >> 32) == ValueTag::STRING as u64
330
    }
331
332
    #[inline(always)]
333
    #[cfg(target_pointer_width = "64")]
334
0
    pub fn is_object(&self) -> bool {
335
0
        assert!((self.asBits() >> JSVAL_TAG_SHIFT) <= ValueTag::OBJECT as u64);
336
0
        self.asBits() >= ValueShiftedTag::OBJECT as u64
337
0
    }
338
339
    #[inline(always)]
340
    #[cfg(target_pointer_width = "32")]
341
    pub fn is_object(&self) -> bool {
342
        (self.asBits() >> 32) == ValueTag::OBJECT as u64
343
    }
344
345
    #[inline(always)]
346
    #[cfg(target_pointer_width = "64")]
347
0
    pub fn is_object_or_null(&self) -> bool {
348
        const JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET: u64 = ValueShiftedTag::NULL as u64;
349
0
        assert!((self.asBits() >> JSVAL_TAG_SHIFT) <= ValueTag::OBJECT as u64);
350
0
        self.asBits() >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET
351
0
    }
352
353
    #[inline(always)]
354
    #[cfg(target_pointer_width = "32")]
355
    pub fn is_object_or_null(&self) -> bool {
356
        const JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET: u64 = ValueTag::NULL as u64;
357
        assert!((self.asBits() >> 32) <= ValueTag::OBJECT as u64);
358
        (self.asBits() >> 32) >= JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET
359
    }
360
361
    #[inline(always)]
362
    #[cfg(target_pointer_width = "64")]
363
0
    pub fn is_magic(&self) -> bool {
364
0
        (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::MAGIC as u64
365
0
    }
366
367
    #[inline(always)]
368
    #[cfg(target_pointer_width = "32")]
369
    pub fn is_magic(&self) -> bool {
370
        (self.asBits() >> 32) == ValueTag::MAGIC as u64
371
    }
372
373
    #[inline(always)]
374
    #[cfg(target_pointer_width = "64")]
375
0
    pub fn is_symbol(&self) -> bool {
376
0
        (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::SYMBOL as u64
377
0
    }
378
379
    #[inline(always)]
380
    #[cfg(target_pointer_width = "32")]
381
    pub fn is_symbol(&self) -> bool {
382
        (self.asBits() >> 32) == ValueTag::SYMBOL as u64
383
    }
384
385
    #[inline(always)]
386
    #[cfg(target_pointer_width = "64")]
387
0
    pub fn is_bigint(&self) -> bool {
388
0
        (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BIGINT as u64
389
0
    }
390
391
    #[inline(always)]
392
    #[cfg(target_pointer_width = "32")]
393
    pub fn is_bigint(&self) -> bool {
394
        (self.asBits() >> 32) == ValueTag::BIGINT as u64
395
    }
396
397
    #[inline(always)]
398
    #[cfg(target_pointer_width = "64")]
399
0
    pub fn is_gcthing(&self) -> bool {
400
        const JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET: u64 = ValueShiftedTag::STRING as u64;
401
0
        self.asBits() >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET
402
0
    }
403
404
    #[inline(always)]
405
    #[cfg(target_pointer_width = "32")]
406
    pub fn is_gcthing(&self) -> bool {
407
        const JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET: u64 = ValueTag::STRING as u64;
408
        (self.asBits() >> 32) >= JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET
409
    }
410
411
    #[inline(always)]
412
    #[cfg(target_pointer_width = "64")]
413
0
    pub fn to_boolean(&self) -> bool {
414
0
        assert!(self.is_boolean());
415
0
        (self.asBits() & JSVAL_PAYLOAD_MASK) != 0
416
0
    }
417
418
    #[inline(always)]
419
    #[cfg(target_pointer_width = "32")]
420
    pub fn to_boolean(&self) -> bool {
421
        (self.asBits() & 0x00000000FFFFFFFF) != 0
422
    }
423
424
    #[inline(always)]
425
0
    pub fn to_int32(&self) -> i32 {
426
0
        assert!(self.is_int32());
427
0
        (self.asBits() & 0x00000000FFFFFFFF) as i32
428
0
    }
429
430
    #[inline(always)]
431
0
    pub fn to_double(&self) -> f64 {
432
0
        assert!(self.is_double());
433
0
        unsafe { mem::transmute(self.asBits()) }
434
0
    }
435
436
    #[inline(always)]
437
0
    pub fn to_number(&self) -> f64 {
438
0
        assert!(self.is_number());
439
0
        if self.is_double() {
440
0
            self.to_double()
441
        } else {
442
0
            self.to_int32() as f64
443
        }
444
0
    }
445
446
    #[inline(always)]
447
    #[cfg(target_pointer_width = "64")]
448
13.1k
    pub fn to_string(&self) -> *mut JSString {
449
13.1k
        assert!(self.is_string());
450
13.1k
        let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK;
451
13.1k
        ptrBits as usize as *mut JSString
452
13.1k
    }
453
454
    #[inline(always)]
455
    #[cfg(target_pointer_width = "32")]
456
    pub fn to_string(&self) -> *mut JSString {
457
        assert!(self.is_string());
458
        let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32;
459
        ptrBits as *mut JSString
460
    }
461
462
    #[inline(always)]
463
0
    pub fn to_object(&self) -> *mut JSObject {
464
0
        assert!(self.is_object());
465
0
        self.to_object_or_null()
466
0
    }
467
468
    #[inline(always)]
469
    #[cfg(target_pointer_width = "64")]
470
0
    pub fn to_object_or_null(&self) -> *mut JSObject {
471
0
        assert!(self.is_object_or_null());
472
0
        let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK;
473
0
        assert!((ptrBits & 0x7) == 0);
474
0
        ptrBits as usize as *mut JSObject
475
0
    }
476
477
    #[inline(always)]
478
    #[cfg(target_pointer_width = "32")]
479
    pub fn to_object_or_null(&self) -> *mut JSObject {
480
        assert!(self.is_object_or_null());
481
        let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32;
482
        ptrBits as *mut JSObject
483
    }
484
485
    #[inline(always)]
486
0
    pub fn to_symbol(&self) -> *mut Symbol {
487
0
        assert!(self.is_symbol());
488
0
        let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK;
489
0
        assert!((ptrBits & 0x7) == 0);
490
0
        ptrBits as usize as *mut Symbol
491
0
    }
492
493
    #[inline(always)]
494
0
    pub fn to_bigint(&self) -> *mut BigInt {
495
0
        assert!(self.is_bigint());
496
0
        let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK;
497
0
        assert!((ptrBits & 0x7) == 0);
498
0
        ptrBits as usize as *mut BigInt
499
0
    }
500
501
    #[inline(always)]
502
0
    pub fn to_private(&self) -> *const c_void {
503
0
        assert!(self.is_double());
504
        #[cfg(target_pointer_width = "64")]
505
0
        assert_eq!(self.asBits() & 0xFFFF000000000000, 0);
506
0
        self.asBits() as usize as *const c_void
507
0
    }
508
509
    #[inline(always)]
510
    #[cfg(target_pointer_width = "64")]
511
0
    pub fn to_gcthing(&self) -> *mut c_void {
512
0
        assert!(self.is_gcthing());
513
0
        let ptrBits = self.asBits() & JSVAL_PAYLOAD_MASK;
514
0
        assert!((ptrBits & 0x7) == 0);
515
0
        ptrBits as *mut c_void
516
0
    }
517
518
    #[inline(always)]
519
    #[cfg(target_pointer_width = "32")]
520
    pub fn to_gcthing(&self) -> *mut c_void {
521
        assert!(self.is_gcthing());
522
        let ptrBits: u32 = (self.asBits() & 0x00000000FFFFFFFF) as u32;
523
        ptrBits as *mut c_void
524
    }
525
526
    #[inline(always)]
527
0
    pub fn is_markable(&self) -> bool {
528
0
        self.is_gcthing() && !self.is_null()
529
0
    }
530
531
    #[inline(always)]
532
0
    pub fn trace_kind(&self) -> TraceKind {
533
0
        assert!(self.is_markable());
534
0
        if self.is_object() {
535
0
            TraceKind::Object
536
0
        } else if self.is_string() {
537
0
            TraceKind::String
538
0
        } else if self.is_symbol() {
539
0
            TraceKind::Symbol
540
        } else {
541
0
            TraceKind::BigInt
542
        }
543
0
    }
544
}
545
546
impl Default for JSVal {
547
52.6k
    fn default() -> JSVal {
548
52.6k
        UndefinedValue()
549
52.6k
    }
550
}
551
552
#[inline(always)]
553
0
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
554
0
    vp.offset(2)
555
0
}
556
557
#[inline(always)]
558
0
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
559
0
    *vp
560
0
}
561
562
// These tests make sure that the Rust definitions agree with the C++ definitions.
563
#[test]
564
fn test_representation_agreement() {
565
    // Annoyingly, we can't check JSObject, JSString, etc. without creating a runtime,
566
    // since the constructor has checks that fail if we try mocking.  There are no-check
567
    // versions of the setters, but they're private.
568
    use crate::jsapi::glue::*;
569
    let mut val1 = UndefinedValue();
570
    let mut val2;
571
572
    unsafe {
573
        JS_ValueSetBoolean(&mut val1, true);
574
    }
575
    val2 = BooleanValue(true);
576
    assert_agreement(val1, val2);
577
578
    unsafe {
579
        JS_ValueSetDouble(&mut val1, 3.14159);
580
    }
581
    val2 = DoubleValue(3.14159);
582
    assert_agreement(val1, val2);
583
584
    unsafe {
585
        JS_ValueSetInt32(&mut val1, 37);
586
    }
587
    val2 = Int32Value(37);
588
    assert_agreement(val1, val2);
589
590
    unsafe {
591
        JS_ValueSetNull(&mut val1);
592
    }
593
    val2 = NullValue();
594
    assert_agreement(val1, val2);
595
}
596
597
#[cfg(test)]
598
fn assert_agreement(val1: JSVal, val2: JSVal) {
599
    use crate::jsapi::glue::*;
600
601
    assert_eq!(val1.asBits(), val2.asBits());
602
603
    assert_eq!(unsafe { JS_ValueIsBoolean(&val1) }, val2.is_boolean());
604
    if val2.is_boolean() {
605
        assert_eq!(unsafe { JS_ValueToBoolean(&val1) }, val2.to_boolean());
606
    }
607
608
    assert_eq!(unsafe { JS_ValueIsDouble(&val1) }, val2.is_double());
609
    if val2.is_double() {
610
        assert_eq!(unsafe { JS_ValueToDouble(&val1) }, val2.to_double());
611
    }
612
613
    assert_eq!(unsafe { JS_ValueIsInt32(&val1) }, val2.is_int32());
614
    if val2.is_int32() {
615
        assert_eq!(unsafe { JS_ValueToInt32(&val1) }, val2.to_int32());
616
    }
617
618
    assert_eq!(unsafe { JS_ValueIsNumber(&val1) }, val2.is_number());
619
    if val2.is_number() {
620
        assert_eq!(unsafe { JS_ValueToNumber(&val1) }, val2.to_number());
621
    }
622
623
    assert_eq!(unsafe { JS_ValueIsNull(&val1) }, val2.is_null());
624
625
    assert_eq!(unsafe { JS_ValueIsUndefined(&val1) }, val2.is_undefined());
626
}