Skip to content

Commit 17ba75f

Browse files
committed
Initial prototype
1 parent 603d574 commit 17ba75f

File tree

11 files changed

+242
-31
lines changed

11 files changed

+242
-31
lines changed

crates/backend/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ pub struct Struct {
222222
pub js_name: String,
223223
pub fields: Vec<StructField>,
224224
pub comments: Vec<String>,
225+
pub parent: Option<syn::Path>,
225226
}
226227

227228
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]

crates/backend/src/codegen.rs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,19 @@ impl TryToTokens for ast::Program {
9393
shared::version()
9494
);
9595
let encoded = encode::encode(self)?;
96-
let mut bytes = Vec::new();
97-
bytes.push((prefix_json.len() >> 0) as u8);
98-
bytes.push((prefix_json.len() >> 8) as u8);
99-
bytes.push((prefix_json.len() >> 16) as u8);
100-
bytes.push((prefix_json.len() >> 24) as u8);
101-
bytes.extend_from_slice(prefix_json.as_bytes());
102-
bytes.extend_from_slice(&encoded.custom_section);
103-
104-
let generated_static_length = bytes.len();
105-
let generated_static_value = syn::LitByteStr::new(&bytes, Span::call_site());
106-
96+
let custom_section = encoded.custom_section;
97+
let mut prefix_bytes = Vec::new();
98+
prefix_bytes.push((prefix_json.len() >> 0) as u8);
99+
prefix_bytes.push((prefix_json.len() >> 8) as u8);
100+
prefix_bytes.push((prefix_json.len() >> 16) as u8);
101+
prefix_bytes.push((prefix_json.len() >> 24) as u8);
102+
prefix_bytes.extend_from_slice(prefix_json.as_bytes());
103+
104+
let generated_static_length =
105+
prefix_bytes.len() +
106+
custom_section.iter().map(encode::EncodePart::len).sum::<usize>()
107+
;
108+
107109
// We already consumed the contents of included files when generating
108110
// the custom section, but we want to make sure that updates to the
109111
// generated files will cause this macro to rerun incrementally. To do
@@ -126,7 +128,7 @@ impl TryToTokens for ast::Program {
126128
pub static #generated_static_name: [u8; #generated_static_length] = {
127129
static _INCLUDED_FILES: &[&str] = &[#(#file_dependencies),*];
128130

129-
*#generated_static_value
131+
[ #(#prefix_bytes),* , #(#custom_section),* ]
130132
};
131133

132134
})
@@ -136,6 +138,17 @@ impl TryToTokens for ast::Program {
136138
}
137139
}
138140

