Skip to content

Commit 83b01d4

Browse files
authored
Merge pull request #25 from superwall/develop
Move to Sync callbacks, update Android NDK to support 16kb pages
2 parents ebf8a05 + b46d534 commit 83b01d4

File tree

5 files changed

+106
-32
lines changed

5 files changed

+106
-32
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
./wasm/pkg
1+
./wasm/pkg/
2+
./wasm/example/browser/build/
3+
./copy_to_ios_repo.sh
24
**/node_modules
35
.DS_Store
46
**/.DS_Store

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cel-eval"
3-
version = "0.2.4"
3+
version = "0.2.5"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.htmlž
@@ -12,7 +12,7 @@ path = "src/lib.rs"
1212
[dependencies]
1313
cel-interpreter = "0.8.1"
1414
cel-parser = "0.7.1"
15-
uniffi = { version = "0.28" }
15+
uniffi = { version = "0.29.2" }
1616
serde = { version = "1.0", features = ["serde_derive"] }
1717
serde_json = { version = "1.0" }
1818
async-trait = "0.1.81"
@@ -23,7 +23,7 @@ futures-lite = "2.3.0"
2323
[dev-dependencies]
2424
tokio = { version = "^1.20", features = ["rt-multi-thread", "macros"] }
2525
[build-dependencies]
26-
uniffi = { version = "0.28", features = [ "build" ] }
26+
uniffi = { version = "0.29.2", features = [ "build" ] }
2727

2828
[[bin]]
2929
name = "uniffi-bindgen"

build_android.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ set -e
44

55
echo "Building for Android x86_64, armv7, aarch64:"
66

7-
export ANDROID_NDK=r25b ANDROID_SDK=26 ANDROID_VERSION=11.0.0_r48
7+
export ANDROID_NDK=r28b ANDROID_SDK=26 ANDROID_VERSION=11.0.0_r48
88

