Skip to content

Commit 7cab136

Browse files
authored
add support for generating JSG_STRUCT (#65)
1 parent 4c3f0ea commit 7cab136

40 files changed

+2071
-4
lines changed

.zed/settings.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Folder-specific settings
2+
//
3+
// For a full list of overridable settings, and general information on folder-specific settings,
4+
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
5+
{
6+
"file_types": {
7+
"Cap'n Proto": ["*.wd-test"],
8+
"Starlark": ["BUILD.*"]
9+
},
10+
"lsp": {
11+
"clangd": {
12+
"binary": {
13+
"arguments": [
14+
"--background-index",
15+
"--header-insertion=never",
16+
"--query-driver=**",
17+
"--clang-tidy"
18+
]
19+
}
20+
},
21+
"rust-analyzer": {
22+
"initialization_options": {
23+
"workspace": {
24+
"discoverConfig": {
25+
"command": ["just", "_rust-analyzer"],
26+
"progressLabel": "generating rust analyzer config",
27+
"filesToWatch": ["BUILD.bazel"]
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}

BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ rust_proc_macro(
8989
proc_macro_deps = [
9090
"@crates.io//:rustversion",
9191
],
92+
visibility = ["//tests:__pkg__"],
9293
deps = [
9394
":gen",
9495
":syntax",

MODULE.bazel

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ cc_configure = use_extension("@rules_cc//cc:extensions.bzl", "cc_configure_exten
1616
use_repo(cc_configure, "local_config_cc")
1717

1818
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
19-
rust.toolchain(versions = ["1.86.0", "nightly/2025-06-06"])
19+
rust.toolchain(versions = [
20+
"1.86.0",
21+
"nightly/2025-06-06",
22+
])
2023
use_repo(rust, "rust_toolchains")
2124

2225
register_toolchains("@rust_toolchains//:all")
@@ -32,6 +35,6 @@ use_repo(capnp_cpp, "capnp-cpp")
3235
bazel_dep(name = "hedron_compile_commands", dev_dependency = True)
3336
git_override(
3437
module_name = "hedron_compile_commands",
35-
remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git",
3638
commit = "4f28899228fb3ad0126897876f147ca15026151e",
39+
remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git",
3740
)

gen/src/include.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub struct Includes<'a> {
4444
pub sys_types: bool,
4545
pub content: Content<'a>,
4646
pub kj_rs: bool,
47+
pub jsg: bool,
4748
}
4849

4950
impl<'a> Includes<'a> {
@@ -107,6 +108,7 @@ pub fn write(out: &mut OutFile) {
107108
basetsd,
108109
sys_types,
109110
kj_rs,
111+
jsg,
110112
content: _,
111113
} = *include;
112114

@@ -191,6 +193,9 @@ pub fn write(out: &mut OutFile) {
191193
if kj_rs && !cxx_header {
192194
writeln!(out, "#include \"kj-rs/kj-rs.h\"");
193195
}
196+
if jsg && !cxx_header {
197+
writeln!(out, "#include \"jsg.h\"");
198+
}
194199
}
195200

196201
impl<'i, 'a> Extend<&'i Include> for Includes<'a> {

gen/src/write.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,19 @@ fn write_struct<'a>(out: &mut OutFile<'a>, strct: &'a Struct, methods: &[&Extern
339339
out.include.type_traits = true;
340340
writeln!(out, " using IsRelocatable = ::std::true_type;");
341341

342+
if derive::contains(&strct.derives, Trait::JsgStruct) {
343+
out.include.jsg = true;
344+
writeln!(out);
345+
write!(out, " JSG_STRUCT(");
346+
for (i, field) in strct.fields.iter().enumerate() {
347+
if i > 0 {
348+
write!(out, ", ");
349+
}
350+
write!(out, "{}", field.name.cxx);
351+
}
352+
writeln!(out, ");");
353+
}
354+
342355
writeln!(out, "}};");
343356
writeln!(out, "#endif // {}", guard);
344357
}

kj-rs/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ cc_library(
1010
"@platforms//os:windows": True,
1111
"//conditions:default": False,
1212
}),
13+
visibility = ["//tests:__pkg__"],
1314
deps = [
1415
":bridge",
1516
],
@@ -34,6 +35,7 @@ rust_cxx_bridge(
3435
src = "lib.rs",
3536
hdrs = glob(["*.h"]),
3637
include_prefix = "kj-rs",
38+
visibility = ["//tests:__pkg__"],
3739
deps = [
3840
"@capnp-cpp//src/kj:kj",
3941
"@capnp-cpp//src/kj:kj-async",

kj-rs/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub mod repr {
3131
pub type Result<T> = std::io::Result<T>;
3232
pub type Error = std::io::Error;
3333

34+
pub trait JsgStruct {}
35+
3436
#[cxx::bridge(namespace = "kj_rs")]
3537
#[allow(clippy::needless_lifetimes)]
3638
mod ffi {

macro/src/derive.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub(crate) fn expand_struct(
2626
Trait::PartialOrd => expanded.extend(struct_partial_ord(strct, span)),
2727
Trait::Serialize => traits.push(quote_spanned!(span=> ::serde::Serialize)),
2828
Trait::Deserialize => traits.push(quote_spanned!(span=> ::serde::Deserialize)),
29+
Trait::JsgStruct => expanded.extend(expand_jsg_struct(strct, span)),
2930
}
3031
}
3132

@@ -73,6 +74,7 @@ pub(crate) fn expand_enum(enm: &Enum, actual_derives: &mut Option<TokenStream>)
7374
Trait::PartialOrd => expanded.extend(enum_partial_ord(enm, span)),
7475
Trait::Serialize => traits.push(quote_spanned!(span=> ::serde::Serialize)),
7576
Trait::Deserialize => traits.push(quote_spanned!(span=> ::serde::Deserialize)),
77+
Trait::JsgStruct => unreachable!(),
7678
}
7779
}
7880

@@ -304,3 +306,13 @@ fn enum_partial_ord(enm: &Enum, span: Span) -> TokenStream {
304306
}
305307
}
306308
}
309+
310+
fn expand_jsg_struct(strct: &Struct, span: Span) -> TokenStream {
311+
let ident = &strct.name.rust;
312+
let generics = &strct.generics;
313+
314+
quote_spanned! {span=>
315+
#[automatically_derived]
316+
impl ::kj_rs::JsgStruct for #ident #generics {}
317+
}
318+
}

macro/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream {
7171
.into()
7272
}
7373

74+
/// JsgStruct derive macro for generating JSG_STRUCT in C++ output
75+
#[proc_macro_derive(JsgStruct)]
76+
pub fn derive_jsg_struct(_input: TokenStream) -> TokenStream {
77+
// This derive macro doesn't generate any Rust code
78+
// The actual JSG_STRUCT generation happens in the C++ code generation phase
79+
TokenStream::new()
80+
}
81+
7482
#[doc(hidden)]
7583
#[proc_macro]
7684
pub fn type_id(input: TokenStream) -> TokenStream {

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ pub use crate::string::CxxString;
446446
pub use crate::unique_ptr::UniquePtr;
447447
pub use crate::weak_ptr::WeakPtr;
448448
pub use cxxbridge_macro::bridge;
449+
pub use cxxbridge_macro::JsgStruct;
449450

450451
/// Synonym for `CxxString`.
451452
///

0 commit comments

Comments
 (0)