Refactor to proc-macro

This commit is contained in:
Rob Watson 2020-09-17 16:42:05 +02:00
parent 944357868c
commit fce19e049d
17 changed files with 595 additions and 132 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
/target
target/
Cargo.lock

View File

@ -1,6 +1,6 @@
[package]
name = "weblog"
version = "0.2.0"
version = "0.3.0-beta.1"
authors = ["Rob Watson <rfwatson@users.noreply.github.com>"]
edition = "2018"
description = "weblog is a crate that defines a set of macros for calling `console.log()` and other members of the browser's console API when targeting Wasm."
@ -15,12 +15,11 @@ doctest = true
[features]
default = ["web_sys"]
web_sys = ["js-sys", "paste", "wasm-bindgen", "web-sys"]
web_sys = ["web-sys", "wasm-bindgen", "weblog-proc-macro"]
std_web = ["stdweb"]
[dependencies]
js-sys = { version = ">= 0.3", optional = true }
paste = { version = "1.0", optional = true }
stdweb = { version = ">= 0.4", optional = true }
wasm-bindgen = { version = ">= 0.2", optional = true }
web-sys = { version = ">= 0.3", optional = true, features = ["console"] }
weblog-proc-macro = { path = "./weblog-proc-macro", version = "0.3.0-beta.1", optional = true }
web-sys = { version = "0.3", features = ["console"], optional = true }
wasm-bindgen = { version = "0.2", optional = true }

View File

@ -1,2 +1,7 @@
all: build
build:
cargo build
docs:
cargo doc --all --no-deps --target wasm32-unknown-unknown && cargo doc --open

View File

@ -54,23 +54,31 @@ No stringification is performed on the Rust side - so objects will be fully intr
```toml
# Defaults to web-sys
weblog = "0.2"
weblog = "0.3.0-beta.1"
# For stdweb:
weblog = { version = "0.2", default-features = false, features = ["std_web"] }
weblog = { version = "0.3.0-beta.1", default-features = false, features = ["std_web"] }
```
See the documentation for usage examples.
The crate currently exposes the following macros:
* `console_assert!`
* `console_clear!`
* `console_count!`
* `console_count_reset!`
* `console_debug!`
* `console_dir!`
* `console_dirxml!`
* `console_error!`
* `console_exception!`
* `console_info!`
* `console_log!`
* `console_table!`
* `console_time!`
* `console_time_end!`
* `console_time_stamp!`
* `console_trace!`
* `console_warn!`

1
examples/web-sys/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target/

View File

