Skip to content

Commit

Permalink
see #44
Browse files Browse the repository at this point in the history
  • Loading branch information
andrieshiemstra committed Apr 19, 2021
1 parent bec9250 commit e3880c2
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 109 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

* moved reflection code to reflection/mod.rs (should not affect api)
* toPrimitive for Proxy classes (do stuff like console.log('got: ' + MyProxyInstanceOrClass))
* removed droppablevalue, replaced with JSPropertyEnumRef

# 0.4.1

Expand Down
50 changes: 0 additions & 50 deletions src/droppable_value.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ macro_rules! es_args {
};
}

mod droppable_value;
pub mod eserror;
pub mod esruntime;
pub mod esruntime_utils;
Expand Down
12 changes: 11 additions & 1 deletion src/quickjs_utils/atoms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::quickjs_utils::primitives;
use crate::quickjscontext::QuickJsContext;
use crate::valueref::JSValueRef;
use libquickjs_sys as q;
use std::ffi::CString;
use std::ffi::{CStr, CString};

#[allow(clippy::upper_case_acronyms)]
pub struct JSAtomRef {
Expand Down Expand Up @@ -62,6 +62,16 @@ pub unsafe fn to_string2(context: *mut q::JSContext, atom: &q::JSAtom) -> Result
primitives::to_string(context, &val_ref)
}

/// # Safety
/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
pub unsafe fn to_str(context: *mut q::JSContext, atom: &q::JSAtom) -> Result<&str, EsError> {
let c_string = q::JS_AtomToCString(context, *atom);
let c_str = CStr::from_ptr(c_string);
c_str
.to_str()
.map_err(|e| EsError::new_string(format!("{}", e)))
}

pub fn from_string_q(q_ctx: &QuickJsContext, string: &str) -> Result<JSAtomRef, EsError> {
unsafe { from_string(q_ctx.context, string) }
}
Expand Down
1 change: 1 addition & 0 deletions src/quickjs_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod modules;
pub mod objects;
pub mod primitives;
pub mod promises;
pub mod properties;
pub mod sets;
pub mod typedarrays;

Expand Down
80 changes: 23 additions & 57 deletions src/quickjs_utils/objects.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
//! Utils for working with objects

use crate::droppable_value::DroppableValue;
use crate::eserror::EsError;
use crate::quickjs_utils::properties::JSPropertyEnumRef;
use crate::quickjs_utils::{atoms, functions, get_constructor, get_global};
use crate::quickjscontext::QuickJsContext;
use crate::quickjsruntime::{make_cstring, QuickJsRuntime};
use crate::valueref::JSValueRef;
use libquickjs_sys as q;
use std::collections::HashMap;

/// get a namespace object
/// this is used to get nested object properties which are used as namespaces
Expand Down Expand Up @@ -370,19 +369,23 @@ pub unsafe fn get_property(
Ok(prop_ref)
}

/// get the names of all properties of an object
pub fn get_property_names_q(
q_ctx: &QuickJsContext,
obj_ref: &JSValueRef,
) -> Result<Vec<String>, EsError> {
unsafe { get_property_names(q_ctx.context, obj_ref) }
}

/// get the names of all properties of an object
/// # Safety
/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
pub unsafe fn get_property_names(
context: *mut q::JSContext,
obj_ref: &JSValueRef,
) -> Result<Vec<String>, EsError> {
// todo wrap this in a get_own_property_names which returns the JSPropertyEnumRef

let mut properties: *mut q::JSPropertyEnum = std::ptr::null_mut();
let mut count: u32 = 0;

Expand All @@ -398,43 +401,25 @@ pub unsafe fn get_property_names(
return Err(EsError::new_str("Could not get object properties"));
}

let properties = DroppableValue::new(properties, |&mut properties| {
for index in 0..count {
let prop = properties.offset(index as isize);

q::JS_FreeAtom(context, (*prop).atom);
}
let enum_ref = JSPropertyEnumRef::new(context, properties, count);

q::js_free(context, properties as *mut std::ffi::c_void);
});
let mut names = vec![];

let mut res: Vec<String> = vec![];
for index in 0..count {
let prop = (*properties).offset(index as isize);

let key_value = q::JS_AtomToString(context, (*prop).atom);
let key_ref = JSValueRef::new(
context,
key_value,
false,
true,
"objects::get_property_names key_value",
);
if key_ref.is_exception() {
return Err(EsError::new_str("Could not get object property name"));
}
let atom = enum_ref.get_atom_raw(index) as q::JSAtom;
let name = atoms::to_str(context, &atom)?;

let key_str = crate::quickjs_utils::primitives::to_string(context, &key_ref)?;
res.push(key_str);
names.push(name.to_string());
}
Ok(res)

Ok(names)
}

pub fn traverse_properties_q<V, R>(
q_ctx: &QuickJsContext,
obj_ref: &JSValueRef,
visitor: V,
) -> Result<HashMap<String, R>, EsError>
) -> Result<Vec<R>, EsError>
where
V: Fn(&str, JSValueRef) -> Result<R, EsError>,
{
Expand All @@ -447,7 +432,7 @@ pub unsafe fn traverse_properties<V, R>(
context: *mut q::JSContext,
obj_ref: &JSValueRef,
visitor: V,
) -> Result<HashMap<String, R>, EsError>
) -> Result<Vec<R>, EsError>
where
V: Fn(&str, JSValueRef) -> Result<R, EsError>,
{
Expand All @@ -466,24 +451,18 @@ where
return Err(EsError::new_str("Could not get object properties"));
}

let properties = DroppableValue::new(properties, |&mut properties| {
for index in 0..count {
let prop = properties.offset(index as isize);
let enum_ref = JSPropertyEnumRef::new(context, properties, count);

q::JS_FreeAtom(context, (*prop).atom);
}

q::js_free(context, properties as *mut std::ffi::c_void);
});

let mut map = HashMap::new();
let mut result = vec![];

for index in 0..count {
let prop = (*properties).offset(index as isize);
let atom = enum_ref.get_atom_raw(index) as q::JSAtom;
let prop_name = atoms::to_str(context, &atom)?;

let raw_value = q::JS_GetPropertyInternal(
context,
*obj_ref.borrow_value(),
(*prop).atom,
atom,
*obj_ref.borrow_value(),
0,
);
Expand All @@ -498,25 +477,12 @@ where
return Err(EsError::new_str("Could not get object property"));
}

let key_value = q::JS_AtomToString(context, (*prop).atom);
let key_ref = JSValueRef::new(
context,
key_value,
false,
true,
"objects::traverse_properties key_value",
);
if key_ref.is_exception() {
return Err(EsError::new_str("Could not get object property name"));
}

let key_str = crate::quickjs_utils::primitives::to_string(context, &key_ref)?;
let r = visitor(key_str.as_str(), prop_val_ref)?;
let r = visitor(prop_name, prop_val_ref)?;

map.insert(key_str, r);
result.push(r);
}

Ok(map)
Ok(result)
}

pub fn is_instance_of_q(
Expand Down
49 changes: 49 additions & 0 deletions src/quickjs_utils/properties.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use crate::quickjs_utils::atoms::JSAtomRef;
use libquickjs_sys as q;

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,
}
}
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();
return atom_ref;
}
}

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);
}
}
}

0 comments on commit e3880c2

Please sign in to comment.