Skip to content

Commit ee693d8

Browse files
coolreader18Centril
authored andcommitted
wip
switch to sats-based deserialization ModuleInstance impl wip
1 parent adbcc47 commit ee693d8

File tree

14 files changed

+1906
-10
lines changed

14 files changed

+1906
-10
lines changed

.prettierrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"tabWidth": 4,
3+
"useTabs": false,
4+
"semi": true,
5+
"singleQuote": true,
6+
"arrowParens": "avoid",
7+
"jsxSingleQuote": false,
8+
"trailingComma": "es5",
9+
"endOfLine": "auto",
10+
"printWidth": 100
11+
}

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,6 @@ termcolor = "1.2.0"
262262
thin-vec = "0.2.13"
263263
thiserror = "1.0.37"
264264
tokio = { version = "1.37", features = ["full"] }
265-
tokio_metrics = { version = "0.4.0" }
266265
tokio-postgres = { version = "0.7.8", features = ["with-chrono-0_4"] }
267266
tokio-stream = "0.1.17"
268267
tokio-tungstenite = { version = "0.26.2", features = ["native-tls"] }

crates/core/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ jwks.workspace = true
118118
async_cache = "0.3.1"
119119
faststr = "0.2.23"
120120
core_affinity = "0.8"
121+
num-traits = "0.2"
122+
# sourcemap = "9"
121123

122124
[target.'cfg(not(target_env = "msvc"))'.dependencies]
123125
tikv-jemallocator = {workspace = true}

crates/core/src/host/v8/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.js