@ -0,0 +1,12 @@
[package]
name = "weblog-example-web-sys"
version = "0.3.0-beta.1"
authors = ["Rob Watson <rfwatson@users.noreply.github.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
weblog = { path = "../.." }
wasm-bindgen = "0.2"

View File

@ -0,0 +1,7 @@
all: build
build:
wasm-pack build --target web --out-name wasm --out-dir ./static
run:
simple-http-server -i static -p 3000 --nocache --try-file ./static/index.html

View File

@ -0,0 +1,76 @@
use wasm_bindgen::prelude::*;
use weblog::*;
#[wasm_bindgen(start)]
pub fn main() {
// A simple example.
console_log!("Hello world");
// Multiple arguments.
console_log!("Hello", "there", "world");
// Various types.
console_log!(
1.0,
2f64,
true,
"&str",
String::from("owned string"),
Some("an option"),
None as Option<i32>,
);
// Various levels.
console_debug!("debug");
console_info!("informational");
console_warn!("warning");
console_error!("an", "error", "occurred");
console_exception!("an", "exception", "occurred");
// Print a stacktrace.
console_trace!();
// And include some data.
console_trace!("some", "data", 1, 2, 3);
// Unlimited arguments.
//
// Note that due to the design of the web-sys library, passing greater
// than 7 variadic arguments (or 8 in the case of console_assert!)
// implies a performance hit.
console_log!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// With a trailing comma.
console_log!(1,);
// With no arguments.
console_log!();
// With an assertion.
console_assert!(true); // outputs nothing
console_assert!(false);
console_assert!(false, "Something went wrong");
console_assert!(false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "Done!");
// With a simple count.
console_count!();
console_count_reset!();
// A count with a label.
console_count!("myCounter");
console_count!("myCounter");
console_count!("myCounter");
console_count_reset!("myCounter");
// A timer.
console_time!();
console_time_end!();
console_time!("with a label");
console_time_log!("with a label", "and", 1, "data");
console_time_log!("with a label", 1, 2, 3, 4, 5, 6, 7, 8, "data");
console_time_end!("with a label");
// A performance timestamp.
console_time_stamp!(); // outputs nothing to console
console_time_stamp!("with a label"); // outputs nothing to console
}

1
examples/web-sys/static/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Weblog Test</title>
<script type="module">
import init from "/wasm.js";
init();
</script>
<link rel="shortcut icon" href="#" />
</head>
<body>
<h2>Check developer tools console for log messages.</h2>
</body>
</html>

View File

@ -1,5 +1,2 @@
#[cfg(feature = "web_sys")]
pub mod web_sys;
#[cfg(feature = "std_web")]
pub mod std_web;

View File

@ -1,26 +1,50 @@
pub extern crate stdweb;
pub use stdweb::js;
#[doc = "Call the browser's `console.debug()` function."]
#[doc = "Call the browser's `console.assert()` function."]
#[macro_export]
macro_rules! console_debug {
($( $item:expr ),* ) => {{
$crate::stdweb::js! { console.debug($( @{$item} ),*) }
macro_rules! console_assert {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.assert($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.clear()` function."]
#[macro_export]
macro_rules! console_clear {
($item:expr) => {{
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.clear() }
}};
}
#[doc = "Call the browser's `console.count()` function."]
#[macro_export]
macro_rules! console_count {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.count($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.countReset()` function."]
#[macro_export]
macro_rules! console_count_reset {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.countReset($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.debug()` function."]
#[macro_export]
macro_rules! console_debug {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.debug($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.dir()` function."]
#[macro_export]
macro_rules! console_dir {
($( $item:expr ),* ) => {{
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.dir($( @{$item} ),*) }
}};
}
@ -28,7 +52,7 @@ macro_rules! console_dir {
#[doc = "Call the browser's `console.dirxml()` function."]
#[macro_export]
macro_rules! console_dirxml {
($( $item:expr ),* ) => {{
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.dirxml($( @{$item} ),*) }
}};
}
@ -36,15 +60,23 @@ macro_rules! console_dirxml {
#[doc = "Call the browser's `console.error()` function."]
#[macro_export]
macro_rules! console_error {
($( $item:expr ),* ) => {{
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.error($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.exception()` function."]
#[macro_export]
macro_rules! console_exception {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.exception($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.info()` function."]
#[macro_export]
macro_rules! console_info {
($( $item:expr ),* ) => {{
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.info($( @{$item} ),*) }
}};
}
@ -52,15 +84,55 @@ macro_rules! console_info {
#[doc = "Call the browser's `console.log()` function."]
#[macro_export]
macro_rules! console_log {
($( $item:expr ),* ) => {{
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.log($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.table()` function."]
#[macro_export]
macro_rules! console_table {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.table($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.time()` function."]
#[macro_export]
macro_rules! console_time {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.time($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.timeEnd()` function."]
#[macro_export]
macro_rules! console_time_end {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.timeEnd($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.timeLog()` function."]
#[macro_export]
macro_rules! console_time_log {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.timeLog($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.timeStamp()` function."]
#[macro_export]
macro_rules! console_time_stamp {
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.timeStamp($( @{$item} ),*) }
}};
}
#[doc = "Call the browser's `console.trace()` function."]
#[macro_export]
macro_rules! console_trace {
($( $item:expr ),* ) => {{
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.trace($( @{$item} ),*) }
}};
}
@ -68,7 +140,7 @@ macro_rules! console_trace {
#[doc = "Call the browser's `console.warn()` function."]
#[macro_export]
macro_rules! console_warn {
($( $item:expr ),* ) => {{
($($item:expr),* $(,)?) => {{
$crate::stdweb::js! { console.warn($( @{$item} ),*) }
}};
}

View File

@ -1,105 +0,0 @@
use paste::paste;
#[doc(hidden)]
pub mod __macro {
pub use js_sys::Array;
pub use wasm_bindgen::JsValue;
pub use web_sys::console;
}
#[doc(hidden)]
#[macro_export]
macro_rules! __jsvalue {
($value: expr) => {
::std::convert::Into::<$crate::__macro::JsValue>::into($value)
};
}
macro_rules! websys_rules {
// $dollar is a workaround to allow repetition in nested macros.
// It needs to be the token `$`.
($dollar:tt, $level:ident) => {
paste! {
#[doc = "Call the browser's `console." $level "()` function.\n\n\
The web-sys crate accepts any amount of arguments, all of which must implement `Into<JsValue>`.\n\n\
See the [wasm-bindgen documentation](../wasm_bindgen/struct.JsValue.html) for more information."]
#[macro_export]
macro_rules! [<console_ $level>] {
() => {
$crate::__macro::console::[<$level _0>]()
};
($a:expr $dollar(,)?) => {
$crate::__macro::console::[<$level _1>](&$crate::__jsvalue!($a))
};
($a:expr, $b:expr $dollar(,)?) => {
$crate::__macro::console::[<$level _2>](&$crate::__jsvalue!($a), &$crate::__jsvalue!($b))
};
($a:expr, $b:expr, $c:expr $dollar(,)?) => {
$crate::__macro::console::[<$level _3>](&$crate::__jsvalue!($a), &$crate::__jsvalue!($b), &$crate::__jsvalue!($c))
};
($a:expr, $b:expr, $c:expr, $d:expr $dollar(,)?) => {
$crate::__macro::console::[<$level _4>](
&$crate::__jsvalue!($a),
&$crate::__jsvalue!($b),
&$crate::__jsvalue!($c),
&$crate::__jsvalue!($d),
)
};
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr $dollar(,)?) => {
$crate::__macro::console::[<$level _5>](
&$crate::__jsvalue!($a),
&$crate::__jsvalue!($b),
&$crate::__jsvalue!($c),
&$crate::__jsvalue!($d),
&$crate::__jsvalue!($e),
)
};
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr $dollar(,)?) => {
$crate::__macro::console::[<$level _6>](
&$crate::__jsvalue!($a),
&$crate::__jsvalue!($b),
&$crate::__jsvalue!($c),
&$crate::__jsvalue!($d),
&$crate::__jsvalue!($e),
&$crate::__jsvalue!($f),
)
};
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr $dollar(,)?) => {
$crate::__macro::console::[<$level _7>](
&$crate::__jsvalue!($a),
&$crate::__jsvalue!($b),
&$crate::__jsvalue!($c),
&$crate::__jsvalue!($d),
&$crate::__jsvalue!($e),
&$crate::__jsvalue!($f),
&$crate::__jsvalue!($g),
)
};
($dollar($dollar item:expr),+ $dollar(,)?) => {
{
let args = ::std::vec![$dollar($crate::__jsvalue!($dollar item)),+];
let args = ::std::iter::IntoIterator::into_iter(args).collect::<$crate::__macro::Array>();
$crate::__macro::console::$level(&args)
}
};
}
}
}
}
websys_rules!($, debug);
websys_rules!($, dir);
websys_rules!($, dirxml);
websys_rules!($, error);
websys_rules!($, info);
websys_rules!($, log);
websys_rules!($, trace);
websys_rules!($, warn);
#[doc = "Call the browser's `console.clear()` function."]
#[macro_export]
macro_rules! console_clear {
() => {
$crate::__macro::console::clear()
};
}

View File

@ -64,7 +64,7 @@
//! By default, the crate assumes the presence of the `web-sys` crate.
//!
//! ```toml
//! weblog = "0.1"
//! weblog = "0.3"
//! ```
//!
//!
@ -72,13 +72,16 @@
//! with `stdweb`, enable the feature in `Cargo.toml`:
//!
//! ```toml
//! weblog = { version = "0.1", default-features = false, features = ["stdweb"] }
//! weblog = { version = "0.3", default-features = false, features = ["stdweb"] }
//! ```
//!
mod console;
#[cfg(feature = "web_sys")]
pub use self::console::web_sys::*;
pub use weblog_proc_macro::*;
#[cfg(feature = "web_sys")]
pub use ::web_sys;
#[cfg(feature = "std_web")]
pub use self::console::std_web::*;

View File

@ -0,0 +1,17 @@
[package]
name = "weblog-proc-macro"
version = "0.3.0-beta.1"
authors = ["Rob Watson <rfwatson@users.noreply.github.com>"]
repository = "https://github.com/rfwatson/weblog"
description = "weblog is a crate that defines a set of macros for calling `console.log()` and other members of the browser's console API when targeting Wasm."
edition = "2018"
keywords = ["wasm", "webassembly", "console", "log", "logging"]
license = "MIT OR Apache-2.0"
[lib]
proc-macro = true
[dependencies]
syn = "1.0.41"
quote = "1.0.7"
proc-macro2 = "1.0"

View File

@ -0,0 +1,231 @@
extern crate proc_macro2;
mod weblog_impl;
use proc_macro::TokenStream;
use std::iter;
use weblog_impl::{quote_console_func, ArgMode, ConsoleFunc};
/// Call the browser's `console.assert()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/assert)
#[proc_macro]
pub fn console_assert(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("assert_with_condition_and_data", 1),
iter::once(ArgMode::PassThrough).chain(iter::repeat(ArgMode::IntoJsValue)),
input,
)
}
/// Call the browser's `console.clear()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/clear)
#[proc_macro]
pub fn console_clear(input: TokenStream) -> TokenStream {
quote_console_func(ConsoleFunc::fixed("clear", 0), iter::empty(), input)
}
/// Call the browser's `console.count()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/count)
#[proc_macro]
pub fn console_count(input: TokenStream) -> TokenStream {
let name = if input.is_empty() {
"count"
} else {
"count_with_label"
};
quote_console_func(
ConsoleFunc::fixed(name, 1),
iter::once(ArgMode::PassThrough),
input,
)
}
/// Call the browser's `console.countReset()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/countReset)
#[proc_macro]
pub fn console_count_reset(input: TokenStream) -> TokenStream {
let name = if input.is_empty() {
"count_reset"
} else {
"count_reset_with_label"
};
quote_console_func(
ConsoleFunc::fixed(name, 1),
iter::once(ArgMode::PassThrough),
input,
)
}
/// Call the browser's `console.debug()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/debug)
#[proc_macro]
pub fn console_debug(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("debug", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.dir()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/dir)
#[proc_macro]
pub fn console_dir(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("dir", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.dirxml()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/dirxml)
#[proc_macro]
pub fn console_dirxml(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("dirxml", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.error()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/error)
#[proc_macro]
pub fn console_error(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("error", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.exception()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/exception)
#[proc_macro]
pub fn console_exception(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("exception", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.info()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/info)
#[proc_macro]
pub fn console_info(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("info", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.log()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/log)
#[proc_macro]
pub fn console_log(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("log", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.table()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/table)
#[proc_macro]
pub fn console_table(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("table", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.time()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/time)
#[proc_macro]
pub fn console_time(input: TokenStream) -> TokenStream {
let name = if input.is_empty() {
"time"
} else {
"time_with_label"
};
quote_console_func(
ConsoleFunc::fixed(name, 1),
iter::once(ArgMode::PassThrough),
input,
)
}
/// Call the browser's `console.timeEnd()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/timeEnd)
#[proc_macro]
pub fn console_time_end(input: TokenStream) -> TokenStream {
let name = if input.is_empty() {
"time_end"
} else {
"time_end_with_label"
};
quote_console_func(
ConsoleFunc::fixed(name, 1),
iter::once(ArgMode::PassThrough),
input,
)
}
/// Call the browser's `console.timeLog()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/timeLog)
#[proc_macro]
pub fn console_time_log(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("time_log_with_label_and_data", 1),
iter::once(ArgMode::PassThrough).chain(iter::repeat(ArgMode::IntoJsValue)),
input,
)
}
/// Call the browser's `console.timeStamp()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/timeStamp)
#[proc_macro]
pub fn console_time_stamp(input: TokenStream) -> TokenStream {
let name = if input.is_empty() {
"time_stamp"
} else {
"time_stamp_with_data"
};
quote_console_func(
ConsoleFunc::fixed(name, 1),
iter::once(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.trace()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/trace)
#[proc_macro]
pub fn console_trace(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("trace", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}
/// Call the browser's `console.warn()` function.
/// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console/warn)
#[proc_macro]
pub fn console_warn(input: TokenStream) -> TokenStream {
quote_console_func(
ConsoleFunc::variadic("warn", 0),
iter::repeat(ArgMode::IntoJsValue),
input,
)
}

View File

@ -0,0 +1,124 @@
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
use quote::quote;
use std::cmp;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{parse_macro_input, Expr, Result, Token};
// quote_console_func builds and quotes a call to the browser's console API, based on the
// provided console function and argument types and the input token stream provider by
// the macro caller.
//
// Arguments:
//
// * `func`: an object containing the target function name and parameter configuration.
// * `arg_modes`: an Iterator that will be called once per argument parsed from the input tokens.
// * `input`: the raw input tokens, as provided by the macro caller.
pub fn quote_console_func(
ConsoleFunc {
name,
params_fixed,
is_variadic,
}: ConsoleFunc,
mut arg_modes: impl Iterator<Item = ArgMode>,
input: TokenStream,
) -> TokenStream {
let InArgs(in_args) = parse_macro_input!(input as InArgs);
let mut out_args = in_args
.iter()
.map(|arg| quote_arg(arg, arg_modes.next().unwrap_or_default()));
let num_provided = out_args.len();
let num_fixed = cmp::min(num_provided, params_fixed);
let num_variadic = cmp::max(num_provided - num_fixed, 0);
let ident = {
let func_name = if is_variadic && num_variadic <= 7 {
format!("{}_{}", name, num_variadic)
} else {
name
};
Ident::new(&func_name, Span::call_site())
};
let mut args: Punctuated<_, Token![,]> = Punctuated::new();
{
for _ in 0..num_fixed {
args.push(out_args.next().unwrap());
}
if num_variadic > 7 {
let variadic_args = out_args.collect::<Punctuated<_, Token![,]>>();
let ary = quote! {
&::std::iter::FromIterator::from_iter(::std::iter::IntoIterator::into_iter(::std::vec![#variadic_args]))
};
args.push(ary);
} else {
for _ in 0..num_variadic {
args.push(out_args.next().unwrap());
}
}
}
(quote! { ::weblog::web_sys::console::#ident(#args) }).into()
}
fn quote_arg(arg: &Expr, arg_mode: ArgMode) -> TokenStream2 {
match arg_mode {
ArgMode::PassThrough => {
quote! { #arg }
}
ArgMode::IntoJsValue => {
quote! { &::std::convert::Into::<::wasm_bindgen::JsValue>::into(#arg) }
}
}
}
// ConsoleFunc represents the console API function being targeted.
#[derive(Debug)]
pub struct ConsoleFunc {
name: String,
params_fixed: usize,
is_variadic: bool,
}
impl ConsoleFunc {
pub fn fixed(name: &str, params_fixed: usize) -> Self {
Self {
name: name.into(),
params_fixed,
is_variadic: false,
}
}
pub fn variadic(name: &str, params_fixed: usize) -> Self {
Self {
name: name.into(),
params_fixed,
is_variadic: true,
}
}
}
// ArgMode represents an argument being passed to a targeted ConsoleFunc.
#[derive(Debug, Copy, Clone)]
pub enum ArgMode {
PassThrough,
IntoJsValue,
}
impl Default for ArgMode {
fn default() -> Self {
Self::PassThrough
}
}
// InArgs is a struct required during parsing of input arguments.
struct InArgs(Punctuated<Expr, Token![,]>);
impl Parse for InArgs {
fn parse(input: ParseStream) -> Result<Self> {
let in_args: Punctuated<Expr, Token![,]> = Punctuated::parse_terminated(&input)?;
Ok(Self(in_args))
}
}