Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions integration_tests/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ fn decode_json_output(output: Vec<u8>) -> Result<serde_json::Value> {
}

fn prepare_wasm_api_input(input: serde_json::Value) -> Result<Vec<u8>> {
Ok(rmp_serde::to_vec(&input)?)
Ok(shopify_function_provider::json_to_custom_msgpack(&input))
}

fn prepare_wasi_json_input(input: serde_json::Value) -> Result<Vec<u8>> {
Expand Down Expand Up @@ -344,7 +344,7 @@ fn test_fuel_consumption_within_threshold() -> Result<()> {
let (_, wasm_api_fuel) = run_example("cart-checkout-validation-wasm-api", wasm_api_input)?;
eprintln!("WASM API fuel: {}", wasm_api_fuel);
// Using a target fuel value as reference similar to the Javy example
assert_fuel_consumed_within_threshold(15880, wasm_api_fuel);
assert_fuel_consumed_within_threshold(12801, wasm_api_fuel);
Ok(())
}

Expand Down Expand Up @@ -384,7 +384,7 @@ fn test_benchmark_comparison_with_input() -> Result<()> {
wasm_api_fuel, non_wasm_api_fuel, improvement
);

assert_fuel_consumed_within_threshold(15880, wasm_api_fuel);
assert_fuel_consumed_within_threshold(12829, wasm_api_fuel);
assert_fuel_consumed_within_threshold(23858, non_wasm_api_fuel);

Ok(())
Expand Down Expand Up @@ -427,7 +427,7 @@ fn test_benchmark_comparison_with_input_early_exit() -> Result<()> {
);

// Add fuel consumption threshold checks for both implementations
assert_fuel_consumed_within_threshold(17826, wasm_api_fuel);
assert_fuel_consumed_within_threshold(15930, wasm_api_fuel);
assert_fuel_consumed_within_threshold(736695, non_wasm_api_fuel);

Ok(())
Expand Down
4 changes: 3 additions & 1 deletion provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ crate-type = ["lib", "cdylib"]
[dependencies]
rmp = "0.8.14"
shopify_function_wasm_api_core = { path = "../core", version = "0.1.0" }
bumpalo = { version = "3.17.0", features = ["collections"] }

[target.'cfg(not(target_family = "wasm"))'.dependencies]
serde_json = "1.0"

[dev-dependencies]
paste = "1.0"
Expand Down
63 changes: 60 additions & 3 deletions provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pub mod read;
mod string_interner;
pub mod write;

#[cfg(not(target_family = "wasm"))]
use rmp::encode;
use rmp::encode::ByteBuf;
use shopify_function_wasm_api_core::ContextPtr;
use std::ptr::NonNull;
Expand All @@ -18,7 +20,6 @@ type DoubleUsize = u128;
type DoubleUsize = u64;

struct Context {
bump_allocator: bumpalo::Bump,
input_bytes: Vec<u8>,
output_bytes: ByteBuf,
write_state: State,
Expand All @@ -33,9 +34,7 @@ enum ContextError {

impl Context {
fn new(input_bytes: Vec<u8>) -> Self {
let bump_allocator = bumpalo::Bump::new();
Self {
bump_allocator,
input_bytes,
output_bytes: ByteBuf::new(),
write_state: State::Start,
Expand Down Expand Up @@ -112,3 +111,61 @@ decorate_for_target! {
}
}
}

#[cfg(not(target_family = "wasm"))]
pub fn json_to_custom_msgpack(json_value: &serde_json::Value) -> Vec<u8> {
let mut byte_buf = ByteBuf::new();
write_json_to_custom_msgpack(&mut byte_buf, json_value);
byte_buf.into_vec()
}

#[cfg(not(target_family = "wasm"))]
fn write_json_to_custom_msgpack(byte_buf: &mut ByteBuf, json_value: &serde_json::Value) {
match json_value {
serde_json::Value::Null => {
encode::write_nil(byte_buf).unwrap();
}
serde_json::Value::Bool(value) => {
encode::write_bool(byte_buf, *value).unwrap();
}
serde_json::Value::Number(value) => {
if value.is_i64() {
encode::write_sint(byte_buf, value.as_i64().unwrap()).unwrap();
} else if value.is_u64() {
encode::write_u64(byte_buf, value.as_u64().unwrap()).unwrap();
} else if value.is_f64() {
encode::write_f64(byte_buf, value.as_f64().unwrap()).unwrap();
} else {
panic!("Unsupported number type");
}
}
serde_json::Value::String(value) => {
encode::write_str(byte_buf, value.as_str()).unwrap();
}
serde_json::Value::Array(value) => {
let byte_len_idx = byte_buf.as_slice().len() + 1;
encode::write_ext_meta(byte_buf, u32::MAX, 16).unwrap();
let byte_array_start_idx = byte_buf.as_slice().len();
encode::write_array_len(byte_buf, value.len() as u32).unwrap();
for item in value {
write_json_to_custom_msgpack(byte_buf, item);
}
let byte_array_len = (byte_buf.as_slice().len() - byte_array_start_idx) as u32;
byte_buf.as_mut_vec()[byte_len_idx..byte_len_idx + 4]
.copy_from_slice(&byte_array_len.to_be_bytes());
}
serde_json::Value::Object(value) => {
let byte_len_idx = byte_buf.as_slice().len() + 1;
encode::write_ext_meta(byte_buf, u32::MAX, 16).unwrap();
let byte_map_start_idx = byte_buf.as_slice().len();
encode::write_map_len(byte_buf, value.len() as u32).unwrap();
for (key, value) in value {
encode::write_str(byte_buf, key.as_str()).unwrap();
write_json_to_custom_msgpack(byte_buf, value);
}
let byte_map_len = (byte_buf.as_slice().len() - byte_map_start_idx) as u32;
byte_buf.as_mut_vec()[byte_len_idx..byte_len_idx + 4]
.copy_from_slice(&byte_map_len.to_be_bytes());
}
}
}
27 changes: 10 additions & 17 deletions provider/src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@ use shopify_function_wasm_api_core::{
InternedStringId,
};

mod lazy_value_ref;
mod value_ref;

pub(crate) use lazy_value_ref::LazyValueRef;
pub(crate) use value_ref::ValueRef;

decorate_for_target! {
fn shopify_function_input_get(context: ContextPtr) -> Val {
match Context::ref_from_raw(context) {
Ok(context) => {
match context.bump_allocator.alloc_try_with(|| {
LazyValueRef::new(&context.input_bytes, 0, &context.bump_allocator)
.map(|(value, _)| value)
}) {
match ValueRef::new(&context.input_bytes, 0) {
Ok(input_ref) => input_ref.encode().to_bits(),
Err(e) => NanBox::error(e).to_bits(),
}
Expand All @@ -39,14 +36,13 @@ decorate_for_target! {
match v.try_decode() {
Ok(NanBoxValueRef::Object { ptr: obj_ptr, .. }) => {
let query = unsafe { std::slice::from_raw_parts(ptr as *const u8, len) };
let value = match LazyValueRef::mut_from_raw(obj_ptr as _) {
let value = match ValueRef::new(&context.input_bytes, obj_ptr) {
Ok(value) => value,
Err(e) => return NanBox::error(e).to_bits(),
};
match value.get_object_property(
query,
&context.input_bytes,
&context.bump_allocator,
) {
Ok(Some(value)) => value.encode().to_bits(),
Ok(None) => NanBox::null().to_bits(),
Expand Down Expand Up @@ -74,14 +70,13 @@ decorate_for_target! {
match v.try_decode() {
Ok(NanBoxValueRef::Object { ptr: obj_ptr, .. }) => {
let query = context.string_interner.get(interned_string_id);
let value = match LazyValueRef::mut_from_raw(obj_ptr as _) {
let value = match ValueRef::new(&context.input_bytes, obj_ptr) {
Ok(value) => value,
Err(e) => return NanBox::error(e).to_bits(),
};
match value.get_object_property(
query,
&context.input_bytes,
&context.bump_allocator,
) {
Ok(Some(value)) => value.encode().to_bits(),
Ok(None) => NanBox::null().to_bits(),
Expand All @@ -108,14 +103,13 @@ decorate_for_target! {
let v = NanBox::from_bits(scope);
match v.try_decode() {
Ok(NanBoxValueRef::Array { ptr, len: _ } | NanBoxValueRef::Object { ptr, len: _ }) => {
let value = match LazyValueRef::mut_from_raw(ptr as _) {
let value = match ValueRef::new(&context.input_bytes, ptr) {
Ok(value) => value,
Err(e) => return NanBox::error(e).to_bits(),
};
match value.get_at_index(
index,
&context.input_bytes,
&context.bump_allocator,
) {
Ok(value) => value.encode().to_bits(),
Err(e) => NanBox::error(e).to_bits(),
Expand All @@ -141,14 +135,13 @@ decorate_for_target! {
let v = NanBox::from_bits(scope);
match v.try_decode() {
Ok(NanBoxValueRef::Object { ptr, .. }) => {
let value = match LazyValueRef::mut_from_raw(ptr as _) {
let value = match ValueRef::new(&context.input_bytes, ptr) {
Ok(value) => value,
Err(e) => return NanBox::error(e).to_bits(),
};
match value.get_key_at_index(
index,
&context.input_bytes,
&context.bump_allocator,
) {
Ok(value) => value.encode().to_bits(),
Err(e) => NanBox::error(e).to_bits(),
Expand All @@ -166,12 +159,12 @@ decorate_for_target! {
decorate_for_target! {
fn shopify_function_input_get_val_len(context: ContextPtr, scope: Val) -> usize {
match Context::ref_from_raw(context) {
Ok(_) => {
Ok(context) => {
// don't actually need the context, but keeping it for consistency and to make it possible to use in the future if needed
let v = NanBox::from_bits(scope);
match v.try_decode() {
Ok(NanBoxValueRef::String { ptr, .. } | NanBoxValueRef::Array { ptr, .. } | NanBoxValueRef::Object { ptr, .. }) => {
let Ok(value) = LazyValueRef::mut_from_raw(ptr as _) else {
let Ok(value) = ValueRef::new(&context.input_bytes, ptr) else {
return usize::MAX;
};
value.get_value_length()
Expand All @@ -191,7 +184,7 @@ decorate_for_target! {
) -> usize {
match Context::ref_from_raw(context) {
Ok(context) => {
let Ok(value) = LazyValueRef::mut_from_raw(ptr as _) else {
let Ok(value) = ValueRef::new(&context.input_bytes, ptr) else {
return 0;
};
value.get_utf8_str_addr(&context.input_bytes)
Expand Down
Loading
Loading