mozjs_sys/
jsid.rs

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
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#![allow(non_snake_case)]
6
7use crate::jsapi::JS::Symbol;
8use crate::jsapi::{jsid, JSString};
9use libc::c_void;
10
11#[deprecated]
12pub const JSID_VOID: jsid = VoidId();
13
14const JSID_TYPE_MASK: usize = 0x7;
15
16#[repr(usize)]
17enum PropertyKeyTag {
18    Int = 0x1,
19    String = 0x0,
20    Void = 0x2,
21    Symbol = 0x4,
22}
23
24#[inline(always)]
25const fn AsPropertyKey(bits: usize) -> jsid {
26    jsid { asBits_: bits }
27}
28
29#[inline(always)]
30pub const fn VoidId() -> jsid {
31    AsPropertyKey(PropertyKeyTag::Void as usize)
32}
33
34#[inline(always)]
35pub fn IntId(i: i32) -> jsid {
36    assert!(i >= 0);
37    AsPropertyKey((((i as u32) << 1) as usize) | (PropertyKeyTag::Int as usize))
38}
39
40#[inline(always)]
41pub fn SymbolId(symbol: *mut Symbol) -> jsid {
42    assert!(!symbol.is_null());
43    assert_eq!((symbol as usize) & JSID_TYPE_MASK, 0);
44    AsPropertyKey((symbol as usize) | (PropertyKeyTag::Symbol as usize))
45}
46
47#[inline(always)]
48/// <https://searchfox.org/mozilla-central/rev/1f65969e57c757146e3e548614b49d3a4168eeb8/js/public/Id.h#183>
49pub fn StringId(s: *mut JSString) -> jsid {
50    assert!(!s.is_null());
51    assert_eq!((s as usize) & JSID_TYPE_MASK, 0);
52    AsPropertyKey((s as usize) | (PropertyKeyTag::String as usize))
53}
54
55impl jsid {
56    #[inline(always)]
57    fn asBits(&self) -> usize {
58        self.asBits_
59    }
60
61    #[inline(always)]
62    pub fn is_void(&self) -> bool {
63        self.asBits() == (PropertyKeyTag::Void as usize)
64    }
65
66    #[inline(always)]
67    pub fn is_int(&self) -> bool {
68        (self.asBits() & (PropertyKeyTag::Int as usize)) != 0
69    }
70
71    #[inline(always)]
72    pub fn is_string(&self) -> bool {
73        (self.asBits() & JSID_TYPE_MASK) == (PropertyKeyTag::String as usize)
74    }
75
76    #[inline(always)]
77    pub fn is_symbol(&self) -> bool {
78        (self.asBits() & JSID_TYPE_MASK) == (PropertyKeyTag::Symbol as usize)
79    }
80
81    #[inline(always)]
82    pub fn is_gcthing(&self) -> bool {
83        self.is_string() && self.is_symbol()
84    }
85
86    #[inline(always)]
87    pub fn to_int(&self) -> i32 {
88        assert!(self.is_int());
89        ((self.asBits() as u32) >> 1) as i32
90    }
91
92    #[inline(always)]
93    pub fn to_string(&self) -> *mut JSString {
94        assert!(self.is_string());
95        (self.asBits() ^ (PropertyKeyTag::String as usize)) as *mut JSString
96    }
97
98    #[inline(always)]
99    pub fn to_symbol(&self) -> *mut Symbol {
100        assert!(self.is_symbol());
101        (self.asBits() ^ (PropertyKeyTag::Symbol as usize)) as *mut Symbol
102    }
103
104    #[inline(always)]
105    pub fn to_gcthing(&self) -> *mut c_void {
106        assert!(self.is_gcthing());
107        (self.asBits() ^ JSID_TYPE_MASK) as *mut c_void
108    }
109}
110
111#[test]
112fn test_representation() {
113    let id = VoidId();
114    assert!(id.is_void());
115
116    let id = IntId(0);
117    assert!(id.is_int());
118    assert_eq!(id.to_int(), 0);
119
120    let id = IntId(i32::MAX);
121    assert!(id.is_int());
122    assert_eq!(id.to_int(), i32::MAX);
123}