1
1
#![ allow( dead_code) ]
2
2
3
- use super :: error:: { exception_already_thrown, ExceptionThrown } ;
3
+ use super :: error:: { exception_already_thrown, ExcResult , ExceptionThrown , ExceptionValue , Throwable , TypeError } ;
4
4
use super :: from_value:: { cast, FromValue } ;
5
+ use core:: cell:: RefCell ;
5
6
use core:: fmt;
6
7
use core:: iter:: { repeat_n, RepeatN } ;
8
+ use core:: marker:: PhantomData ;
7
9
use core:: mem:: MaybeUninit ;
8
10
use derive_more:: From ;
9
- use spacetimedb_sats:: de:: {
10
- self , ArrayVisitor , DeserializeSeed , NoneAccess , ProductVisitor , SliceVisitor , SomeAccess , SumVisitor ,
11
- } ;
11
+ use spacetimedb_sats:: de:: { self , ArrayVisitor , DeserializeSeed , ProductVisitor , SliceVisitor , SumVisitor } ;
12
12
use spacetimedb_sats:: { i256, u256} ;
13
13
use std:: borrow:: { Borrow , Cow } ;
14
+ use std:: rc:: Rc ;
14
15
use v8:: { Array , Global , HandleScope , Local , Name , Object , Uint8Array , Value } ;
15
16
17
+ /// Returns a `KeyCache` for the current `scope`.
18
+ ///
19
+ /// Creates the cache in the scope if it doesn't exist yet.
20
+ pub ( super ) fn get_or_create_key_cache ( scope : & mut HandleScope < ' _ > ) -> Rc < RefCell < KeyCache > > {
21
+ let context = scope. get_current_context ( ) ;
22
+ context. get_slot :: < RefCell < KeyCache > > ( ) . unwrap_or_else ( || {
23
+ let cache = Rc :: default ( ) ;
24
+ context. set_slot ( Rc :: clone ( & cache) ) ;
25
+ cache
26
+ } )
27
+ }
28
+
29
+ /// Deserializes a `T` from `val` in `scope`, using `seed` for any context needed.
30
+ pub ( super ) fn deserialize_js_seed < ' de , T : DeserializeSeed < ' de > > (
31
+ scope : & mut HandleScope < ' de > ,
32
+ val : Local < ' _ , Value > ,
33
+ seed : T ,
34
+ ) -> ExcResult < T :: Output > {
35
+ let key_cache = get_or_create_key_cache ( scope) ;
36
+ let key_cache = & mut * key_cache. borrow_mut ( ) ;
37
+ let de = Deserializer :: new ( scope, val, key_cache) ;
38
+ seed. deserialize ( de) . map_err ( |e| e. throw ( scope) )
39
+ }
40
+
41
+ /// Deserializes a `T` from `val` in `scope`.
42
+ pub ( super ) fn deserialize_js < ' de , T : de:: Deserialize < ' de > > (
43
+ scope : & mut HandleScope < ' de > ,
44
+ val : Local < ' _ , Value > ,
45
+ ) -> ExcResult < T > {
46
+ deserialize_js_seed ( scope, val, PhantomData )
47
+ }
48
+
16
49
/// Deserializes from V8 values.
17
- pub ( super ) struct Deserializer < ' this , ' scope > {
50
+ struct Deserializer < ' this , ' scope > {
18
51
common : DeserializerCommon < ' this , ' scope > ,
19
52
input : Local < ' scope , Value > ,
20
53
}
21
54
22
55
impl < ' this , ' scope > Deserializer < ' this , ' scope > {
23
56
/// Creates a new deserializer from `input` in `scope`.
24
- pub fn new ( scope : & ' this mut HandleScope < ' scope > , input : Local < ' _ , Value > , key_cache : & ' this mut KeyCache ) -> Self {
57
+ fn new ( scope : & ' this mut HandleScope < ' scope > , input : Local < ' _ , Value > , key_cache : & ' this mut KeyCache ) -> Self {
25
58
let input = Local :: new ( scope, input) ;
26
59
let common = DeserializerCommon { scope, key_cache } ;
27
60
Deserializer { input, common }
@@ -49,12 +82,22 @@ impl<'scope> DeserializerCommon<'_, 'scope> {
49
82
50
83
/// The possible errors that [`Deserializer`] can produce.
51
84
#[ derive( Debug , From ) ]
52
- pub ( super ) enum Error < ' scope > {
53
- Value ( Local < ' scope , Value > ) ,
54
- Exception ( ExceptionThrown ) ,
85
+ enum Error < ' scope > {
86
+ Unthrown ( ExceptionValue < ' scope > ) ,
87
+ Thrown ( ExceptionThrown ) ,
55
88
Custom ( String ) ,
56
89
}
57
90
91
+ impl < ' scope > Throwable < ' scope > for Error < ' scope > {
92
+ fn throw ( self , scope : & mut HandleScope < ' scope > ) -> ExceptionThrown {
93
+ match self {
94
+ Self :: Unthrown ( exception) => exception. throw ( scope) ,
95
+ Self :: Thrown ( thrown) => thrown,
96
+ Self :: Custom ( msg) => TypeError ( msg) . throw ( scope) ,
97
+ }
98
+ }
99
+ }
100
+
58
101
impl de:: Error for Error < ' _ > {
59
102
fn custom ( msg : impl fmt:: Display ) -> Self {
60
103
Self :: Custom ( msg. to_string ( ) )
@@ -104,7 +147,7 @@ impl KeyCache {
104
147
}
105
148
106
149
// Creates an interned [`v8::String`].
107
- pub ( super ) fn v8_interned_string < ' scope > ( scope : & mut HandleScope < ' scope > , field : & str ) -> Local < ' scope , v8:: String > {
150
+ fn v8_interned_string < ' scope > ( scope : & mut HandleScope < ' scope > , field : & str ) -> Local < ' scope , v8:: String > {
108
151
// Internalized v8 strings are significantly faster than "normal" v8 strings
109
152
// since v8 deduplicates re-used strings minimizing new allocations
110
153
// see: https://github.com/v8/v8/blob/14ac92e02cc3db38131a57e75e2392529f405f2f/include/v8.h#L3165-L3171
@@ -128,7 +171,7 @@ fn deref_local<'scope, T>(local: Local<'scope, T>) -> &'scope T {
128
171
macro_rules! deserialize_primitive {
129
172
( $dmethod: ident, $t: ty) => {
130
173
fn $dmethod( self ) -> Result <$t, Self :: Error > {
131
- FromValue :: from_value( self . input, self . common. scope) . map_err( Error :: Value )
174
+ FromValue :: from_value( self . input, self . common. scope) . map_err( Error :: Unthrown )
132
175
}
133
176
} ;
134
177
}
@@ -175,40 +218,9 @@ impl<'de, 'this, 'scope: 'de> de::Deserializer<'de> for Deserializer<'this, 'sco
175
218
let sum_name = visitor. sum_name ( ) . unwrap_or ( "<unknown>" ) ;
176
219
177
220
// We expect a canonical representation of a sum value in JS to be
178
- // `{ tag: "foo", value: a_value_for_foo }`
179
- // with special convenience for optionals
180
- // where we also accept `null`, `undefined` and an object without `tag`.
181
- let ( object, tag_field) = ' treat_as_regular_sum: {
182
- // Optionals receive some special handling for added convenience in JS.
183
- if visitor. is_option ( ) {
184
- // If we don't have an object at all,
185
- // it's either `null | undefined` which means `none`
186
- // or it is `some(the_value)`.
187
- if let Some ( object) = self . input . to_object ( scope) {
188
- // If there is `tag` field, treat this as a normal sum.
189
- // Otherwise, we have `some(the_value)`.
190
- let tag_field = self . common . key_cache . tag ( scope) ;
191
- if object
192
- . has_own_property ( scope, tag_field. into ( ) )
193
- . ok_or_else ( exception_already_thrown) ?
194
- {
195
- break ' treat_as_regular_sum ( object, tag_field) ;
196
- }
197
- } else if self . input . is_null_or_undefined ( ) {
198
- // JS has support for `undefined` and `null` values.
199
- // It's reasonable to interpret these as `None`
200
- // when we're deserializing to an optional value
201
- // rust-side, such as `Option<T>`.
202
- return visitor. visit_sum ( NoneAccess :: new ( ) ) ;
203
- }
204
-
205
- return visitor. visit_sum ( SomeAccess :: new ( self ) ) ;
206
- } else {
207
- let tag_field = self . common . key_cache . tag ( scope) ;
208
- let val = cast ! ( scope, self . input, Object , "object for sum type `{}`" , sum_name) ?;
209
- ( val, tag_field)
210
- }
211
- } ;
221
+ // `{ tag: "foo", value: a_value_for_foo }`.
222
+ let tag_field = self . common . key_cache . tag ( scope) ;
223
+ let object = cast ! ( scope, self . input, Object , "object for sum type `{}`" , sum_name) ?;
212
224
213
225
// Extract the `tag` field. It needs to contain a string.
214
226
let tag = object
@@ -320,7 +332,7 @@ impl<'de, 'scope: 'de> de::NamedProductAccess<'de> for ProductAccess<'_, 'scope>
320
332
Ok ( None )
321
333
}
322
334
323
- fn get_field_value_seed < T : de :: DeserializeSeed < ' de > > ( & mut self , seed : T ) -> Result < T :: Output , Self :: Error > {
335
+ fn get_field_value_seed < T : DeserializeSeed < ' de > > ( & mut self , seed : T ) -> Result < T :: Output , Self :: Error > {
324
336
let common = self . common . reborrow ( ) ;
325
337
// Extract the field's value.
326
338
let input = self
@@ -369,7 +381,7 @@ impl<'de, 'this, 'scope: 'de> de::SumAccess<'de> for SumAccess<'this, 'scope> {
369
381
impl < ' de , ' this , ' scope : ' de > de:: VariantAccess < ' de > for Deserializer < ' this , ' scope > {
370
382
type Error = Error < ' scope > ;
371
383
372
- fn deserialize_seed < T : de :: DeserializeSeed < ' de > > ( self , seed : T ) -> Result < T :: Output , Self :: Error > {
384
+ fn deserialize_seed < T : DeserializeSeed < ' de > > ( self , seed : T ) -> Result < T :: Output , Self :: Error > {
373
385
seed. deserialize ( self )
374
386
}
375
387
}
0 commit comments