@@ -5,13 +5,22 @@ pub mod write;
5
5
6
6
use rmp:: encode:: ByteBuf ;
7
7
use shopify_function_wasm_api_core:: ContextPtr ;
8
- use std:: ptr:: NonNull ;
8
+ use std:: { cell :: RefCell , ptr:: NonNull } ;
9
9
use string_interner:: StringInterner ;
10
10
use write:: State ;
11
11
12
12
pub const PROVIDER_MODULE_NAME : & str =
13
13
concat ! ( "shopify_function_v" , env!( "CARGO_PKG_VERSION_MAJOR" ) ) ;
14
14
15
+ // This serves 2 purposes:
16
+ // 1. Creating multiple contexts in Wasm won't cause a hang waiting for input
17
+ // on stdin.
18
+ // 2. Data in the context can be read by the host environment.
19
+ // Thread local values live for the same amount of time as the Wasm instance.
20
+ thread_local ! {
21
+ static CONTEXT : RefCell <Option <ContextPtr >> = const { RefCell :: new( None ) } ;
22
+ }
23
+
15
24
#[ cfg( target_pointer_width = "64" ) ]
16
25
type DoubleUsize = u128 ;
17
26
#[ cfg( target_pointer_width = "32" ) ]
@@ -93,12 +102,22 @@ pub(crate) use decorate_for_target;
93
102
#[ cfg( target_family = "wasm" ) ]
94
103
#[ export_name = "_shopify_function_context_new" ]
95
104
extern "C" fn shopify_function_context_new ( ) -> ContextPtr {
96
- Box :: into_raw ( Box :: new ( Context :: new_from_stdin ( ) ) ) as _
105
+ // Assuming this is called from a Wasm module, we should return a
106
+ // pre-existing context if there is one to avoid trying to read input
107
+ // multiple times.
108
+ CONTEXT . with_borrow_mut ( |option_ptr| {
109
+ * option_ptr. get_or_insert_with ( || Box :: into_raw ( Box :: new ( Context :: new_from_stdin ( ) ) ) as _ )
110
+ } )
97
111
}
98
112
99
113
#[ cfg( not( target_family = "wasm" ) ) ]
100
114
pub fn shopify_function_context_new_from_msgpack_bytes ( bytes : Vec < u8 > ) -> ContextPtr {
101
- Box :: into_raw ( Box :: new ( Context :: new ( bytes) ) ) as _
115
+ // Assuming this is called from a unit test, we should reset the context
116
+ // with the input passed as an argument instead of using any context that
117
+ // may have been present before.
118
+ CONTEXT . with_borrow_mut ( |option_ptr| {
119
+ * option_ptr. insert ( Box :: into_raw ( Box :: new ( Context :: new ( bytes) ) ) as _ )
120
+ } )
102
121
}
103
122
104
123
decorate_for_target ! {
0 commit comments