Refactor to proc-macro
This commit is contained in:
parent
944357868c
commit
fce19e049d
|
@ -1,2 +1,2 @@
|
|||
/target
|
||||
target/
|
||||
Cargo.lock
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -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 }
|
||||
|
|
5
Makefile
5
Makefile
|
@ -1,2 +1,7 @@
|
|||
all: build
|
||||
|
||||
build:
|
||||
cargo build
|
||||
|
||||
docs:
|
||||
cargo doc --all --no-deps --target wasm32-unknown-unknown && cargo doc --open
|
||||
|
|
12
README.md
12
README.md
|
@ -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!`
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/target/
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
*
|
|
@ -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>
|
|
@ -1,5 +1,2 @@
|
|||
#[cfg(feature = "web_sys")]
|
||||
pub mod web_sys;
|
||||
|
||||
#[cfg(feature = "std_web")]
|
||||
pub mod std_web;
|
||||
|
|
|
@ -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} ),*) }
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
}
|
|
@ -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::*;
|
||||
|
|
|
@ -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"
|
|
@ -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,
|
||||
)
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue