Skip to content

Commit 153ece0

Browse files
committed
remove &str special handling
1 parent bcc2b72 commit 153ece0

File tree

9 files changed

+158
-206
lines changed

9 files changed

+158
-206
lines changed

src/rust/api/dns.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl DnsUtil {
136136
/// `DnsParserError::InvalidHexString`
137137
/// `DnsParserError::ParseIntError`
138138
#[jsg_method]
139-
pub fn parse_caa_record(&self, record: &str) -> Result<CaaRecord, DnsParserError> {
139+
pub fn parse_caa_record(&self, record: String) -> Result<CaaRecord, DnsParserError> {
140140
// Let's remove "\\#" and the length of data from the beginning of the record
141141
let data = record.split_ascii_whitespace().collect::<Vec<_>>()[2..].to_vec();
142142
let critical = data[0].parse::<u8>()?;
@@ -191,7 +191,7 @@ impl DnsUtil {
191191
/// `DnsParserError::InvalidHexString`
192192
/// `DnsParserError::ParseIntError`
193193
#[jsg_method]
194-
pub fn parse_naptr_record(&self, record: &str) -> jsg::Result<NaptrRecord, DnsParserError> {
194+
pub fn parse_naptr_record(&self, record: String) -> jsg::Result<NaptrRecord, DnsParserError> {
195195
let data = record.split_ascii_whitespace().collect::<Vec<_>>()[1..].to_vec();
196196

197197
let order_str = data[1..3].to_vec();
@@ -262,7 +262,7 @@ mod tests {
262262
_state: ResourceState::default(),
263263
};
264264
let record = dns_util
265-
.parse_caa_record("\\# 15 00 05 69 73 73 75 65 70 6b 69 2e 67 6f 6f 67")
265+
.parse_caa_record("\\# 15 00 05 69 73 73 75 65 70 6b 69 2e 67 6f 6f 67".to_owned())
266266
.unwrap();
267267

268268
assert_eq!(record.critical, 0);
@@ -277,7 +277,8 @@ mod tests {
277277
};
278278
let record = dns_util
279279
.parse_caa_record(
280-
"\\# 21 00 09 69 73 73 75 65 77 69 6c 64 6c 65 74 73 65 6e 63 72 79 70 74",
280+
"\\# 21 00 09 69 73 73 75 65 77 69 6c 64 6c 65 74 73 65 6e 63 72 79 70 74"
281+
.to_owned(),
281282
)
282283
.unwrap();
283284

@@ -291,8 +292,9 @@ mod tests {
291292
let dns_util = DnsUtil {
292293
_state: ResourceState::default(),
293294
};
294-
let result =
295-
dns_util.parse_caa_record("\\# 15 00 05 69 6e 76 61 6c 69 64 70 6b 69 2e 67 6f 6f 67");
295+
let result = dns_util.parse_caa_record(
296+
"\\# 15 00 05 69 6e 76 61 6c 69 64 70 6b 69 2e 67 6f 6f 67".to_owned(),
297+
);
296298

297299
assert!(result.is_err());
298300
}
@@ -303,7 +305,7 @@ mod tests {
303305
_state: ResourceState::default(),
304306
};
305307
let record = dns_util
306-
.parse_naptr_record("\\# 37 15 b3 08 ae 01 73 0a 6d 79 2d 73 65 72 76 69 63 65 06 72 65 67 65 78 70 0b 72 65 70 6c 61 63 65 6d 65 6e 74 00")
308+
.parse_naptr_record("\\# 37 15 b3 08 ae 01 73 0a 6d 79 2d 73 65 72 76 69 63 65 06 72 65 67 65 78 70 0b 72 65 70 6c 61 63 65 6d 65 6e 74 00".to_owned())
307309
.unwrap();
308310

309311
assert_eq!(record.flags, "s");

src/rust/jsg-macros/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ wd_rust_proc_macro(
44
name = "jsg-macros",
55
visibility = ["//visibility:public"],
66
deps = [
7-
"@crates_vendor//:proc-macro2",
87
"@crates_vendor//:quote",
98
"@crates_vendor//:syn",
109
],

src/rust/jsg-macros/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Generates the `jsg::Struct` and `jsg::Type` implementations for data structures.
99
```rust
1010
#[jsg_struct]
1111
pub struct CaaRecord {
12-
pub critical: u8,
12+
pub critical: f64,
1313
pub field: String,
1414
pub value: String,
1515
}
@@ -29,7 +29,7 @@ Parameters and return values are handled via the `jsg::Wrappable` trait. Any typ
2929
```rust
3030
impl DnsUtil {
3131
#[jsg_method(name = "parseCaaRecord")]
32-
pub fn parse_caa_record(&self, record: &str) -> Result<CaaRecord, DnsParserError> {
32+
pub fn parse_caa_record(&self, record: String) -> Result<CaaRecord, DnsParserError> {
3333
// Errors are thrown as JavaScript exceptions
3434
}
3535

@@ -65,7 +65,7 @@ pub struct MyUtil {
6565
#[jsg_resource]
6666
impl DnsUtil {
6767
#[jsg_method]
68-
pub fn parse_caa_record(&self, record: &str) -> Result<CaaRecord, DnsParserError> {
68+
pub fn parse_caa_record(&self, record: String) -> Result<CaaRecord, DnsParserError> {
6969
// implementation
7070
}
7171
}

src/rust/jsg-macros/lib.rs

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
mod types;
2-
31
use proc_macro::TokenStream;
4-
use proc_macro2::TokenStream as TokenStream2;
52
use quote::ToTokens;
63
use quote::quote;
74
use syn::Data;
@@ -10,10 +7,8 @@ use syn::Fields;
107
use syn::FnArg;
118
use syn::ItemFn;
129
use syn::ItemImpl;
13-
use syn::Type;
1410
use syn::parse_macro_input;
1511
use syn::spanned::Spanned;
16-
use types::is_str_ref;
1712

1813
/// Generates `jsg::Struct` and `jsg::Type` implementations for data structures.
1914
///
@@ -51,27 +46,31 @@ pub fn jsg_struct(attr: TokenStream, item: TokenStream) -> TokenStream {
5146
#input
5247

5348
impl jsg::Type for #name {
54-
type This = Self;
55-
5649
fn class_name() -> &'static str { #class_name }
5750

58-
fn wrap<'a, 'b>(this: Self::This, lock: &'a mut jsg::Lock) -> jsg::v8::Local<'b, jsg::v8::Value>
59-
where 'b: 'a,
51+
fn is_exact(value: &jsg::v8::Local<jsg::v8::Value>) -> bool {
52+
value.is_object()
53+
}
54+
}
55+
56+
impl jsg::Wrappable for #name {
57+
fn wrap<'a, 'b>(self, lock: &'a mut jsg::Lock) -> jsg::v8::Local<'b, jsg::v8::Value>
58+
where
59+
'b: 'a,
6060
{
6161
// TODO(soon): Use a precached ObjectTemplate instance to create the object,
6262
// similar to how C++ JSG optimizes object creation. This would avoid recreating
6363
// the object shape on every wrap() call and improve performance.
6464
unsafe {
65+
let this = self;
6566
let mut obj = lock.new_object();
6667
#(#field_assignments)*
6768
obj.into()
6869
}
6970
}
71+
}
7072

71-
fn is_exact(value: &jsg::v8::Local<jsg::v8::Value>) -> bool {
72-
value.is_object()
73-
}
74-
73+
impl jsg::Unwrappable for #name {
7574
fn unwrap(_isolate: jsg::v8::IsolatePtr, _value: jsg::v8::Local<jsg::v8::Value>) -> Self {
7675
unimplemented!("Struct unwrap is not yet supported")
7776
}
@@ -104,13 +103,15 @@ pub fn jsg_method(_attr: TokenStream, item: TokenStream) -> TokenStream {
104103
})
105104
.collect();
106105

107-
let (unwraps, arg_refs): (Vec<_>, Vec<_>) = params
106+
let (unwraps, arg_names): (Vec<_>, Vec<_>) = params
108107
.iter()
109108
.enumerate()
110109
.map(|(i, ty)| {
111110
let arg = syn::Ident::new(&format!("arg{i}"), fn_name.span());
112-
let (unwrap, arg_ref) = generate_unwrap(&arg, ty, i);
113-
(unwrap, arg_ref)
111+
let unwrap = quote! {
112+
let Some(#arg) = <#ty as jsg::Unwrappable>::try_unwrap(&mut lock, args.get(#i)) else { return; };
113+
};
114+
(unwrap, arg)
114115
})
115116
.unzip();
116117

@@ -124,29 +125,13 @@ pub fn jsg_method(_attr: TokenStream, item: TokenStream) -> TokenStream {
124125
#(#unwraps)*
125126
let this = args.this();
126127
let self_ = jsg::unwrap_resource::<Self>(&mut lock, this);
127-
let result = self_.#fn_name(#(#arg_refs),*);
128-
jsg::Wrappable::wrap_return(result, &mut lock, &mut args);
128+
let result = self_.#fn_name(#(#arg_names),*);
129+
args.set_return_value(jsg::Wrappable::wrap(result, &mut lock));
129130
}
130131
}
131132
.into()
132133
}
133134

134-
fn generate_unwrap(arg: &syn::Ident, ty: &Type, index: usize) -> (TokenStream2, TokenStream2) {
135-
// &str: unwrap as String and borrow
136-
if is_str_ref(ty) {
137-
let unwrap = quote! {
138-
let Some(#arg) = <String as jsg::Wrappable>::try_unwrap(&mut lock, args.get(#index)) else { return; };
139-
};
140-
return (unwrap, quote! { &#arg });
141-
}
142-
143-
// All types use Wrappable::try_unwrap
144-
let unwrap = quote! {
145-
let Some(#arg) = <#ty as jsg::Wrappable>::try_unwrap(&mut lock, args.get(#index)) else { return; };
146-
};
147-
(unwrap, quote! { #arg })
148-
}
149-
150135
/// Generates boilerplate for JSG resources.
151136
///
152137
/// On structs: generates `jsg::Type` and `ResourceTemplate`.
@@ -174,20 +159,25 @@ pub fn jsg_resource(attr: TokenStream, item: TokenStream) -> TokenStream {
174159

175160
#[automatically_derived]
176161
impl jsg::Type for #name {
177-
type This = jsg::Ref<Self>;
178-
179162
fn class_name() -> &'static str { #class_name }
180163

181-
fn wrap<'a, 'b>(_this: Self::This, _lock: &'a mut jsg::Lock) -> jsg::v8::Local<'b, jsg::v8::Value>
182-
where 'b: 'a,
183-
{
184-
todo!("Implement wrap for jsg::Resource")
185-
}
186-
187164
fn is_exact(value: &jsg::v8::Local<jsg::v8::Value>) -> bool {
188165
value.is_object()
189166
}
167+
}
190168

169+
#[automatically_derived]
170+
impl jsg::Wrappable for #name {
171+
fn wrap<'a, 'b>(self, _lock: &'a mut jsg::Lock) -> jsg::v8::Local<'b, jsg::v8::Value>
172+
where
173+
'b: 'a,
174+
{
175+
unimplemented!("Resource wrap is not yet supported")
176+
}
177+
}
178+
179+
#[automatically_derived]
180+
impl jsg::Unwrappable for #name {
191181
fn unwrap(_isolate: jsg::v8::IsolatePtr, _value: jsg::v8::Local<jsg::v8::Value>) -> Self {
192182
unimplemented!("Resource unwrap is not yet supported")
193183
}

src/rust/jsg-macros/types.rs

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/rust/jsg-test/tests/jsg_struct.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use jsg::Error;
22
use jsg::ExceptionType;
33
use jsg::Lock;
4-
use jsg::Type;
4+
use jsg::Wrappable;
55
use jsg::v8;
66
use jsg::v8::ToLocalValue;
77
use jsg_macros::jsg_struct;
@@ -31,7 +31,7 @@ fn objects_can_be_wrapped_and_unwrapped() {
3131
let instance = TestStruct {
3232
str: "test".to_owned(),
3333
};
34-
let wrapped = TestStruct::wrap(instance, &mut lock);
34+
let wrapped = instance.wrap(&mut lock);
3535
let mut obj: v8::Local<'_, v8::Object> = wrapped.into();
3636
assert!(obj.has(&mut lock, "str"));
3737
let str_value = obj.get(&mut lock, "str");
@@ -54,7 +54,7 @@ fn struct_with_multiple_properties() {
5454
age: 30,
5555
active: "true".to_owned(),
5656
};
57-
let wrapped = MultiPropertyStruct::wrap(instance, &mut lock);
57+
let wrapped = instance.wrap(&mut lock);
5858
let obj: v8::Local<'_, v8::Object> = wrapped.into();
5959

6060
assert!(obj.has(&mut lock, "name"));
@@ -142,7 +142,7 @@ fn nested_object_properties() {
142142
let inner_instance = NestedStruct {
143143
inner: "nested value".to_owned(),
144144
};
145-
let inner_wrapped = NestedStruct::wrap(inner_instance, &mut lock);
145+
let inner_wrapped = inner_instance.wrap(&mut lock);
146146
outer.set(&mut lock, "nested", inner_wrapped);
147147

148148
assert!(outer.has(&mut lock, "nested"));

src/rust/jsg-test/tests/resource_callback.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ struct EchoResource {
2626
#[expect(clippy::unnecessary_wraps)]
2727
impl EchoResource {
2828
#[jsg_method]
29-
pub fn echo(&self, message: &str) -> Result<String, String> {
29+
pub fn echo(&self, message: String) -> Result<String, String> {
3030
Ok(format!("{}{}", self.prefix, message))
3131
}
3232
}

src/rust/jsg/lib.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod v8;
1414
mod wrappable;
1515

1616
pub use v8::ffi::ExceptionType;
17+
pub use wrappable::Unwrappable;
1718
pub use wrappable::Wrappable;
1819

1920
#[cxx::bridge(namespace = "workerd::rust::jsg")]
@@ -230,6 +231,11 @@ impl<T: Type> NonCoercible<T> {
230231
pub fn new(value: T) -> Self {
231232
Self { value }
232233
}
234+
235+
/// Consumes the wrapper and returns the inner value.
236+
pub fn into_inner(self) -> T {
237+
self.value
238+
}
233239
}
234240

235241
impl<T: Type> From<T> for NonCoercible<T> {
@@ -366,32 +372,30 @@ impl<T: Resource> Clone for Ref<T> {
366372
}
367373
}
368374

375+
/// Provides metadata about Rust types exposed to JavaScript.
376+
///
377+
/// This trait provides type information used for error messages, memory tracking,
378+
/// and type validation (for `NonCoercible<T>`). The actual conversion logic is in
379+
/// `Wrappable` (Rust → JS) and `Unwrappable` (JS → Rust).
380+
///
369381
/// TODO: Implement `memory_info(jsg::MemoryTracker)`
370382
pub trait Type: Sized {
371-
/// The input type for [`wrap()`](Self::wrap). For primitive types this is typically `Self`,
372-
/// but resource types may use `Ref<Self>` or other wrapper types.
373-
type This;
374-
383+
/// The JavaScript class name for this type (used in error messages).
375384
fn class_name() -> &'static str;
385+
376386
/// Same as jsgGetMemoryName
377387
fn memory_name() -> &'static str {
378388
std::any::type_name::<Self>()
379389
}
390+
380391
/// Same as jsgGetMemorySelfSize
381392
fn memory_self_size() -> usize {
382393
std::mem::size_of::<Self>()
383394
}
384-
/// Wraps this struct as a JavaScript value by deep-copying its fields.
385-
fn wrap<'a, 'b>(this: Self::This, lock: &'a mut Lock) -> v8::Local<'b, v8::Value>
386-
where
387-
'b: 'a;
388395

389396
/// Returns true if the V8 value is exactly this type (no coercion).
390397
/// Used by `NonCoercible<T>` to reject values that would require coercion.
391398
fn is_exact(value: &v8::Local<v8::Value>) -> bool;
392-
393-
/// Unwraps a V8 value into this type without coercion.
394-
fn unwrap(isolate: v8::IsolatePtr, value: v8::Local<v8::Value>) -> Self;
395399
}
396400

397401
pub enum Member {

0 commit comments

Comments
 (0)