crates/core/src/host/v8/convert.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
use super::util::{IntoException, IntoExceptionResultExt, TypeError, ValueResult};
2+
use num_traits::ToPrimitive;
3+
use spacetimedb_sats::{i256, u256};
4+
5+
pub(super) trait FromValue: Sized {
6+
fn from_value<'s>(scope: &mut v8::HandleScope<'s>, val: v8::Local<'_, v8::Value>) -> ValueResult<'s, Self>;
7+
}
8+
9+
impl FromValue for bool {
10+
fn from_value<'s>(scope: &mut v8::HandleScope<'s>, val: v8::Local<'_, v8::Value>) -> ValueResult<'s, Self> {
11+
let b = cast!(val, v8::Boolean, "boolean").map_err(|e| e.into_exception(scope))?;
12+
Ok(b.is_true())
13+
}
14+
}
15+
16+
macro_rules! cast {
17+
($val:expr, $t:ty, $expected:literal $(, $args:expr)* $(,)?) => {{
18+
let val = $val;
19+
val.try_cast::<$t>()
20+
.map_err(|_| $crate::host::v8::util::TypeError(format!(
21+
concat!("Expected ", $expected, ", got {__got}"),
22+
$($args,)*
23+
__got = val.type_repr()
24+
)))
25+
}};
26+
}
27+
pub(super) use cast;
28+
29+
macro_rules! num_from_value {
30+
($($t:ident: $to:ident),*) => {
31+
$(impl FromValue for $t {
32+
fn from_value<'s>(scope: &mut v8::HandleScope<'s>, val: v8::Local<'_, v8::Value>) -> ValueResult<'s, Self> {
33+
let num = cast!(val, v8::Number, "number for {}", stringify!($t)).map_err_exc(scope)?;
34+
num.value()
35+
.$to()
36+
.ok_or_else(|| TypeError(format!("Value overflowed {}", stringify!($t))))
37+
.map_err_exc(scope)
38+
}
39+
})*
40+
};
41+
(64bit $($t:ident: $value_method:ident),*) => {
42+
$(impl FromValue for $t {
43+
fn from_value<'s>(scope: &mut v8::HandleScope<'s>, val: v8::Local<'_, v8::Value>) -> ValueResult<'s, Self> {
44+
let int = cast!(val, v8::BigInt, "bigint for {}", stringify!($t)).map_err_exc(scope)?;
45+
let (val, ok) = int.$value_method();
46+
ok.then_some(val)
47+
.ok_or_else(|| TypeError(format!("Value overflowed {}", stringify!($t))))
48+
.map_err_exc(scope)
49+
}
50+
})*
51+
};
52+
(float $($t:ident),*) => {
53+
$(impl FromValue for $t {
54+
fn from_value<'s>(scope: &mut v8::HandleScope<'s>, val: v8::Local<'_, v8::Value>) -> ValueResult<'s, Self> {
55+
let num = cast!(val, v8::Number, "number for {}", stringify!($t)).map_err_exc(scope)?;
56+
Ok(num.value() as _)
57+
}
58+
})*
59+
};
60+
(large $($t:ident: $value64:ident),*) => {
61+
$(impl FromValue for $t {
62+
fn from_value<'s>(scope: &mut v8::HandleScope<'s>, val: v8::Local<'_, v8::Value>) -> ValueResult<'s, Self> {
63+
let int = cast!(val, v8::BigInt, "bigint for {}", stringify!($t)).map_err_exc(scope)?;
64+
if let (val, true) = int.u64_value() {
65+
return Ok(val.into());
66+
}
67+
const WORDS: usize = size_of::<$t>() / size_of::<u64>();
68+
let mut err = || TypeError(format!("Value overflowed {}", stringify!($t))).into_exception(scope);
69+
if int.word_count() > WORDS {
70+
#[allow(unused_comparisons)]
71+
if $t::MIN < 0 && int.word_count() == WORDS + 1 {
72+
let mut words = [0u64; WORDS + 1];
73+
let (sign, _) = int.to_words_array(&mut words);
74+
let [prev @ .., last] = words;
75+
if sign && prev == [0; WORDS] && last == (1 << 63) {
76+
return Ok($t::MIN)
77+
}
78+
}
79+
return Err(err());
80+
}
81+
let mut words = [0u64; WORDS];
82+
let (sign, _) = int.to_words_array(&mut words);
83+
let bytes = bytemuck::must_cast(words.map(|w| w.to_le_bytes()));
84+
let x = Self::from_le_bytes(bytes);
85+
if sign {
86+
x.checked_neg().ok_or_else(err)
87+
} else {
88+
Ok(x)
89+
}
90+
}
91+
})*
92+
};
93+
}
94+
95+
num_from_value!(u8: to_u8, i8: to_i8, u16: to_u16, i16: to_i16, u32: to_u32, i32: to_i32);
96+
97+
num_from_value!(64bit u64: u64_value, i64: i64_value);
98+
99+
num_from_value!(float f32, f64);
100+
101+
num_from_value!(large u128: u64_value, i128: i64_value, u256: u64_value, i256: i64_value);
102+
103+
pub(super) trait ToValue {
104+
fn to_value<'s>(&self, scope: &mut v8::HandleScope<'s>) -> ValueResult<'s, v8::Local<'s, v8::Value>>;
105+
}
106+
107+
impl ToValue for bool {
108+
fn to_value<'s>(&self, scope: &mut v8::HandleScope<'s>) -> ValueResult<'s, v8::Local<'s, v8::Value>> {
109+
Ok(v8::Boolean::new(scope, *self).into())
110+
}
111+
}
112+
113+
macro_rules! num_to_value {
114+
($($t:ident),*) => {
115+
$(impl ToValue for $t {
116+
fn to_value<'s>(&self, scope: &mut v8::HandleScope<'s>) -> ValueResult<'s, v8::Local<'s, v8::Value>> {
117+
Ok(v8::Number::new(scope, *self as f64).into())
118+
}
119+
})*
120+
};
121+
(64bit $($t:ident: $new_from:ident),*) => {
122+
$(impl ToValue for $t {
123+
fn to_value<'s>(&self, scope: &mut v8::HandleScope<'s>) -> ValueResult<'s, v8::Local<'s, v8::Value>> {
124+
Ok(v8::BigInt::$new_from(scope, *self).into())
125+
}
126+
})*
127+
};
128+
(large $($t:ident),*) => {
129+
$(impl ToValue for $t {
130+
fn to_value<'s>(&self, scope: &mut v8::HandleScope<'s>) -> ValueResult<'s, v8::Local<'s, v8::Value>> {
131+
const WORDS: usize = size_of::<$t>() / size_of::<u64>();
132+
#[allow(unused_comparisons)]
133+
let sign = *self < 0;
134+
let Some(magnitude) = (if sign { self.checked_neg() } else { Some(*self) }) else {
135+
let mut words = [0u64; WORDS + 1];
136+
let [.., last] = &mut words;
137+
*last = 1 << 63;
138+
return Ok(v8::BigInt::new_from_words(scope, true, &words).unwrap().into());
139+
};
140+
let bytes = magnitude.to_le_bytes();
141+
let words = bytemuck::must_cast::<_, [u64; WORDS]>(bytes).map(u64::from_le);
142+
Ok(v8::BigInt::new_from_words(scope, sign, &words).unwrap().into())
143+
}
144+
})*
145+
};
146+
}
147+
148+
num_to_value!(u8, i8, u16, i16, u32, i32, f32, f64);
149+
150+
num_to_value!(64bit u64: new_from_u64, i64: new_from_i64);
151+
152+
num_to_value!(large u128, i128, u256, i256);

0 commit comments

Comments
 (0)