Skip to main content

deno_ops/
lib.rs

1// Copyright 2018-2026 the Deno authors. MIT license.
2
3#![doc = include_str!("README.md")]
4#![deny(clippy::unnecessary_wraps)]
5
6use proc_macro::TokenStream;
7
8mod conversion;
9mod cppgc;
10mod op2;
11mod webidl;
12
13#[proc_macro_derive(CppgcInherits, attributes(cppgc_inherits_from))]
14pub fn cppgc_inherits(item: TokenStream) -> TokenStream {
15  cppgc::derives_inherits(item)
16}
17
18#[proc_macro_derive(CppgcBase)]
19pub fn cppgc_inherits_from(item: TokenStream) -> TokenStream {
20  cppgc::derives_base(item)
21}
22
23/// A macro designed to provide an extremely fast V8->Rust interface layer.
24#[doc = include_str!("op2/README.md")]
25#[proc_macro_attribute]
26pub fn op2(attr: TokenStream, item: TokenStream) -> TokenStream {
27  op2_macro(attr, item)
28}
29
30fn op2_macro(attr: TokenStream, item: TokenStream) -> TokenStream {
31  match op2::op2(attr.into(), item.into()) {
32    Ok(output) => output.into(),
33    Err(err) => syn::Error::from(err).into_compile_error().into(),
34  }
35}
36
37#[proc_macro_derive(WebIDL, attributes(webidl, options))]
38pub fn webidl(item: TokenStream) -> TokenStream {
39  match webidl::webidl(item.into()) {
40    Ok(output) => output.into(),
41    Err(err) => err.into_compile_error().into(),
42  }
43}
44
45#[proc_macro_derive(FromV8, attributes(from_v8, v8))]
46pub fn from_v8(item: TokenStream) -> TokenStream {
47  match conversion::from_v8::from_v8(item.into()) {
48    Ok(output) => output.into(),
49    Err(err) => err.into_compile_error().into(),
50  }
51}
52
53#[proc_macro_derive(ToV8, attributes(to_v8, v8))]
54pub fn to_v8(item: TokenStream) -> TokenStream {
55  match conversion::to_v8::to_v8(item.into()) {
56    Ok(output) => output.into(),
57    Err(err) => err.into_compile_error().into(),
58  }
59}
60
61fn get_internalized_string(
62  name: syn::Ident,
63) -> Result<proc_macro2::TokenStream, syn::Error> {
64  let name_str = name.to_string();
65
66  if !name_str.is_ascii() {
67    return Err(syn::Error::new(
68      name.span(),
69      "Only ASCII keys are supported",
70    ));
71  }
72
73  Ok(quote::quote! {
74    ::deno_core::v8::String::new_from_one_byte(
75      __scope,
76      #name_str.as_bytes(),
77      ::deno_core::v8::NewStringType::Internalized,
78    )
79    .unwrap()
80    .into()
81  })
82}
83
84#[cfg(test)]
85mod infra {
86  #![allow(clippy::disallowed_methods, reason = "test code")]
87
88  use std::path::PathBuf;
89
90  use syn::File;
91
92  pub fn run_macro_expansion_test<F, I>(input: PathBuf, expander: F)
93  where
94    F: FnOnce(File) -> I,
95    I: Iterator<Item = proc_macro2::TokenStream>,
96  {
97    let update_expected = std::env::var("UPDATE_EXPECTED").is_ok();
98
99    let source =
100      std::fs::read_to_string(&input).expect("Failed to read test file");
101
102    const PRELUDE: &str = r"// Copyright 2018-2026 the Deno authors. MIT license.
103
104#![deny(warnings)]
105deno_ops_compile_test_runner::prelude!();";
106
107    if !source.starts_with(PRELUDE) {
108      panic!("Source does not start with expected prelude:]n{PRELUDE}");
109    }
110
111    let file =
112      syn::parse_str::<File>(&source).expect("Failed to parse Rust file");
113
114    #[allow(clippy::print_stdout, reason = "test code")]
115    let expected_out = expander(file)
116      .map(|tokens| {
117        println!("======== Raw tokens ========:\n{}", tokens.clone());
118        let tree = syn::parse2(tokens).unwrap();
119        let actual = prettyplease::unparse(&tree);
120        println!("======== Generated ========:\n{}", actual);
121        actual
122      })
123      .collect::<Vec<String>>()
124      .join("\n");
125
126    if update_expected {
127      std::fs::write(input.with_extension("out"), expected_out)
128        .expect("Failed to write expectation file");
129    } else {
130      let expected = std::fs::read_to_string(input.with_extension("out"))
131        .expect("Failed to read expectation file");
132
133      pretty_assertions::assert_eq!(
134        expected,
135        expected_out,
136        "Failed to match expectation. Use UPDATE_EXPECTED=1."
137      );
138    }
139  }
140}