141+
fn gen_id() -> [u8; 8] {
142+
use ::std::time::{SystemTime, UNIX_EPOCH};
143+
144+
let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
145+
146+
let mut bytes = duration.as_secs().to_be_bytes();
147+
bytes[0..4].copy_from_slice(&duration.subsec_nanos().to_be_bytes());
148+
149+
bytes
150+
}
151+
139152
impl ToTokens for ast::Struct {
140153
fn to_tokens(&self, tokens: &mut TokenStream) {
141154
let name = &self.rust_name;
@@ -144,7 +157,12 @@ impl ToTokens for ast::Struct {
144157
let name_chars = name_str.chars().map(|c| c as u32);
145158
let new_fn = Ident::new(&shared::new_function(&name_str), Span::call_site());
146159
let free_fn = Ident::new(&shared::free_function(&name_str), Span::call_site());
160+
let id_bytes = gen_id();
147161
(quote! {
162+
impl wasm_bindgen::WasmBindgenReferenceable for #name {
163+
const ID: [u8; 8] = [#(#id_bytes),*];
164+
}
165+
148166
#[allow(clippy::all)]
149167
impl wasm_bindgen::describe::WasmDescribe for #name {
150168
fn describe() {
@@ -561,6 +579,8 @@ impl ToTokens for ast::ImportType {
561579
}
562580
});
563581

582+
let id_bytes = gen_id();
583+
564584
(quote! {
565585
#[allow(bad_style)]
566586
#(#attrs)*
@@ -578,9 +598,13 @@ impl ToTokens for ast::ImportType {
578598
use wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
579599
use wasm_bindgen::convert::RefFromWasmAbi;
580600
use wasm_bindgen::describe::WasmDescribe;
581-
use wasm_bindgen::{JsValue, JsCast};
601+
use wasm_bindgen::{JsValue, JsCast, WasmBindgenReferenceable};
582602
use wasm_bindgen::__rt::core;
583603

604+
impl WasmBindgenReferenceable for #rust_name {
605+
const ID: [u8; 8] = [#(#id_bytes),*];
606+
}
607+
584608
impl WasmDescribe for #rust_name {
585609
fn describe() {
586610
JsValue::describe();

crates/backend/src/encode.rs

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,37 @@ use std::path::PathBuf;
99
use crate::ast;
1010
use crate::Diagnostic;
1111

12+
pub enum EncodePart {
13+
Literal(Vec<u8>),
14+
ID(syn::Path),
15+
}
16+
17+
impl EncodePart {
18+
pub fn len(&self) -> usize {
19+
match self {
20+
EncodePart::Literal(vec) => vec.len(),
21+
EncodePart::ID(_) => 8,
22+
}
23+
}
24+
}
25+
26+
impl quote::ToTokens for EncodePart {
27+
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
28+
let byte = 0..8usize;//size_of::<wasm_bindgen::WasmBindgenReferenceable::ID>()
29+
30+
match self {
31+
EncodePart::Literal(bytes) => quote::quote!{
32+
#(#bytes),*
33+
},
34+
EncodePart::ID(path) => quote::quote!{
35+
#(<#path as wasm_bindgen::WasmBindgenReferenceable>::ID[#byte]),*
36+
},
37+
}.to_tokens(tokens);
38+
}
39+
}
40+
1241
pub struct EncodeResult {
13-
pub custom_section: Vec<u8>,
42+
pub custom_section: Vec<EncodePart>,
1443
pub included_files: Vec<PathBuf>,
1544
}
1645

@@ -287,6 +316,7 @@ fn shared_import_static<'a>(i: &'a ast::ImportStatic, intern: &'a Interner) -> I
287316

288317
fn shared_import_type<'a>(i: &'a ast::ImportType, intern: &'a Interner) -> ImportType<'a> {
289318
ImportType {
319+
id: i.rust_name.clone().into(),
290320
name: &i.js_name,
291321
instanceof_shim: &i.instanceof_shim,
292322
vendor_prefixes: i.vendor_prefixes.iter().map(|x| intern.intern(x)).collect(),
@@ -299,13 +329,15 @@ fn shared_import_enum<'a>(_i: &'a ast::ImportEnum, _intern: &'a Interner) -> Imp
299329

300330
fn shared_struct<'a>(s: &'a ast::Struct, intern: &'a Interner) -> Struct<'a> {
301331
Struct {
332+
id: s.rust_name.clone().into(),
302333
name: &s.js_name,
303334
fields: s
304335
.fields
305336
.iter()
306337
.map(|s| shared_struct_field(s, intern))
307338
.collect(),
308339
comments: s.comments.iter().map(|s| &**s).collect(),
340+
parent: s.parent.clone(),
309341
}
310342
}
311343

@@ -325,27 +357,44 @@ trait Encode {
325357
}
326358

327359
struct Encoder {
328-
dst: Vec<u8>,
360+
dst: Vec<EncodePart>,
329361
}
330362

331363
impl Encoder {
332364
fn new() -> Encoder {
333365
Encoder {
334-
dst: vec![0, 0, 0, 0],
366+
dst: vec![EncodePart::Literal(vec![0, 0, 0, 0])],
335367
}
336368
}
337369

338-
fn finish(mut self) -> Vec<u8> {
339-
let len = self.dst.len() - 4;
340-
self.dst[0] = (len >> 0) as u8;
341-
self.dst[1] = (len >> 8) as u8;
342-
self.dst[2] = (len >> 16) as u8;
343-
self.dst[3] = (len >> 24) as u8;
344-
self.dst
370+
fn finish(mut self) -> Vec<EncodePart> {
371+
let len = self.dst.iter().map(EncodePart::len).sum::<usize>() - 4;
372+
if let Some(EncodePart::Literal(bytes)) = self.dst.first_mut() {
373+
bytes[0] = (len >> 0) as u8;
374+
bytes[1] = (len >> 8) as u8;
375+
bytes[2] = (len >> 16) as u8;
376+
bytes[3] = (len >> 24) as u8;
377+
self.dst
378+
} else {
379+
unreachable!()
380+
}
381+
}
382+
383+
fn bytes(&mut self) -> &mut Vec<u8> {
384+
if let Some(EncodePart::Literal(bytes)) = self.dst.last_mut() {
385+
bytes
386+
} else {
387+
unreachable!()
388+
}
345389
}
346390

347391
fn byte(&mut self, byte: u8) {
348-
self.dst.push(byte);
392+
self.bytes().push(byte);
393+
}
394+
395+
fn id(&mut self, path: &syn::Path) {
396+
self.dst.push(EncodePart::ID(path.clone()));
397+
self.dst.push(EncodePart::Literal(vec![]));
349398
}
350399
}
351400

@@ -377,7 +426,7 @@ impl Encode for usize {
377426
impl<'a> Encode for &'a [u8] {
378427
fn encode(&self, dst: &mut Encoder) {
379428
self.len().encode(dst);
380-
dst.dst.extend_from_slice(*self);
429+
dst.bytes().extend_from_slice(*self);
381430
}
382431
}
383432

@@ -414,6 +463,16 @@ impl<T: Encode> Encode for Option<T> {
414463
}
415464
}
416465

466+
impl Encode for syn::Path {
467+
fn encode(&self, dst: &mut Encoder) {
468+
dst.id(self)
469+
}
470+
}
471+
472+
impl <T> Encode for std::marker::PhantomData<T> {
473+
fn encode(&self, _dst: &mut Encoder) {}
474+
}
475+
417476
macro_rules! encode_struct {
418477
($name:ident ($($lt:tt)*) $($field:ident: $ty:ty,)*) => {
419478
struct $name $($lt)* {
@@ -490,6 +549,8 @@ macro_rules! encode_api {
490549
}
491550
wasm_bindgen_shared::shared_api!(encode_api);
492551

552+
type InternalReference = syn::Path;
553+
493554
fn from_ast_method_kind<'a>(
494555
function: &'a ast::Function,
495556
intern: &'a Interner,

crates/cli-support/src/decode.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,23 @@ macro_rules! decode_api {
155155
}
156156

157157
wasm_bindgen_shared::shared_api!(decode_api);
158+
159+
#[derive(PartialEq,Eq,Hash,Clone,Copy,Debug)]
160+
pub struct InternalReference(u64);
161+
162+
impl <'a> Decode<'a> for InternalReference {
163+
fn decode(data: &mut &'a [u8]) -> InternalReference {
164+
let r = u64::from_be_bytes([
165+
get(data),
166+
get(data),
167+
get(data),
168+
get(data),
169+
get(data),
170+
get(data),
171+
get(data),
172+
get(data),
173+
]);
174+
log::trace!("decoded id {:x?}", r);
175+
InternalReference(r)
176+
}
177+
}

crates/cli-support/src/js/mod.rs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ pub struct Context<'a> {
5050
pub npm_dependencies: HashMap<String, (PathBuf, String)>,
5151
}
5252

53+
pub enum ParentID {
54+
Struct(String),
55+
Import(String),
56+
}
57+
5358
#[derive(Default)]
5459
pub struct ExportedClass {
5560
comments: String,
@@ -59,6 +64,7 @@ pub struct ExportedClass {
5964
wrap_needed: bool,
6065
/// Map from field name to type as a string plus whether it has a setter
6166
typescript_fields: HashMap<String, (String, bool)>,
67+
parent_id: Option<ParentID>,
6268
}
6369

6470
const INITIAL_HEAP_VALUES: &[&str] = &["undefined", "null", "true", "false"];
@@ -585,14 +591,36 @@ impl<'a> Context<'a> {
585591
}
586592

587593
fn write_classes(&mut self) -> Result<(), Error> {
588-
for (class, exports) in self.exported_classes.take().unwrap() {
589-
self.write_class(&class, &exports)?;
594+
use std::collections::VecDeque;
595+
596+
let classes = self.exported_classes.take().unwrap();
597+
let mut todo = classes.iter().collect::<VecDeque<_>>();
598+
let mut done = vec![];
599+
600+
while let Some((name, exports)) = todo.pop_front() {
601+
if match &exports.parent_id {
602+
Some(ParentID::Struct(parent)) => done.contains(&parent),
603+
_ => true,
604+
} {
605+
//do it
606+
self.write_class(name, exports)?;
607+
done.push(name);
608+
} else {
609+
//defer
610+
todo.push_back((name, exports));
611+
}
590612
}
591613
Ok(())
592614
}
593615

594616
fn write_class(&mut self, name: &str, class: &ExportedClass) -> Result<(), Error> {
595-
let mut dst = format!("class {} {{\n", name);
617+
let mut dst = match &class.parent_id {
618+
Some(p) => format!("class {} extends {} {{\n", name, match p {
619+
ParentID::Struct(name) => name,
620+
ParentID::Import(name) => name,
621+
}),
622+
None => format!("class {} {{\n", name),
623+
};
596624
let mut ts_dst = format!("export {}", dst);
597625

598626
if self.config.debug && !class.has_constructor {
@@ -1888,7 +1916,15 @@ impl<'a> Context<'a> {
18881916
}
18891917

18901918
for s in aux.structs.iter() {
1891-
self.generate_struct(s)?;
1919+
let parent_id = s.parent_id
1920+
.as_ref()
1921+
.and_then(|p| Some(match aux.internal_refs.get(p).unwrap() {
1922+
crate::webidl::Referenceable::Struct(id) => ParentID::Struct(aux.structs[*id].name.clone()),
1923+
crate::webidl::Referenceable::Import(id) => ParentID::Import(self.import_name(id).unwrap()),
1924+
}))
1925+
;
1926+
1927+
self.generate_struct(s, parent_id)?;
18921928
}
18931929

18941930
self.typescript.push_str(&aux.extra_typescript);
@@ -2665,9 +2701,10 @@ impl<'a> Context<'a> {
26652701
Ok(())
26662702
}
26672703

2668-
fn generate_struct(&mut self, struct_: &AuxStruct) -> Result<(), Error> {
2704+
fn generate_struct(&mut self, struct_: &AuxStruct, parent_id: Option<ParentID>) -> Result<(), Error> {
26692705
let class = require_class(&mut self.exported_classes, &struct_.name);
26702706
class.comments = format_doc_comments(&struct_.comments, None);
2707+
class.parent_id = parent_id;
26712708
Ok(())
26722709
}
26732710

0 commit comments

Comments
 (0)