Skip to content

Commit

Permalink
0.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
andrieshiemstra committed Mar 25, 2023
1 parent 74d6132 commit facb444
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 105 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# 0.5.7 (wip)
# 0.6.0

* AutoIdMap IDs are now random instead of sequential
* JSRealmAdapter::promise_cache_consume now returns an Option instead of panic on not found

# 0.5.7

* impl JsValueConvertable::to_jsValue_facade for serde::Value
* impl JsValueFacade::to_json_string for return types like JsValueFacade::JsObject (not input types like JsValueFacade::Object>)
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "hirofa_utils"
version = "0.5.7"
version = "0.5.8"
authors = ["HiRoFa <[email protected]>"]
edition = "2018"
description = "Utils project which is depended on by several other projects"
Expand All @@ -22,6 +22,7 @@ tokio = {version = "1", features = ["rt-multi-thread", "rt", "bytes", "fs", "io-
string_cache = "0.8"
serde = "1"
serde_json = "1"
rand = "0.8.5"

[dev-dependencies.cargo-husky]
version = "1.5.0"
Expand Down
57 changes: 39 additions & 18 deletions src/auto_id_map.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use rand::rngs::ThreadRng;
use rand::{thread_rng, Rng};
use std::collections::HashMap;

/// AutoIdMap is a wrapper around HashMap which automatically creates a unique id for it's entries
Expand All @@ -16,7 +18,7 @@ use std::collections::HashMap;
/// ```
pub struct AutoIdMap<T> {
max_size: usize,
last_id: usize,
rng: ThreadRng,
pub map: HashMap<usize, T>,
}

Expand All @@ -29,7 +31,7 @@ impl<T> AutoIdMap<T> {
pub fn new_with_max_size(max_size: usize) -> AutoIdMap<T> {
AutoIdMap {
max_size,
last_id: 0,
rng: thread_rng(),
map: HashMap::new(),
}
}
Expand Down Expand Up @@ -83,25 +85,27 @@ impl<T> AutoIdMap<T> {

/// insert an element and return the new id
pub fn insert(&mut self, elem: T) -> usize {
if self.map.len() >= self.max_size {
panic!("AutoIdMap is full");
}

self.last_id += 1;

if self.last_id >= self.max_size {
self.last_id = 0;
}
self.try_insert(elem).expect("map is full")
}

while self.map.contains_key(&self.last_id) {
if self.last_id >= self.max_size {
self.last_id = 0;
/// insert an element and return the new id
pub fn try_insert(&mut self, elem: T) -> Result<usize, &str> {
if self.map.len() >= self.max_size {
Err("AutoIdMap is full")
} else {
let mut id = self.rng.gen_range(0..self.max_size);

while self.map.contains_key(&id) {
if id >= self.max_size - 1 {
id = 0;
} else {
id += 1;
}
}
self.last_id += 1;
}

self.map.insert(self.last_id, elem);
self.last_id
self.map.insert(id, elem);
Ok(id)
}
}

/// replace an element, this will panic if you pass an id that is not present
Expand Down Expand Up @@ -179,4 +183,21 @@ pub mod tests {

assert_eq!(free_id, 5);
}

#[test]
fn test_aim_ms() {
let mut map = AutoIdMap::new_with_max_size(8);
for _x in 0..8 {
map.insert("foo");
}
assert_eq!(map.len(), 8);
map.remove(&5);
let free_id = map.insert("fail?");

assert_eq!(free_id, 5);

let res = map.try_insert("foobar");
// should be full
assert!(res.is_err());
}
}
2 changes: 1 addition & 1 deletion src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ pub mod tests {

#[test]
fn test_cache() {
let producer = |key: &&str| Some(format!("entry: {}", key));
let producer = |key: &&str| Some(format!("entry: {key}"));
let mut cache: Cache<&str, String> = Cache::new(producer, Duration::from_secs(2), 10);

test_send(&cache);
Expand Down
5 changes: 2 additions & 3 deletions src/js_utils/adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ pub trait JsRealmAdapter {
/// cache a JsPromiseAdapter so it can be accessed later based on an id, while cached the JsPromiseAdapter object will not be garbage collected
fn js_promise_cache_add(&self, promise_ref: Box<dyn JsPromiseAdapter<Self>>) -> usize;
/// Consume a JsPromiseAdapter (remove from cache)
fn js_promise_cache_consume(&self, id: usize) -> Box<dyn JsPromiseAdapter<Self>>;
fn js_promise_cache_consume(&self, id: usize) -> Option<Box<dyn JsPromiseAdapter<Self>>>;

/// cache a Object so it can be accessed later based on an id, while cached the Object will not be garbage collected
fn js_cache_add(&self, object: &Self::JsValueAdapterType) -> i32;
Expand Down Expand Up @@ -683,8 +683,7 @@ pub trait JsRealmAdapter {
let constructor = self.js_object_get_property(&global, constructor_name)?;
if constructor.js_is_null_or_undefined() {
Err(JsError::new_string(format!(
"no such constructor: {}",
constructor_name
"no such constructor: {constructor_name}"
)))
} else {
Ok(self.js_instance_of(object, &constructor))
Expand Down
138 changes: 73 additions & 65 deletions src/js_utils/adapters/promises.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ pub fn new_resolving_promise<P, R, M, T>(
producer: P,
mapper: M,
) -> Result<T::JsValueAdapterType, JsError>
where
T: JsRealmAdapter + 'static,
R: Send + 'static,
P: FnOnce() -> Result<R, JsError> + Send + 'static,
M: FnOnce(&<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType, R) -> Result<<<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType as JsRealmAdapter>::JsValueAdapterType, JsError> + Send + 'static,
where
T: JsRealmAdapter + 'static,
R: Send + 'static,
P: FnOnce() -> Result<R, JsError> + Send + 'static,
M: FnOnce(&<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType, R) -> Result<<<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType as JsRealmAdapter>::JsValueAdapterType, JsError> + Send + 'static,
{
// create promise
let promise_ref = realm.js_promise_create()?;
Expand All @@ -40,39 +40,43 @@ where

// in q_js_rt worker thread, resolve promise
// retrieve promise
let prom_ref: Box<(dyn JsPromiseAdapter<<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType> + 'static)> = realm.js_promise_cache_consume(id);
//let prom_ref = realm.js_promise_cache_consume(id);
match produced_result {
Ok(ok_res) => {
// map result to JSValueRef
let raw_res = mapper(realm, ok_res);
let prom_ref_opt: Option<Box<(dyn JsPromiseAdapter<<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType> + 'static)>> = realm.js_promise_cache_consume(id);
if let Some(prom_ref) = prom_ref_opt {
//let prom_ref = realm.js_promise_cache_consume(id);
match produced_result {
Ok(ok_res) => {
// map result to JSValueRef
let raw_res = mapper(realm, ok_res);

// resolve or reject promise
match raw_res {
Ok(val_ref) => {
prom_ref
.js_promise_resolve(realm, &val_ref)
.expect("prom resolution failed");
}
Err(err) => {
let err_ref = realm
.js_error_create(err.get_name(), err.get_message(), err.get_stack())
.expect("could not create str");
prom_ref
.js_promise_reject(realm, &err_ref)
.expect("prom rejection failed");
// resolve or reject promise
match raw_res {
Ok(val_ref) => {
prom_ref
.js_promise_resolve(realm, &val_ref)
.expect("prom resolution failed");
}
Err(err) => {
let err_ref = realm
.js_error_create(err.get_name(), err.get_message(), err.get_stack())
.expect("could not create str");
prom_ref
.js_promise_reject(realm, &err_ref)
.expect("prom rejection failed");
}
}
}
Err(err) => {
// todo use error:new_error(err)
let err_ref = realm
.js_error_create(err.get_name(), err.get_message(), err.get_stack())
.expect("could not create str");
prom_ref
.js_promise_reject(realm, &err_ref)
.expect("prom rejection failed");
}
}
Err(err) => {
// todo use error:new_error(err)
let err_ref = realm
.js_error_create(err.get_name(), err.get_message(), err.get_stack())
.expect("could not create str");
prom_ref
.js_promise_reject(realm, &err_ref)
.expect("prom rejection failed");
}
} else {
log::error!("async promise running for dropped realm: {} promise_id:{}", realm_id, id);
}
} else {
log::error!("async promise running for dropped realm: {}", realm_id);
Expand All @@ -99,7 +103,7 @@ pub(crate) fn new_resolving_promise_async<P, R, M, T>(
where
T: JsRealmAdapter + 'static,
R: Send + 'static,
P: Future<Output = Result<R, JsError>> + Send + 'static,
P: Future<Output=Result<R, JsError>> + Send + 'static,
M: FnOnce(&<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType, R) -> Result<<<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType as JsRealmAdapter>::JsValueAdapterType, JsError> + Send + 'static,
{
// create promise
Expand All @@ -113,47 +117,51 @@ pub(crate) fn new_resolving_promise_async<P, R, M, T>(

let realm_id = realm.js_get_realm_id().to_string();
// go async
let _ = add_helper_task_async(async move {
let _ignore_result = add_helper_task_async(async move {
// in helper thread, produce result
let produced_result = producer.await;
if let Some(rti) = rti_ref.upgrade() {
rti.js_add_rt_task_to_event_loop_void(move |rt| {
if let Some(realm) = rt.js_get_realm(realm_id.as_str()) {
// in q_js_rt worker thread, resolve promise
// retrieve promise
let prom_ref: Box<(dyn JsPromiseAdapter<<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType> + 'static)> = realm.js_promise_cache_consume(id);
//let prom_ref = realm.js_promise_cache_consume(id);
match produced_result {
Ok(ok_res) => {
// map result to JSValueRef
let raw_res = mapper(realm, ok_res);
let prom_ref_opt: Option<Box<(dyn JsPromiseAdapter<<<<<<<T as JsRealmAdapter>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeFacadeInnerType as JsRuntimeFacadeInner>::JsRuntimeFacadeType as JsRuntimeFacade>::JsRuntimeAdapterType as JsRuntimeAdapter>::JsRealmAdapterType> + 'static)>> = realm.js_promise_cache_consume(id);
if let Some(prom_ref) = prom_ref_opt {
//let prom_ref = realm.js_promise_cache_consume(id);
match produced_result {
Ok(ok_res) => {
// map result to JSValueRef
let raw_res = mapper(realm, ok_res);

// resolve or reject promise
match raw_res {
Ok(val_ref) => {
prom_ref
.js_promise_resolve(realm, &val_ref)
.expect("prom resolution failed");
}
Err(err) => {
let err_ref = realm
.js_error_create(err.get_name(), err.get_message(), err.get_stack())
.expect("could not create err");
prom_ref
.js_promise_reject(realm, &err_ref)
.expect("prom rejection failed");
// resolve or reject promise
match raw_res {
Ok(val_ref) => {
prom_ref
.js_promise_resolve(realm, &val_ref)
.expect("prom resolution failed");
}
Err(err) => {
let err_ref = realm
.js_error_create(err.get_name(), err.get_message(), err.get_stack())
.expect("could not create err");
prom_ref
.js_promise_reject(realm, &err_ref)
.expect("prom rejection failed");
}
}
}
Err(err) => {
// todo use error:new_error(err)
let err_ref = realm
.js_error_create(err.get_name(), err.get_message(), err.get_stack())
.expect("could not create str");
prom_ref
.js_promise_reject(realm, &err_ref)
.expect("prom rejection failed");
}
}
Err(err) => {
// todo use error:new_error(err)
let err_ref = realm
.js_error_create(err.get_name(), err.get_message(), err.get_stack())
.expect("could not create str");
prom_ref
.js_promise_reject(realm, &err_ref)
.expect("prom rejection failed");
}
} else {
log::error!("async promise running on dropped realm: {} promise_id:{}", realm_id, id);
}
} else {
log::error!("async promise running on dropped realm: {}", realm_id);
Expand Down
Loading

0 comments on commit facb444

Please sign in to comment.