1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use crate::jsutils::JsError;
use crate::quickjs_utils::atoms;
use crate::quickjs_utils::atoms::JSAtomRef;
use libquickjs_sys as q;
use std::os::raw::c_int;

#[allow(clippy::upper_case_acronyms)]
/// this is a wrapper struct for JSPropertyEnum struct in quickjs
/// it used primarily as a result of objects::get_own_property_names()
pub struct JSPropertyEnumRef {
    context: *mut q::JSContext,
    property_enum: *mut q::JSPropertyEnum,
    length: u32,
}

impl JSPropertyEnumRef {
    pub fn new(
        context: *mut q::JSContext,
        property_enum: *mut q::JSPropertyEnum,
        length: u32,
    ) -> Self {
        Self {
            context,
            property_enum,
            length,
        }
    }
    /// get a raw ptr to an Atom
    /// # Safety
    /// do not drop the JSPropertyEnumRef while still using the ptr
    pub unsafe fn get_atom_raw(&self, index: u32) -> *mut q::JSAtom {
        if index >= self.length {
            panic!("index out of bounds");
        }
        let prop: *mut q::JSPropertyEnum = self.property_enum.offset(index as isize);
        let atom: *mut q::JSAtom = (*prop).atom as *mut q::JSAtom;
        atom
    }
    pub fn get_atom(&self, index: u32) -> JSAtomRef {
        let atom: *mut q::JSAtom = unsafe { self.get_atom_raw(index) };
        let atom_ref = JSAtomRef::new(self.context, atom as q::JSAtom);
        atom_ref.increment_ref_ct();
        atom_ref
    }
    pub fn get_name(&self, index: u32) -> Result<String, JsError> {
        let atom: *mut q::JSAtom = unsafe { self.get_atom_raw(index) };
        let atom = atom as q::JSAtom;
        unsafe { Ok(atoms::to_str(self.context, &atom)?.to_string()) }
    }
    pub fn is_enumerable(&self, index: u32) -> bool {
        if index >= self.length {
            panic!("index out of bounds");
        }
        unsafe {
            let prop: *mut q::JSPropertyEnum = self.property_enum.offset(index as isize);
            let is_enumerable: c_int = (*prop).is_enumerable;
            is_enumerable != 0
        }
    }
    pub fn len(&self) -> u32 {
        self.length
    }
    pub fn is_empty(&self) -> bool {
        self.length == 0
    }
}

impl Drop for JSPropertyEnumRef {
    fn drop(&mut self) {
        unsafe {
            for index in 0..self.length {
                let prop: *mut q::JSPropertyEnum = self.property_enum.offset(index as isize);
                q::JS_FreeAtom(self.context, (*prop).atom);
            }

            q::js_free(self.context, self.property_enum as *mut std::ffi::c_void);
        }
    }
}