99
build_targets=(
1010
"x86_64-linux-android"
@@ -13,6 +13,8 @@ build_targets=(
1313
"i686-linux-android"
1414
)
1515

16+
## If this fails, ensure you are using proper login to ghcr.io - create a new github PAT
17+
## echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin
1618
export CROSS_NO_WARNINGS=0
1719
for target in "${build_targets[@]}"; do
1820
rustup target add "$target"

src/cel.udl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
[Trait]
2+
interface ResultCallback {
3+
void on_result(string result);
4+
};
5+
16
[Trait, WithForeign]
27
interface HostContext {
3-
[Async]
4-
string computed_property(string name, string args);
5-
[Async]
6-
string device_property(string name, string args);
7-
8+
string computed_property(string name, string args, ResultCallback callback);
9+
string device_property(string name, string args, ResultCallback callback);
810
};
911

1012
namespace cel {

src/lib.rs

Lines changed: 90 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,25 @@ mod models;
55

66
use crate::ast::{ASTExecutionContext, JSONExpression};
77
use crate::models::PassableValue::Function;
8-
use crate::models::{ExecutionContext, PassableMap, PassableValue};
98
use crate::models::PassableValue::PMap;
9+
use crate::models::{ExecutionContext, PassableMap, PassableValue};
1010
use crate::ExecutableType::{CompiledProgram, AST};
11-
use async_trait::async_trait;
1211
use cel_interpreter::extractors::This;
1312
use cel_interpreter::objects::{Key, Map, TryIntoValue};
1413
use cel_interpreter::{Context, ExecutionError, Expression, FunctionContext, Program, Value};
14+
use cel_parser::parse;
1515
use std::collections::HashMap;
1616
use std::error::Error;
1717
use std::fmt;
1818
use std::fmt::Debug;
19+
use std::future::Future;
1920
use std::ops::Deref;
20-
use std::sync::{Arc, mpsc, Mutex};
21-
use std::thread::spawn;
22-
use cel_parser::parse;
21+
use std::pin::Pin;
22+
use std::sync::{Arc, Mutex};
23+
use std::task::{Poll, Waker};
2324

2425
#[cfg(target_arch = "wasm32")]
2526
use wasm_bindgen_futures::spawn_local;
26-
#[cfg(not(target_arch = "wasm32"))]
27-
use futures_lite::future::block_on;
28-
use uniffi::deps::log::__private_api::log;
2927

3028

3129
/**
@@ -43,11 +41,15 @@ pub trait HostContext: Send + Sync {
4341
}
4442

4543
#[cfg(not(target_arch = "wasm32"))]
46-
#[async_trait]
4744
pub trait HostContext: Send + Sync {
48-
async fn computed_property(&self, name: String, args: String) -> String;
45+
fn computed_property(&self, name: String, args: String, callback: Arc<dyn ResultCallback>) -> String;
4946

50-
async fn device_property(&self, name: String, args: String) -> String;
47+
fn device_property(&self, name: String, args: String, callback: Arc<dyn ResultCallback>) -> String;
48+
}
49+
50+
#[cfg(not(target_arch = "wasm32"))]
51+
pub trait ResultCallback: Send + Sync {
52+
fn on_result(&self, result: String);
5153
}
5254

5355
/**
@@ -109,9 +111,15 @@ pub fn evaluate_with_context(definition: String, host: Arc<dyn HostContext>) ->
109111
let data: Result<ExecutionContext,_> = serde_json::from_str(definition.as_str());
110112
let data: ExecutionContext = match data {
111113
Ok(data) => data,
112-
Err(_) => {
113-
let e : Result<ExecutionContext, String> = Err("Invalid execution context JSON".to_string());
114-
return serde_json::to_string(&e).unwrap()
114+
Err(e) => {
115+
let mut error_message = format!("Invalid execution context JSON: {}", e);
116+
// If there's a source (cause), add it
117+
if let Some(source) = e.source() {
118+
error_message = format!("{}\nCaused by: {}", error_message, source);
119+
}
120+
121+
let error_result: Result<_, String> = Err::<ASTExecutionContext,String>(error_message);
122+
return serde_json::to_string(&error_result).unwrap()
115123
}
116124
};
117125
let compiled = Program::compile(data.expression.as_str())
@@ -208,23 +216,44 @@ fn execute_with(
208216
} else {
209217
serde_json::to_string::<Vec<PassableValue>>(&vec![])
210218
};
211-
match args {
219+
let shared = Arc::new(Mutex::new(SharedState {
220+
result: None,
221+
waker: None,
222+
}));
223+
let callback = CallbackFuture {
224+
shared: shared.clone(),
225+
};
226+
227+
let result: Result<_,String> = match args {
212228
Ok(args) => {
213229
match prop_type {
214230
PropType::Computed => Ok(ctx.computed_property(
215231
name.clone().to_string(),
216232
args,
217-
).await),
233+
Arc::new(callback),
234+
)),
218235
PropType::Device => Ok(ctx.device_property(
219236
name.clone().to_string(),
220237
args,
221-
).await),
238+
Arc::new(callback),
239+
)),
222240
}
223241
}
224242
Err(e) => {
225243
Err(ExecutionError::UndeclaredReference(name).to_string())
226244
}
245+
};
246+
247+
match result {
248+
Ok(_) => {
249+
let future = CallbackFuture { shared }.await;
250+
Ok(future)
251+
}
252+
Err(e) => {
253+
Err(e)
254+
}
227255
}
256+
228257
});
229258
// Deserialize the value
230259
let passable: Result<PassableValue, String> =
@@ -451,6 +480,42 @@ impl fmt::Display for DisplayableError {
451480
}
452481
}
453482

483+
// We use this to turn the ResultCallback into a future we can await
484+
#[cfg(not(target_arch = "wasm32"))]
485+
impl ResultCallback for CallbackFuture {
486+
fn on_result(&self, result: String) {
487+
let mut shared = self.shared.lock().unwrap(); // Now valid
488+
shared.result = Some(result);
489+
if let Some(waker) = shared.waker.take() {
490+
waker.wake();
491+
}
492+
}
493+
}
494+
#[cfg(not(target_arch = "wasm32"))]
495+
pub struct CallbackFuture {
496+
shared: Arc<Mutex<SharedState>>,
497+
}
498+
499+
#[cfg(not(target_arch = "wasm32"))]
500+
struct SharedState {
501+
result: Option<String>,
502+
waker: Option<Waker>,
503+
}
504+
505+
#[cfg(not(target_arch = "wasm32"))]
506+
impl Future for CallbackFuture {
507+
type Output = String;
508+
509+
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
510+
let mut shared = self.shared.lock().unwrap();
511+
if let Some(result) = shared.result.take() {
512+
Poll::Ready(result)
513+
} else {
514+
shared.waker = Some(cx.waker().clone());
515+
Poll::Pending
516+
}
517+
}
518+
}
454519
#[cfg(test)]
455520
mod tests {
456521
use super::*;
@@ -459,14 +524,17 @@ mod tests {
459524
map: HashMap<String, String>,
460525
}
461526

462-
#[async_trait]
463527
impl HostContext for TestContext {
464-
async fn computed_property(&self, name: String, args: String) -> String {
465-
self.map.get(&name).unwrap().to_string()
528+
fn computed_property(&self, name: String, args: String, callback: Arc<dyn ResultCallback>)-> String {
529+
let result = self.map.get(&name).unwrap().to_string();
530+
callback.on_result(result.clone());
531+
result
466532
}
467533

468-
async fn device_property(&self, name: String, args: String) -> String {
469-
self.map.get(&name).unwrap().to_string()
534+
fn device_property(&self, name: String, args: String, callback: Arc<dyn ResultCallback>) -> String {
535+
let result = self.map.get(&name).unwrap().to_string();
536+
callback.on_result(result.clone());
537+
result
470538
}
471539
}
472540

0 commit comments

Comments
 (0)