1#![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)]
48pub 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}