diff --git a/ext/web/lib.rs b/ext/web/lib.rs index 2f59636fe3..76095810ef 100644 --- a/ext/web/lib.rs +++ b/ext/web/lib.rs @@ -350,7 +350,28 @@ impl Resource for TextDecoderResource { } } -#[op] +#[op(v8)] +fn op_encoding_encode_into_fallback( + scope: &mut v8::HandleScope, + input: serde_v8::Value, + buffer: &mut [u8], + out_buf: &mut [u32], +) -> Result<(), AnyError> { + let s = v8::Local::::try_from(input.v8_value)?; + + let mut nchars = 0; + out_buf[1] = s.write_utf8( + scope, + buffer, + Some(&mut nchars), + v8::WriteOptions::NO_NULL_TERMINATION + | v8::WriteOptions::REPLACE_INVALID_UTF8, + ) as u32; + out_buf[0] = nchars as u32; + Ok(()) +} + +#[op(fast, slow = op_encoding_encode_into_fallback)] fn op_encoding_encode_into( input: Cow<'_, str>, buffer: &mut [u8], diff --git a/ops/attrs.rs b/ops/attrs.rs index a76cfddf6a..d0182fc693 100644 --- a/ops/attrs.rs +++ b/ops/attrs.rs @@ -1,44 +1,54 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use syn::parse::Parse; use syn::parse::ParseStream; -use syn::punctuated::Punctuated; use syn::Error; use syn::Ident; use syn::Result; use syn::Token; -#[derive(Copy, Clone, Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct Attributes { pub is_unstable: bool, pub is_v8: bool, pub must_be_fast: bool, pub deferred: bool, pub is_wasm: bool, + pub relation: Option, } impl Parse for Attributes { fn parse(input: ParseStream) -> Result { - let vars = Punctuated::::parse_terminated(input)?; - - let vars: Vec<_> = vars.iter().map(Ident::to_string).collect(); - let vars: Vec<_> = vars.iter().map(String::as_str).collect(); - for var in vars.iter() { - if !["unstable", "v8", "fast", "deferred", "wasm"].contains(var) { - return Err(Error::new( - input.span(), - "invalid attribute, expected one of: unstable, v8, fast, deferred, wasm", - )); - } + let mut self_ = Self::default(); + let mut fast = false; + while let Ok(v) = input.parse::() { + match v.to_string().as_str() { + "unstable" => self_.is_unstable = true, + "v8" => self_.is_v8 = true, + "fast" => fast = true, + "deferred" => self_.deferred = true, + "wasm" => self_.is_wasm = true, + "slow" => { + if !fast { + return Err(Error::new( + input.span(), + "relational attributes can only be used with fast attribute", + )); + } + input.parse::()?; + self_.relation = Some(input.parse()?); + } + _ => { + return Err(Error::new( + input.span(), + "invalid attribute, expected one of: unstable, v8, fast, deferred, wasm", + )); + } + }; + let _ = input.parse::(); } - let is_wasm = vars.contains(&"wasm"); + self_.must_be_fast = self_.is_wasm || fast; - Ok(Self { - is_unstable: vars.contains(&"unstable"), - is_v8: vars.contains(&"v8"), - deferred: vars.contains(&"deferred"), - must_be_fast: is_wasm || vars.contains(&"fast"), - is_wasm, - }) + Ok(self_) } } diff --git a/ops/lib.rs b/ops/lib.rs index 19667ab455..21812f6053 100644 --- a/ops/lib.rs +++ b/ops/lib.rs @@ -111,24 +111,68 @@ impl Op { active, } = fast_call::generate(&core, &mut optimizer, &item); + let docline = format!("Use `{name}::decl()` to get an op-declaration"); + + let is_v8 = attrs.is_v8; + let is_unstable = attrs.is_unstable; + + if let Some(v8_fn) = attrs.relation { + return quote! { + #[allow(non_camel_case_types)] + #[doc="Auto-generated by `deno_ops`, i.e: `#[op]`"] + #[doc=""] + #[doc=#docline] + #[doc="you can include in a `deno_core::Extension`."] + pub struct #name; + + #[doc(hidden)] + impl #name { + pub fn name() -> &'static str { + stringify!(#name) + } + + pub fn v8_fn_ptr #generics () -> #core::v8::FunctionCallback #where_clause { + use #core::v8::MapFnTo; + #v8_fn::v8_func::<#type_params>.map_fn_to() + } + + pub fn decl #generics () -> #core::OpDecl #where_clause { + #core::OpDecl { + name: Self::name(), + v8_fn_ptr: Self::v8_fn_ptr::<#type_params>(), + enabled: true, + fast_fn: #decl, + is_async: #is_async, + is_unstable: #is_unstable, + is_v8: #is_v8, + argc: 0, + } + } + + #[inline] + #[allow(clippy::too_many_arguments)] + #orig + } + + #impl_and_fn + }; + } + let has_fallible_fast_call = active && optimizer.returns_result; let (v8_body, argc) = if is_async { + let deferred = attrs.deferred; codegen_v8_async( &core, &item, attrs, item.sig.asyncness.is_some(), - attrs.deferred, + deferred, ) } else { codegen_v8_sync(&core, &item, attrs, has_fallible_fast_call) }; - let is_v8 = attrs.is_v8; - let is_unstable = attrs.is_unstable; - - let docline = format!("Use `{name}::decl()` to get an op-declaration"); // Generate wrapper quote! { #[allow(non_camel_case_types)]