|
| 1 | +use std::borrow::Cow; |
| 2 | + |
| 3 | +use spacetimedb_sats::{de, i256, u256}; |
| 4 | + |
| 5 | +use super::convert::{cast, FromValue}; |
| 6 | +use super::util::{scratch_buf, ExceptionOptionExt, ExceptionThrown, IntoExceptionResultExt, Throwable, TypeError}; |
| 7 | + |
| 8 | +pub(super) struct Deserializer<'a, 's> { |
| 9 | + common: DeserializerCommon<'a, 's>, |
| 10 | + input: v8::Local<'s, v8::Value>, |
| 11 | +} |
| 12 | + |
| 13 | +impl<'a, 's> Deserializer<'a, 's> { |
| 14 | + pub fn new( |
| 15 | + scope: &'a mut v8::HandleScope<'s>, |
| 16 | + input: v8::Local<'_, v8::Value>, |
| 17 | + key_cache: &'a mut KeyCache, |
| 18 | + ) -> Self { |
| 19 | + let input = v8::Local::new(scope, input); |
| 20 | + let common = DeserializerCommon { scope, key_cache }; |
| 21 | + Deserializer { input, common } |
| 22 | + } |
| 23 | +} |
| 24 | + |
| 25 | +struct DeserializerCommon<'a, 's> { |
| 26 | + scope: &'a mut v8::HandleScope<'s>, |
| 27 | + key_cache: &'a mut KeyCache, |
| 28 | +} |
| 29 | + |
| 30 | +impl<'a, 's> DeserializerCommon<'a, 's> { |
| 31 | + fn reborrow(&mut self) -> DeserializerCommon<'_, 's> { |
| 32 | + DeserializerCommon { |
| 33 | + scope: self.scope, |
| 34 | + key_cache: self.key_cache, |
| 35 | + } |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +macro_rules! def_key_cache { |
| 40 | + ($($key:ident$(: $string:expr)?),* $(,)?) => { |
| 41 | + #[derive(Default)] |
| 42 | + pub(super) struct KeyCache { |
| 43 | + $($key: Option<v8::Global<v8::String>>,)* |
| 44 | + } |
| 45 | + impl KeyCache { |
| 46 | + $(pub(super) fn $key<'s>(&mut self, scope: &mut v8::HandleScope<'s>) -> v8::Local<'s, v8::String> { |
| 47 | + get_or_create_key(scope, &mut self.$key, ($($string,)? stringify!($key),).0) |
| 48 | + })* |
| 49 | + } |
| 50 | + }; |
| 51 | +} |
| 52 | + |
| 53 | +fn get_or_create_key<'s>( |
| 54 | + scope: &mut v8::HandleScope<'s>, |
| 55 | + key: &mut Option<v8::Global<v8::String>>, |
| 56 | + string: &str, |
| 57 | +) -> v8::Local<'s, v8::String> { |
| 58 | + if let Some(s) = &*key { |
| 59 | + v8::Local::new(scope, s) |
| 60 | + } else { |
| 61 | + let s = v8_struct_key(scope, string); |
| 62 | + *key = Some(v8::Global::new(scope, s)); |
| 63 | + s |
| 64 | + } |
| 65 | +} |
| 66 | + |
| 67 | +def_key_cache!(tag, value, some); |
| 68 | + |
| 69 | +// creates an optimized v8::String for a struct field |
| 70 | +pub fn v8_struct_key<'s>(scope: &mut v8::HandleScope<'s>, field: &str) -> v8::Local<'s, v8::String> { |
| 71 | + // Internalized v8 strings are significantly faster than "normal" v8 strings |
| 72 | + // since v8 deduplicates re-used strings minimizing new allocations |
| 73 | + // see: https://github.com/v8/v8/blob/14ac92e02cc3db38131a57e75e2392529f405f2f/include/v8.h#L3165-L3171 |
| 74 | + v8::String::new_from_utf8(scope, field.as_ref(), v8::NewStringType::Internalized).unwrap() |
| 75 | +} |
| 76 | + |
| 77 | +pub(super) enum Error<'s> { |
| 78 | + Value(v8::Local<'s, v8::Value>), |
| 79 | + Exception(ExceptionThrown), |
| 80 | + String(String), |
| 81 | +} |
| 82 | + |
| 83 | +impl<'s> Throwable for Error<'s> { |
| 84 | + fn throw(self, scope: &mut v8::HandleScope<'_>) -> ExceptionThrown { |
| 85 | + match self { |
| 86 | + Error::Value(exc) => exc.throw(scope), |
| 87 | + Error::Exception(thrown) => thrown, |
| 88 | + Error::String(s) => TypeError(s).throw(scope), |
| 89 | + } |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +impl<'s> From<ExceptionThrown> for Error<'s> { |
| 94 | + fn from(v: ExceptionThrown) -> Self { |
| 95 | + Self::Exception(v) |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +impl<'s> From<v8::Local<'s, v8::Value>> for Error<'s> { |
| 100 | + fn from(v: v8::Local<'s, v8::Value>) -> Self { |
| 101 | + Self::Value(v) |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +impl de::Error for Error<'_> { |
| 106 | + fn custom(msg: impl core::fmt::Display) -> Self { |
| 107 | + Self::String(msg.to_string()) |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +fn extend_local<'s, T>(local: v8::Local<'s, T>) -> &'s T { |
| 112 | + unsafe { std::mem::transmute::<&T, &'s T>(&local) } |
| 113 | +} |
| 114 | + |
| 115 | +macro_rules! deserialize_primitive { |
| 116 | + ($dmethod:ident, $t:ty) => { |
| 117 | + fn $dmethod(self) -> Result<$t, Self::Error> { |
| 118 | + FromValue::from_value(self.common.scope, self.input).map_err(Error::Value) |
| 119 | + } |
| 120 | + }; |
| 121 | +} |
| 122 | + |
| 123 | +impl<'de, 'a, 's: 'de, 'x> de::Deserializer<'de> for Deserializer<'a, 's> { |
| 124 | + type Error = Error<'s>; |
| 125 | + |
| 126 | + fn deserialize_product<V: de::ProductVisitor<'de>>(self, visitor: V) -> Result<V::Output, Self::Error> { |
| 127 | + let obj = cast!( |
| 128 | + self.input, |
| 129 | + v8::Object, |
| 130 | + "object for product type {}", |
| 131 | + visitor.product_name().unwrap_or("") |
| 132 | + ) |
| 133 | + .map_err_exc(self.common.scope)?; |
| 134 | + |
| 135 | + visitor.visit_named_product(ProductAccess { |
| 136 | + common: self.common, |
| 137 | + obj, |
| 138 | + next_value: None, |
| 139 | + n: 0, |
| 140 | + }) |
| 141 | + } |
| 142 | + |
| 143 | + fn deserialize_sum<V: de::SumVisitor<'de>>(self, visitor: V) -> Result<V::Output, Self::Error> { |
| 144 | + let scope = &mut *self.common.scope; |
| 145 | + let val = if visitor.is_option() { |
| 146 | + if self.input.is_null_or_undefined() { |
| 147 | + return visitor.visit_sum(de::NoneAccess::new()); |
| 148 | + } |
| 149 | + let val = cast!(self.input, v8::Object, "nullish or {{some:_}} for option").map_err_exc(scope)?; |
| 150 | + let some_field = self.common.key_cache.some(scope); |
| 151 | + if val.has_own_property(scope, some_field.into()).err()? { |
| 152 | + let value = val.get(scope, some_field.into()).err()?; |
| 153 | + return visitor.visit_sum(SumAccess { |
| 154 | + common: self.common, |
| 155 | + tag: some_field, |
| 156 | + value, |
| 157 | + }); |
| 158 | + } |
| 159 | + val |
| 160 | + } else { |
| 161 | + cast!( |
| 162 | + self.input, |
| 163 | + v8::Object, |
| 164 | + "object for sum type {}", |
| 165 | + visitor.sum_name().unwrap_or("") |
| 166 | + ) |
| 167 | + .map_err_exc(scope)? |
| 168 | + }; |
| 169 | + |
| 170 | + let tag_field = self.common.key_cache.tag(scope); |
| 171 | + let tag = val.get(scope, tag_field.into()).err()?; |
| 172 | + let tag = cast!( |
| 173 | + tag, |
| 174 | + v8::String, |
| 175 | + "string for sum tag of {}", |
| 176 | + visitor.sum_name().unwrap_or("") |
| 177 | + ) |
| 178 | + .map_err_exc(scope)?; |
| 179 | + |
| 180 | + let value_field = self.common.key_cache.value(scope); |
| 181 | + let value = val.get(scope, value_field.into()).err()?; |
| 182 | + |
| 183 | + visitor.visit_sum(SumAccess { |
| 184 | + common: self.common, |
| 185 | + tag, |
| 186 | + value, |
| 187 | + }) |
| 188 | + } |
| 189 | + |
| 190 | + deserialize_primitive!(deserialize_bool, bool); |
| 191 | + |
| 192 | + deserialize_primitive!(deserialize_u8, u8); |
| 193 | + deserialize_primitive!(deserialize_u16, u16); |
| 194 | + deserialize_primitive!(deserialize_u32, u32); |
| 195 | + deserialize_primitive!(deserialize_u64, u64); |
| 196 | + deserialize_primitive!(deserialize_u128, u128); |
| 197 | + deserialize_primitive!(deserialize_u256, u256); |
| 198 | + |
| 199 | + deserialize_primitive!(deserialize_i8, i8); |
| 200 | + deserialize_primitive!(deserialize_i16, i16); |
| 201 | + deserialize_primitive!(deserialize_i32, i32); |
| 202 | + deserialize_primitive!(deserialize_i64, i64); |
| 203 | + deserialize_primitive!(deserialize_i128, i128); |
| 204 | + deserialize_primitive!(deserialize_i256, i256); |
| 205 | + |
| 206 | + deserialize_primitive!(deserialize_f64, f64); |
| 207 | + deserialize_primitive!(deserialize_f32, f32); |
| 208 | + |
| 209 | + fn deserialize_str<V: de::SliceVisitor<'de, str>>(self, visitor: V) -> Result<V::Output, Self::Error> { |
| 210 | + let scope = self.common.scope; |
| 211 | + let val = cast!(self.input, v8::String, "string").map_err_exc(scope)?; |
| 212 | + let mut buf = scratch_buf::<64>(); |
| 213 | + match val.to_rust_cow_lossy(scope, &mut buf) { |
| 214 | + Cow::Borrowed(s) => visitor.visit(s), |
| 215 | + Cow::Owned(string) => visitor.visit_owned(string), |
| 216 | + } |
| 217 | + } |
| 218 | + |
| 219 | + fn deserialize_bytes<V: de::SliceVisitor<'de, [u8]>>(self, visitor: V) -> Result<V::Output, Self::Error> { |
| 220 | + let scope = self.common.scope; |
| 221 | + let arr = cast!(self.input, v8::Uint8Array, "Uint8Array for bytes").map_err_exc(scope)?; |
| 222 | + let storage: &'static mut [u8] = &mut [0; v8::TYPED_ARRAY_MAX_SIZE_IN_HEAP]; |
| 223 | + let bytes = extend_local(arr).get_contents(storage); |
| 224 | + visitor.visit_borrowed(bytes) |
| 225 | + } |
| 226 | + |
| 227 | + fn deserialize_array_seed<V: de::ArrayVisitor<'de, T::Output>, T: de::DeserializeSeed<'de> + Clone>( |
| 228 | + self, |
| 229 | + visitor: V, |
| 230 | + seed: T, |
| 231 | + ) -> Result<V::Output, Self::Error> { |
| 232 | + let arr = cast!(self.input, v8::Array, "Array").map_err_exc(self.common.scope)?; |
| 233 | + visitor.visit(ArrayAccess::new(arr, self.common, seed)) |
| 234 | + } |
| 235 | +} |
| 236 | + |
| 237 | +struct ProductAccess<'a, 's> { |
| 238 | + common: DeserializerCommon<'a, 's>, |
| 239 | + obj: v8::Local<'s, v8::Object>, |
| 240 | + next_value: Option<v8::Local<'s, v8::Value>>, |
| 241 | + n: usize, |
| 242 | +} |
| 243 | + |
| 244 | +impl<'de, 's: 'de> de::NamedProductAccess<'de> for ProductAccess<'_, 's> { |
| 245 | + type Error = Error<'s>; |
| 246 | + |
| 247 | + fn get_field_ident<V: de::FieldNameVisitor<'de>>(&mut self, visitor: V) -> Result<Option<V::Output>, Self::Error> { |
| 248 | + let scope = &mut *self.common.scope; |
| 249 | + while let Some(field) = visitor.field_names().nth(self.n) { |
| 250 | + let i = self.n; |
| 251 | + self.n += 1; |
| 252 | + |
| 253 | + let Some(field) = field else { |
| 254 | + continue; |
| 255 | + }; |
| 256 | + |
| 257 | + let key = v8_struct_key(scope, field); |
| 258 | + if !self.obj.has_own_property(scope, key.into()).err()? { |
| 259 | + continue; |
| 260 | + } |
| 261 | + let val = self.obj.get(scope, key.into()).err()?; |
| 262 | + self.next_value = Some(val); |
| 263 | + return visitor.visit_seq(i, field).map(Some); |
| 264 | + } |
| 265 | + Ok(None) |
| 266 | + } |
| 267 | + |
| 268 | + fn get_field_value_seed<T: de::DeserializeSeed<'de>>(&mut self, seed: T) -> Result<T::Output, Self::Error> { |
| 269 | + let val = self |
| 270 | + .next_value |
| 271 | + .take() |
| 272 | + .expect("Call next_key_seed before next_value_seed"); |
| 273 | + seed.deserialize(Deserializer { |
| 274 | + common: self.common.reborrow(), |
| 275 | + input: val, |
| 276 | + }) |
| 277 | + } |
| 278 | +} |
| 279 | + |
| 280 | +struct SumAccess<'a, 's> { |
| 281 | + common: DeserializerCommon<'a, 's>, |
| 282 | + tag: v8::Local<'s, v8::String>, |
| 283 | + value: v8::Local<'s, v8::Value>, |
| 284 | + // p1: std::marker::PhantomData<&'x ()>, |
| 285 | +} |
| 286 | + |
| 287 | +impl<'de, 'a, 's: 'de> de::SumAccess<'de> for SumAccess<'a, 's> { |
| 288 | + type Error = Error<'s>; |
| 289 | + type Variant = Deserializer<'a, 's>; |
| 290 | + |
| 291 | + fn variant<V: de::VariantVisitor>(self, visitor: V) -> Result<(V::Output, Self::Variant), Self::Error> { |
| 292 | + let mut buf = scratch_buf::<32>(); |
| 293 | + let name = self.tag.to_rust_cow_lossy(self.common.scope, &mut buf); |
| 294 | + let variant = visitor.visit_name::<Self::Error>(&name)?; |
| 295 | + let dpayload = Deserializer { |
| 296 | + common: self.common, |
| 297 | + input: self.value, |
| 298 | + }; |
| 299 | + |
| 300 | + Ok((variant, dpayload)) |
| 301 | + } |
| 302 | +} |
| 303 | + |
| 304 | +impl<'de, 'a, 's: 'de> de::VariantAccess<'de> for Deserializer<'a, 's> { |
| 305 | + type Error = Error<'s>; |
| 306 | + |
| 307 | + fn deserialize_seed<T: de::DeserializeSeed<'de>>(self, seed: T) -> Result<T::Output, Self::Error> { |
| 308 | + seed.deserialize(self) |
| 309 | + } |
| 310 | +} |
| 311 | + |
| 312 | +struct ArrayAccess<'a, 's, T> { |
| 313 | + common: DeserializerCommon<'a, 's>, |
| 314 | + arr: v8::Local<'s, v8::Array>, |
| 315 | + seeds: std::iter::RepeatN<T>, |
| 316 | + len: u32, |
| 317 | +} |
| 318 | + |
| 319 | +impl<'de, 'a, 's, T> ArrayAccess<'a, 's, T> |
| 320 | +where |
| 321 | + T: de::DeserializeSeed<'de> + Clone, |
| 322 | +{ |
| 323 | + fn new(arr: v8::Local<'s, v8::Array>, common: DeserializerCommon<'a, 's>, seed: T) -> Self { |
| 324 | + let len = arr.length(); |
| 325 | + Self { |
| 326 | + arr, |
| 327 | + common, |
| 328 | + seeds: std::iter::repeat_n(seed, len as usize), |
| 329 | + len, |
| 330 | + } |
| 331 | + } |
| 332 | +} |
| 333 | + |
| 334 | +impl<'de, 's: 'de, T> de::ArrayAccess<'de> for ArrayAccess<'_, 's, T> |
| 335 | +where |
| 336 | + T: de::DeserializeSeed<'de> + Clone, |
| 337 | +{ |
| 338 | + type Element = T::Output; |
| 339 | + type Error = Error<'s>; |
| 340 | + |
| 341 | + fn next_element(&mut self) -> Result<Option<Self::Element>, Self::Error> { |
| 342 | + let i = self.len - self.seeds.len() as u32; |
| 343 | + if let Some(seed) = self.seeds.next() { |
| 344 | + let val = self.arr.get_index(self.common.scope, i).err()?; |
| 345 | + let val = seed.deserialize(Deserializer { |
| 346 | + common: self.common.reborrow(), |
| 347 | + input: val, |
| 348 | + })?; |
| 349 | + Ok(Some(val)) |
| 350 | + } else { |
| 351 | + Ok(None) |
| 352 | + } |
| 353 | + } |
| 354 | + |
| 355 | + fn size_hint(&self) -> Option<usize> { |
| 356 | + Some(self.seeds.len()) |
| 357 | + } |
| 358 | +} |
0 commit comments