mirror of
https://gitee.com/openharmony/third_party_rust_quote
synced 2024-11-27 01:11:38 +00:00
commit
50a4349c6a
6
.cargo_vcs_info.json
Normal file
6
.cargo_vcs_info.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "b01743f24cb5b19f96a3eac6bce0e7aee10f6199"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
@ -1 +0,0 @@
|
||||
msrv = "1.31.0"
|
63
.github/workflows/ci.yml
vendored
63
.github/workflows/ci.yml
vendored
@ -3,6 +3,7 @@ name: CI
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule: [cron: "40 1 * * *"]
|
||||
|
||||
permissions:
|
||||
@ -12,45 +13,58 @@ env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
|
||||
jobs:
|
||||
pre_ci:
|
||||
uses: dtolnay/.github/.github/workflows/pre_ci.yml@master
|
||||
|
||||
test:
|
||||
name: Rust ${{matrix.rust}}
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
rust: [stable, beta, 1.56.0]
|
||||
rust: [nightly, stable, beta, 1.56.0]
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{matrix.rust}}
|
||||
components: rust-src
|
||||
- name: Enable type layout randomization
|
||||
run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV
|
||||
if: matrix.rust == 'nightly'
|
||||
- run: cargo test
|
||||
- run: cargo run --manifest-path benches/Cargo.toml
|
||||
|
||||
nightly:
|
||||
name: Rust nightly
|
||||
minimal:
|
||||
name: Minimal versions
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cargo generate-lockfile -Z minimal-versions
|
||||
- run: cargo check --locked
|
||||
|
||||
doc:
|
||||
name: Documentation
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
RUSTDOCFLAGS: -Dwarnings
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: rust-src
|
||||
- run: cargo test
|
||||
- run: cargo update -Z minimal-versions
|
||||
- run: cargo build
|
||||
|
||||
msrv:
|
||||
name: Rust 1.31.0
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@1.31.0
|
||||
with:
|
||||
components: rust-src
|
||||
- run: cargo check
|
||||
- uses: dtolnay/install@cargo-docs-rs
|
||||
- run: cargo docs-rs
|
||||
|
||||
clippy:
|
||||
name: Clippy
|
||||
@ -58,19 +72,22 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: clippy, rust-src
|
||||
- run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic
|
||||
- run: cargo clippy --tests --workspace -- -Dclippy::all -Dclippy::pedantic
|
||||
|
||||
miri:
|
||||
name: Miri
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@miri
|
||||
- run: cargo miri setup
|
||||
- run: cargo miri test
|
||||
env:
|
||||
MIRIFLAGS: -Zmiri-strict-provenance
|
||||
@ -81,6 +98,6 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/install@cargo-outdated
|
||||
- run: cargo outdated --workspace --exit-code 1
|
||||
|
24
BUILD.gn
24
BUILD.gn
@ -14,18 +14,16 @@
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_cargo_crate("lib") {
|
||||
crate_name = "quote"
|
||||
crate_type = "rlib"
|
||||
crate_root = "src/lib.rs"
|
||||
crate_name = "quote"
|
||||
crate_type = "rlib"
|
||||
crate_root = "src/lib.rs"
|
||||
|
||||
sources = ["src/lib.rs"]
|
||||
edition = "2018"
|
||||
cargo_pkg_version = "1.0.23"
|
||||
cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
|
||||
cargo_pkg_name = "quote"
|
||||
cargo_pkg_description = "Quasi-quoting macro quote!(...)"
|
||||
deps = ["//third_party/rust/crates/proc-macro2:lib"]
|
||||
features = ["proc-macro"]
|
||||
build_root = "build.rs"
|
||||
build_sources = ["build.rs"]
|
||||
sources = [ "src/lib.rs" ]
|
||||
edition = "2018"
|
||||
cargo_pkg_version = "1.0.35"
|
||||
cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
|
||||
cargo_pkg_name = "quote"
|
||||
cargo_pkg_description = "Quasi-quoting macro quote!(...)"
|
||||
deps = [ "//third_party/rust/crates/proc-macro2:lib" ]
|
||||
features = [ "proc-macro" ]
|
||||
}
|
||||
|
57
Cargo.toml
57
Cargo.toml
@ -1,35 +1,50 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
rust-version = "1.56"
|
||||
name = "quote"
|
||||
version = "1.0.23" # don't forget to update html_root_url, version in readme for breaking changes
|
||||
version = "1.0.35"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
autobenches = false
|
||||
categories = ["development-tools::procedural-macro-helpers"]
|
||||
description = "Quasi-quoting macro quote!(...)"
|
||||
documentation = "https://docs.rs/quote/"
|
||||
edition = "2018"
|
||||
keywords = ["macros", "syn"]
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"macros",
|
||||
"syn",
|
||||
]
|
||||
categories = ["development-tools::procedural-macro-helpers"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/quote"
|
||||
rust-version = "1.31"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = { version = "1.0.40", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
rustversion = "1.0"
|
||||
trybuild = { version = "1.0.66", features = ["diff"] }
|
||||
|
||||
[features]
|
||||
default = ["proc-macro"]
|
||||
# Disabling the proc-macro feature removes the dynamic library dependency on
|
||||
# libproc_macro in the rustc compiler.
|
||||
proc-macro = ["proc-macro2/proc-macro"]
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
|
||||
[workspace]
|
||||
members = ["benches"]
|
||||
[dependencies.proc-macro2]
|
||||
version = "1.0.74"
|
||||
default-features = false
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
[dev-dependencies.rustversion]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.trybuild]
|
||||
version = "1.0.66"
|
||||
features = ["diff"]
|
||||
|
||||
[features]
|
||||
default = ["proc-macro"]
|
||||
proc-macro = ["proc-macro2/proc-macro"]
|
||||
|
36
Cargo.toml.orig
generated
Normal file
36
Cargo.toml.orig
generated
Normal file
@ -0,0 +1,36 @@
|
||||
[package]
|
||||
name = "quote"
|
||||
version = "1.0.35" # don't forget to update html_root_url, version in readme for breaking changes
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
autobenches = false
|
||||
categories = ["development-tools::procedural-macro-helpers"]
|
||||
description = "Quasi-quoting macro quote!(...)"
|
||||
documentation = "https://docs.rs/quote/"
|
||||
edition = "2018"
|
||||
keywords = ["macros", "syn"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/quote"
|
||||
rust-version = "1.56"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = { version = "1.0.74", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
rustversion = "1.0"
|
||||
trybuild = { version = "1.0.66", features = ["diff"] }
|
||||
|
||||
[features]
|
||||
default = ["proc-macro"]
|
||||
# Disabling the proc-macro feature removes the dynamic library dependency on
|
||||
# libproc_macro in the rustc compiler.
|
||||
proc-macro = ["proc-macro2/proc-macro"]
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
|
||||
[workspace]
|
||||
members = ["benches"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
@ -3,7 +3,7 @@
|
||||
"Name": "quote",
|
||||
"License": "Apache License V2.0, MIT",
|
||||
"License File": "LICENSE-APACHE, LICENSE-MIT",
|
||||
"Version Number": "1.0.23",
|
||||
"Version Number": "1.0.35",
|
||||
"Owner": "fangting12@huawei.com",
|
||||
"Upstream URL": "https://github.com/dtolnay/quote",
|
||||
"Description": "A Rust library that provides support for generating Rust code."
|
||||
|
23
README.md
23
README.md
@ -34,7 +34,7 @@ macros.
|
||||
quote = "1.0"
|
||||
```
|
||||
|
||||
*Version requirement: Quote supports rustc 1.31 and up.*<br>
|
||||
*Version requirement: Quote supports rustc 1.56 and up.*<br>
|
||||
[*Release notes*](https://github.com/dtolnay/quote/releases)
|
||||
|
||||
<br>
|
||||
@ -233,15 +233,26 @@ macro.
|
||||
## Non-macro code generators
|
||||
|
||||
When using `quote` in a build.rs or main.rs and writing the output out to a
|
||||
file, consider having the code generator pass the tokens through [rustfmt]
|
||||
before writing (either by shelling out to the `rustfmt` binary or by pulling in
|
||||
the `rustfmt` library as a dependency). This way if an error occurs in the
|
||||
generated code it is convenient for a human to read and debug.
|
||||
file, consider having the code generator pass the tokens through [prettyplease]
|
||||
before writing. This way if an error occurs in the generated code it is
|
||||
convenient for a human to read and debug.
|
||||
|
||||
Be aware that no kind of hygiene or span information is retained when tokens are
|
||||
written to a file; the conversion from tokens to source code is lossy.
|
||||
|
||||
[rustfmt]: https://github.com/rust-lang/rustfmt
|
||||
Example usage in build.rs:
|
||||
|
||||
```rust
|
||||
let output = quote! { ... };
|
||||
let syntax_tree = syn::parse2(output).unwrap();
|
||||
let formatted = prettyplease::unparse(&syntax_tree);
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let dest_path = Path::new(&out_dir).join("out.rs");
|
||||
fs::write(dest_path, formatted).unwrap();
|
||||
```
|
||||
|
||||
[prettyplease]: https://github.com/dtolnay/prettyplease
|
||||
|
||||
<br>
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
[package]
|
||||
name = "quote-benchmark"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
path = "lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "quote-benchmark"
|
||||
path = "main.rs"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = { path = ".." }
|
||||
termcolor = "1.1"
|
@ -1,18 +0,0 @@
|
||||
Example output:
|
||||
|
||||
<pre>
|
||||
$ <b>cargo run && cargo run --release</b>
|
||||
|
||||
<i>Compiling quote v1.0.10</i>
|
||||
<i>Compiling quote-benchmark v0.0.0</i>
|
||||
<kbd><kbd><b>macro in debug mode: 1655 micros</b></kbd></kbd>
|
||||
<i>Finished dev [unoptimized + debuginfo] target(s) in 4.39s</i>
|
||||
<i>Running `/git/quote/target/debug/quote-benchmark`</i>
|
||||
<kbd><kbd><b>non-macro in debug mode: 1205 micros</b></kbd></kbd>
|
||||
<i>Compiling quote v1.0.10</i>
|
||||
<i>Compiling quote-benchmark v0.0.0</i>
|
||||
<kbd><kbd><b>macro in release mode: 1635 micros</b></kbd></kbd>
|
||||
<i>Finished release [optimized] target(s) in 4.00s</i>
|
||||
<i>Running `/git/quote/target/release/quote-benchmark`</i>
|
||||
<kbd><kbd><b>non-macro in release mode: 105 micros</b></kbd></kbd>
|
||||
</pre>
|
206
benches/lib.rs
206
benches/lib.rs
@ -1,206 +0,0 @@
|
||||
use quote::quote;
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! benchmark {
|
||||
(|$ident:ident| $quote:expr) => {
|
||||
mod timer;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Ident;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn run_quote_benchmark(input: TokenStream) -> TokenStream {
|
||||
let input = proc_macro2::TokenStream::from(input);
|
||||
let span = input.into_iter().next().unwrap().span();
|
||||
let $ident = Ident::new("Response", span);
|
||||
timer::time("macro", || proc_macro::TokenStream::from($quote));
|
||||
TokenStream::new()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use benchmark;
|
||||
|
||||
crate::benchmark! {
|
||||
|ident| quote! {
|
||||
impl<'de> _serde::Deserialize<'de> for #ident {
|
||||
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
|
||||
where
|
||||
__D: _serde::Deserializer<'de>,
|
||||
{
|
||||
#[allow(non_camel_case_types)]
|
||||
enum __Field {
|
||||
__field0,
|
||||
__field1,
|
||||
__ignore,
|
||||
}
|
||||
struct __FieldVisitor;
|
||||
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
|
||||
type Value = __Field;
|
||||
fn expecting(
|
||||
&self,
|
||||
__formatter: &mut _serde::export::Formatter,
|
||||
) -> _serde::export::fmt::Result {
|
||||
_serde::export::Formatter::write_str(__formatter, "field identifier")
|
||||
}
|
||||
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
0u64 => _serde::export::Ok(__Field::__field0),
|
||||
1u64 => _serde::export::Ok(__Field::__field1),
|
||||
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 2",
|
||||
)),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
"id" => _serde::export::Ok(__Field::__field0),
|
||||
"s" => _serde::export::Ok(__Field::__field1),
|
||||
_ => _serde::export::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_bytes<__E>(
|
||||
self,
|
||||
__value: &[u8],
|
||||
) -> _serde::export::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
b"id" => _serde::export::Ok(__Field::__field0),
|
||||
b"s" => _serde::export::Ok(__Field::__field1),
|
||||
_ => _serde::export::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'de> _serde::Deserialize<'de> for __Field {
|
||||
#[inline]
|
||||
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
|
||||
where
|
||||
__D: _serde::Deserializer<'de>,
|
||||
{
|
||||
_serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
|
||||
}
|
||||
}
|
||||
struct __Visitor<'de> {
|
||||
marker: _serde::export::PhantomData<#ident>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
}
|
||||
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
|
||||
type Value = #ident;
|
||||
fn expecting(
|
||||
&self,
|
||||
__formatter: &mut _serde::export::Formatter,
|
||||
) -> _serde::export::fmt::Result {
|
||||
_serde::export::Formatter::write_str(__formatter, "struct")
|
||||
}
|
||||
#[inline]
|
||||
fn visit_seq<__A>(
|
||||
self,
|
||||
mut __seq: __A,
|
||||
) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::SeqAccess<'de>,
|
||||
{
|
||||
let __field0 =
|
||||
match try!(_serde::de::SeqAccess::next_element::<u64>(&mut __seq)) {
|
||||
_serde::export::Some(__value) => __value,
|
||||
_serde::export::None => {
|
||||
return _serde::export::Err(_serde::de::Error::invalid_length(
|
||||
0usize,
|
||||
&"struct with 2 elements",
|
||||
));
|
||||
}
|
||||
};
|
||||
let __field1 =
|
||||
match try!(_serde::de::SeqAccess::next_element::<String>(&mut __seq)) {
|
||||
_serde::export::Some(__value) => __value,
|
||||
_serde::export::None => {
|
||||
return _serde::export::Err(_serde::de::Error::invalid_length(
|
||||
1usize,
|
||||
&"struct with 2 elements",
|
||||
));
|
||||
}
|
||||
};
|
||||
_serde::export::Ok(#ident {
|
||||
id: __field0,
|
||||
s: __field1,
|
||||
})
|
||||
}
|
||||
#[inline]
|
||||
fn visit_map<__A>(
|
||||
self,
|
||||
mut __map: __A,
|
||||
) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::MapAccess<'de>,
|
||||
{
|
||||
let mut __field0: _serde::export::Option<u64> = _serde::export::None;
|
||||
let mut __field1: _serde::export::Option<String> = _serde::export::None;
|
||||
while let _serde::export::Some(__key) =
|
||||
try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map))
|
||||
{
|
||||
match __key {
|
||||
__Field::__field0 => {
|
||||
if _serde::export::Option::is_some(&__field0) {
|
||||
return _serde::export::Err(
|
||||
<__A::Error as _serde::de::Error>::duplicate_field("id"),
|
||||
);
|
||||
}
|
||||
__field0 = _serde::export::Some(
|
||||
try!(_serde::de::MapAccess::next_value::<u64>(&mut __map)),
|
||||
);
|
||||
}
|
||||
__Field::__field1 => {
|
||||
if _serde::export::Option::is_some(&__field1) {
|
||||
return _serde::export::Err(
|
||||
<__A::Error as _serde::de::Error>::duplicate_field("s"),
|
||||
);
|
||||
}
|
||||
__field1 = _serde::export::Some(
|
||||
try!(_serde::de::MapAccess::next_value::<String>(&mut __map)),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
let _ = try!(_serde::de::MapAccess::next_value::<
|
||||
_serde::de::IgnoredAny,
|
||||
>(&mut __map));
|
||||
}
|
||||
}
|
||||
}
|
||||
let __field0 = match __field0 {
|
||||
_serde::export::Some(__field0) => __field0,
|
||||
_serde::export::None => try!(_serde::private::de::missing_field("id")),
|
||||
};
|
||||
let __field1 = match __field1 {
|
||||
_serde::export::Some(__field1) => __field1,
|
||||
_serde::export::None => try!(_serde::private::de::missing_field("s")),
|
||||
};
|
||||
_serde::export::Ok(#ident {
|
||||
id: __field0,
|
||||
s: __field1,
|
||||
})
|
||||
}
|
||||
}
|
||||
const FIELDS: &'static [&'static str] = &["id", "s"];
|
||||
_serde::Deserializer::deserialize_struct(
|
||||
__deserializer,
|
||||
stringify!(#ident),
|
||||
FIELDS,
|
||||
__Visitor {
|
||||
marker: _serde::export::PhantomData::<#ident>,
|
||||
lifetime: _serde::export::PhantomData,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
quote_benchmark::run_quote_benchmark!(_);
|
||||
|
||||
mod benchmark {
|
||||
macro_rules! benchmark {
|
||||
(|$ident:ident| $quote:expr) => {
|
||||
use proc_macro2::{Ident, Span};
|
||||
|
||||
pub fn quote() -> proc_macro2::TokenStream {
|
||||
let $ident = Ident::new("Response", Span::call_site());
|
||||
$quote
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use benchmark;
|
||||
}
|
||||
|
||||
use benchmark::benchmark;
|
||||
|
||||
mod lib;
|
||||
mod timer;
|
||||
|
||||
fn main() {
|
||||
timer::time("non-macro", lib::quote);
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
use std::io::Write;
|
||||
use std::time::Instant;
|
||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||
|
||||
const ITERATIONS: u32 = 1000;
|
||||
|
||||
pub fn time<T>(name: &'static str, function: impl Fn() -> T) {
|
||||
let begin = Instant::now();
|
||||
for _ in 0..ITERATIONS {
|
||||
_ = function();
|
||||
}
|
||||
let micros = (begin.elapsed() / ITERATIONS).as_micros();
|
||||
let mode = ["release", "debug"][cfg!(debug_assertions) as usize];
|
||||
let mut writer = StandardStream::stderr(ColorChoice::Auto);
|
||||
_ = writer.set_color(ColorSpec::new().set_fg(Some(Color::Magenta)));
|
||||
_ = writeln!(&mut writer, "{} in {} mode: {} micros", name, mode, micros);
|
||||
}
|
38
build.rs
38
build.rs
@ -1,38 +0,0 @@
|
||||
use std::env;
|
||||
use std::process::{self, Command};
|
||||
use std::str;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let version = match rustc_version() {
|
||||
Some(version) => version,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if version.minor < 31 {
|
||||
eprintln!("Minimum supported rustc version is 1.31");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
if version.minor < 53 {
|
||||
// https://github.com/rust-lang/rust/issues/43081
|
||||
println!("cargo:rustc-cfg=needs_invalid_span_workaround");
|
||||
}
|
||||
}
|
||||
|
||||
struct RustcVersion {
|
||||
minor: u32,
|
||||
}
|
||||
|
||||
fn rustc_version() -> Option<RustcVersion> {
|
||||
let rustc = env::var_os("RUSTC")?;
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = str::from_utf8(&output.stdout).ok()?;
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return None;
|
||||
}
|
||||
let minor = pieces.next()?.parse().ok()?;
|
||||
Some(RustcVersion { minor })
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use alloc::borrow::Cow;
|
||||
use core::fmt;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Specialized formatting trait used by `format_ident!`.
|
||||
///
|
||||
@ -8,6 +8,8 @@ use std::borrow::Cow;
|
||||
/// stripped, if present.
|
||||
///
|
||||
/// See [`format_ident!`] for more information.
|
||||
///
|
||||
/// [`format_ident!`]: crate::format_ident
|
||||
pub trait IdentFragment {
|
||||
/// Format this value as an identifier fragment.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
|
||||
@ -47,8 +49,8 @@ impl IdentFragment for Ident {
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let id = self.to_string();
|
||||
if id.starts_with("r#") {
|
||||
fmt::Display::fmt(&id[2..], f)
|
||||
if let Some(id) = id.strip_prefix("r#") {
|
||||
fmt::Display::fmt(id, f)
|
||||
} else {
|
||||
fmt::Display::fmt(&id[..], f)
|
||||
}
|
||||
|
32
src/lib.rs
32
src/lib.rs
@ -79,9 +79,20 @@
|
||||
//! }
|
||||
//! };
|
||||
//! ```
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Non-macro code generators
|
||||
//!
|
||||
//! When using `quote` in a build.rs or main.rs and writing the output out to a
|
||||
//! file, consider having the code generator pass the tokens through
|
||||
//! [prettyplease] before writing. This way if an error occurs in the generated
|
||||
//! code it is convenient for a human to read and debug.
|
||||
//!
|
||||
//! [prettyplease]: https://github.com/dtolnay/prettyplease
|
||||
|
||||
// Quote types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/quote/1.0.23")]
|
||||
#![doc(html_root_url = "https://docs.rs/quote/1.0.35")]
|
||||
#![allow(
|
||||
clippy::doc_markdown,
|
||||
clippy::missing_errors_doc,
|
||||
@ -91,10 +102,9 @@
|
||||
clippy::wrong_self_convention,
|
||||
)]
|
||||
|
||||
#[cfg(all(
|
||||
not(all(target_arch = "wasm32", target_os = "unknown")),
|
||||
feature = "proc-macro"
|
||||
))]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "proc-macro")]
|
||||
extern crate proc_macro;
|
||||
|
||||
mod ext;
|
||||
@ -418,7 +428,7 @@ pub mod spanned;
|
||||
/// appears suffixed as integer literals by interpolating them as [`syn::Index`]
|
||||
/// instead.
|
||||
///
|
||||
/// [`syn::Index`]: https://docs.rs/syn/1.0/syn/struct.Index.html
|
||||
/// [`syn::Index`]: https://docs.rs/syn/2.0/syn/struct.Index.html
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// let i = 0usize..self.fields.len();
|
||||
@ -619,14 +629,14 @@ macro_rules! quote_spanned {
|
||||
#[macro_export]
|
||||
macro_rules! quote_spanned {
|
||||
($span:expr=>) => {{
|
||||
let _: $crate::__private::Span = $span;
|
||||
let _: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
|
||||
$crate::__private::TokenStream::new()
|
||||
}};
|
||||
|
||||
// Special case rule for a single tt, for performance.
|
||||
($span:expr=> $tt:tt) => {{
|
||||
let mut _s = $crate::__private::TokenStream::new();
|
||||
let _span: $crate::__private::Span = $span;
|
||||
let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
|
||||
$crate::quote_token_spanned!{$tt _s _span}
|
||||
_s
|
||||
}};
|
||||
@ -634,13 +644,13 @@ macro_rules! quote_spanned {
|
||||
// Special case rules for two tts, for performance.
|
||||
($span:expr=> # $var:ident) => {{
|
||||
let mut _s = $crate::__private::TokenStream::new();
|
||||
let _: $crate::__private::Span = $span;
|
||||
let _: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
|
||||
$crate::ToTokens::to_tokens(&$var, &mut _s);
|
||||
_s
|
||||
}};
|
||||
($span:expr=> $tt1:tt $tt2:tt) => {{
|
||||
let mut _s = $crate::__private::TokenStream::new();
|
||||
let _span: $crate::__private::Span = $span;
|
||||
let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
|
||||
$crate::quote_token_spanned!{$tt1 _s _span}
|
||||
$crate::quote_token_spanned!{$tt2 _s _span}
|
||||
_s
|
||||
@ -649,7 +659,7 @@ macro_rules! quote_spanned {
|
||||
// Rule for any other number of tokens.
|
||||
($span:expr=> $($tt:tt)*) => {{
|
||||
let mut _s = $crate::__private::TokenStream::new();
|
||||
let _span: $crate::__private::Span = $span;
|
||||
let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
|
||||
$crate::quote_each_token_spanned!{_s _span $($tt)*}
|
||||
_s
|
||||
}};
|
||||
|
102
src/runtime.rs
102
src/runtime.rs
@ -1,13 +1,25 @@
|
||||
use self::get_span::{GetSpan, GetSpanBase, GetSpanInner};
|
||||
use crate::{IdentFragment, ToTokens, TokenStreamExt};
|
||||
use core::fmt;
|
||||
use core::iter;
|
||||
use core::ops::BitOr;
|
||||
use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use alloc::format;
|
||||
#[doc(hidden)]
|
||||
pub use core::option::Option;
|
||||
pub use proc_macro2::*;
|
||||
pub use std::format;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type Delimiter = proc_macro2::Delimiter;
|
||||
#[doc(hidden)]
|
||||
pub type Span = proc_macro2::Span;
|
||||
#[doc(hidden)]
|
||||
pub type TokenStream = proc_macro2::TokenStream;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct HasIterator; // True
|
||||
#[doc(hidden)]
|
||||
pub struct ThereIsNoIteratorInRepetition; // False
|
||||
|
||||
impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
|
||||
@ -44,14 +56,16 @@ impl BitOr<HasIterator> for HasIterator {
|
||||
/// These traits expose a `quote_into_iter` method which should allow calling
|
||||
/// whichever impl happens to be applicable. Calling that method repeatedly on
|
||||
/// the returned value should be idempotent.
|
||||
#[doc(hidden)]
|
||||
pub mod ext {
|
||||
use super::RepInterp;
|
||||
use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
|
||||
use crate::ToTokens;
|
||||
use alloc::collections::btree_set::{self, BTreeSet};
|
||||
use core::slice;
|
||||
use std::collections::btree_set::{self, BTreeSet};
|
||||
|
||||
/// Extension trait providing the `quote_into_iter` method on iterators.
|
||||
#[doc(hidden)]
|
||||
pub trait RepIteratorExt: Iterator + Sized {
|
||||
fn quote_into_iter(self) -> (Self, HasIter) {
|
||||
(self, HasIter)
|
||||
@ -63,6 +77,7 @@ pub mod ext {
|
||||
/// Extension trait providing the `quote_into_iter` method for
|
||||
/// non-iterable types. These types interpolate the same value in each
|
||||
/// iteration of the repetition.
|
||||
#[doc(hidden)]
|
||||
pub trait RepToTokensExt {
|
||||
/// Pretend to be an iterator for the purposes of `quote_into_iter`.
|
||||
/// This allows repeated calls to `quote_into_iter` to continue
|
||||
@ -80,6 +95,7 @@ pub mod ext {
|
||||
|
||||
/// Extension trait providing the `quote_into_iter` method for types that
|
||||
/// can be referenced as an iterator.
|
||||
#[doc(hidden)]
|
||||
pub trait RepAsIteratorExt<'q> {
|
||||
type Iter: Iterator;
|
||||
|
||||
@ -138,6 +154,7 @@ pub mod ext {
|
||||
// Helper type used within interpolations to allow for repeated binding names.
|
||||
// Implements the relevant traits, and exports a dummy `next()` method.
|
||||
#[derive(Copy, Clone)]
|
||||
#[doc(hidden)]
|
||||
pub struct RepInterp<T>(pub T);
|
||||
|
||||
impl<T> RepInterp<T> {
|
||||
@ -164,10 +181,69 @@ impl<T: ToTokens> ToTokens for RepInterp<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn get_span<T>(span: T) -> GetSpan<T> {
|
||||
GetSpan(GetSpanInner(GetSpanBase(span)))
|
||||
}
|
||||
|
||||
mod get_span {
|
||||
use core::ops::Deref;
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::Span;
|
||||
|
||||
pub struct GetSpan<T>(pub(crate) GetSpanInner<T>);
|
||||
|
||||
pub struct GetSpanInner<T>(pub(crate) GetSpanBase<T>);
|
||||
|
||||
pub struct GetSpanBase<T>(pub(crate) T);
|
||||
|
||||
impl GetSpan<Span> {
|
||||
#[inline]
|
||||
pub fn __into_span(self) -> Span {
|
||||
((self.0).0).0
|
||||
}
|
||||
}
|
||||
|
||||
impl GetSpanInner<DelimSpan> {
|
||||
#[inline]
|
||||
pub fn __into_span(&self) -> Span {
|
||||
(self.0).0.join()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> GetSpanBase<T> {
|
||||
#[allow(clippy::unused_self)]
|
||||
pub fn __into_span(&self) -> T {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for GetSpan<T> {
|
||||
type Target = GetSpanInner<T>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for GetSpanInner<T> {
|
||||
type Target = GetSpanBase<T>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
|
||||
tokens.append(Group::new(delimiter, inner));
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn push_group_spanned(
|
||||
tokens: &mut TokenStream,
|
||||
span: Span,
|
||||
@ -179,11 +255,13 @@ pub fn push_group_spanned(
|
||||
tokens.append(g);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn parse(tokens: &mut TokenStream, s: &str) {
|
||||
let s: TokenStream = s.parse().expect("invalid token stream");
|
||||
tokens.extend(iter::once(s));
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn parse_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
|
||||
let s: TokenStream = s.parse().expect("invalid token stream");
|
||||
tokens.extend(s.into_iter().map(|t| respan_token_tree(t, span)));
|
||||
@ -206,15 +284,18 @@ fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
|
||||
token
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn push_ident(tokens: &mut TokenStream, s: &str) {
|
||||
let span = Span::call_site();
|
||||
push_ident_spanned(tokens, span, s);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
|
||||
tokens.append(ident_maybe_raw(s, span));
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) {
|
||||
struct Lifetime<'a> {
|
||||
name: &'a str,
|
||||
@ -245,6 +326,7 @@ pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) {
|
||||
});
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str) {
|
||||
struct Lifetime<'a> {
|
||||
name: &'a str,
|
||||
@ -281,9 +363,11 @@ pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &st
|
||||
|
||||
macro_rules! push_punct {
|
||||
($name:ident $spanned:ident $char1:tt) => {
|
||||
#[doc(hidden)]
|
||||
pub fn $name(tokens: &mut TokenStream) {
|
||||
tokens.append(Punct::new($char1, Spacing::Alone));
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub fn $spanned(tokens: &mut TokenStream, span: Span) {
|
||||
let mut punct = Punct::new($char1, Spacing::Alone);
|
||||
punct.set_span(span);
|
||||
@ -291,10 +375,12 @@ macro_rules! push_punct {
|
||||
}
|
||||
};
|
||||
($name:ident $spanned:ident $char1:tt $char2:tt) => {
|
||||
#[doc(hidden)]
|
||||
pub fn $name(tokens: &mut TokenStream) {
|
||||
tokens.append(Punct::new($char1, Spacing::Joint));
|
||||
tokens.append(Punct::new($char2, Spacing::Alone));
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub fn $spanned(tokens: &mut TokenStream, span: Span) {
|
||||
let mut punct = Punct::new($char1, Spacing::Joint);
|
||||
punct.set_span(span);
|
||||
@ -305,11 +391,13 @@ macro_rules! push_punct {
|
||||
}
|
||||
};
|
||||
($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => {
|
||||
#[doc(hidden)]
|
||||
pub fn $name(tokens: &mut TokenStream) {
|
||||
tokens.append(Punct::new($char1, Spacing::Joint));
|
||||
tokens.append(Punct::new($char2, Spacing::Joint));
|
||||
tokens.append(Punct::new($char3, Spacing::Alone));
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub fn $spanned(tokens: &mut TokenStream, span: Span) {
|
||||
let mut punct = Punct::new($char1, Spacing::Joint);
|
||||
punct.set_span(span);
|
||||
@ -369,24 +457,27 @@ push_punct!(push_star push_star_spanned '*');
|
||||
push_punct!(push_sub push_sub_spanned '-');
|
||||
push_punct!(push_sub_eq push_sub_eq_spanned '-' '=');
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn push_underscore(tokens: &mut TokenStream) {
|
||||
push_underscore_spanned(tokens, Span::call_site());
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) {
|
||||
tokens.append(Ident::new("_", span));
|
||||
}
|
||||
|
||||
// Helper method for constructing identifiers from the `format_ident!` macro,
|
||||
// handling `r#` prefixes.
|
||||
#[doc(hidden)]
|
||||
pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
|
||||
let span = span.unwrap_or_else(Span::call_site);
|
||||
ident_maybe_raw(id, span)
|
||||
}
|
||||
|
||||
fn ident_maybe_raw(id: &str, span: Span) -> Ident {
|
||||
if id.starts_with("r#") {
|
||||
Ident::new_raw(&id[2..], span)
|
||||
if let Some(id) = id.strip_prefix("r#") {
|
||||
Ident::new_raw(id, span)
|
||||
} else {
|
||||
Ident::new(id, span)
|
||||
}
|
||||
@ -399,6 +490,7 @@ fn ident_maybe_raw(id: &str, span: Span) -> Ident {
|
||||
// `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within
|
||||
// `format_ident!`.
|
||||
#[derive(Copy, Clone)]
|
||||
#[doc(hidden)]
|
||||
pub struct IdentFragmentAdapter<T: IdentFragment>(pub T);
|
||||
|
||||
impl<T: IdentFragment> IdentFragmentAdapter<T> {
|
||||
|
@ -1,7 +1,9 @@
|
||||
use crate::ToTokens;
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
|
||||
pub trait Spanned {
|
||||
// Not public API other than via the syn crate. Use syn::spanned::Spanned.
|
||||
pub trait Spanned: private::Sealed {
|
||||
fn __span(&self) -> Span;
|
||||
}
|
||||
|
||||
@ -11,6 +13,12 @@ impl Spanned for Span {
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for DelimSpan {
|
||||
fn __span(&self) -> Span {
|
||||
self.join()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + ToTokens> Spanned for T {
|
||||
fn __span(&self) -> Span {
|
||||
join_spans(self.into_token_stream())
|
||||
@ -18,20 +26,8 @@ impl<T: ?Sized + ToTokens> Spanned for T {
|
||||
}
|
||||
|
||||
fn join_spans(tokens: TokenStream) -> Span {
|
||||
#[cfg(not(needs_invalid_span_workaround))]
|
||||
let mut iter = tokens.into_iter().map(|tt| tt.span());
|
||||
|
||||
#[cfg(needs_invalid_span_workaround)]
|
||||
let mut iter = tokens.into_iter().filter_map(|tt| {
|
||||
let span = tt.span();
|
||||
let debug = format!("{:?}", span);
|
||||
if debug.ends_with("bytes(0..0)") {
|
||||
None
|
||||
} else {
|
||||
Some(span)
|
||||
}
|
||||
});
|
||||
|
||||
let first = match iter.next() {
|
||||
Some(span) => span,
|
||||
None => return Span::call_site(),
|
||||
@ -41,3 +37,14 @@ fn join_spans(tokens: TokenStream) -> Span {
|
||||
.and_then(|last| first.join(last))
|
||||
.unwrap_or(first)
|
||||
}
|
||||
|
||||
mod private {
|
||||
use crate::ToTokens;
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::Span;
|
||||
|
||||
pub trait Sealed {}
|
||||
impl Sealed for Span {}
|
||||
impl Sealed for DelimSpan {}
|
||||
impl<T: ?Sized + ToTokens> Sealed for T {}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use super::TokenStreamExt;
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::rc::Rc;
|
||||
use core::iter;
|
||||
use proc_macro2::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Types that can be interpolated inside a `quote!` invocation.
|
||||
///
|
||||
|
@ -1,14 +1,17 @@
|
||||
#![allow(
|
||||
clippy::disallowed_names,
|
||||
clippy::let_underscore_untyped,
|
||||
clippy::shadow_unrelated,
|
||||
clippy::unseparated_literal_suffix,
|
||||
clippy::used_underscore_binding
|
||||
)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote, quote_spanned, TokenStreamExt};
|
||||
|
||||
struct X;
|
||||
@ -517,3 +520,30 @@ fn test_quote_raw_id() {
|
||||
let id = quote!(r#raw_id);
|
||||
assert_eq!(id.to_string(), "r#raw_id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_inference_for_span() {
|
||||
trait CallSite {
|
||||
fn get() -> Self;
|
||||
}
|
||||
|
||||
impl CallSite for Span {
|
||||
fn get() -> Self {
|
||||
Span::call_site()
|
||||
}
|
||||
}
|
||||
|
||||
let span = Span::call_site();
|
||||
let _ = quote_spanned!(span=> ...);
|
||||
|
||||
let delim_span = Group::new(Delimiter::Parenthesis, TokenStream::new()).delim_span();
|
||||
let _ = quote_spanned!(delim_span=> ...);
|
||||
|
||||
let inferred = CallSite::get();
|
||||
let _ = quote_spanned!(inferred=> ...);
|
||||
|
||||
if false {
|
||||
let proc_macro_span = proc_macro::Span::call_site();
|
||||
let _ = quote_spanned!(proc_macro_span.into()=> ...);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ error[E0308]: mismatched types
|
||||
8 | quote!(#(#nonrep #nonrep)*);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
|
||||
| expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
|
||||
| expected due to this
|
||||
| here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition`
|
||||
|
|
||||
= note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
@ -4,7 +4,8 @@ error[E0308]: mismatched types
|
||||
8 | quote!(#(#nonrep)*);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
|
||||
| expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
|
||||
| expected due to this
|
||||
| here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition`
|
||||
|
|
||||
= note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
@ -4,7 +4,7 @@ error[E0308]: mismatched types
|
||||
4 | quote!(#(a b),*);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
|
||||
| expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
|
||||
| expected due to this
|
||||
|
|
||||
= note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
@ -4,7 +4,7 @@ error[E0308]: mismatched types
|
||||
4 | quote!(#(a b)*);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
|
||||
| expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
|
||||
| expected due to this
|
||||
|
|
||||
= note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
@ -3,5 +3,5 @@ use std::net::Ipv4Addr;
|
||||
|
||||
fn main() {
|
||||
let ip = Ipv4Addr::LOCALHOST;
|
||||
_ = quote! { #ip };
|
||||
let _ = quote! { #ip };
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied
|
||||
--> tests/ui/not-quotable.rs:6:9
|
||||
--> tests/ui/not-quotable.rs:6:13
|
||||
|
|
||||
6 | _ = quote! { #ip };
|
||||
| ^^^^^^^^^^^^^^
|
||||
| |
|
||||
| the trait `ToTokens` is not implemented for `Ipv4Addr`
|
||||
| required by a bound introduced by this call
|
||||
6 | let _ = quote! { #ip };
|
||||
| ^^^^^^^^^^^^^^
|
||||
| |
|
||||
| the trait `ToTokens` is not implemented for `Ipv4Addr`
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the following other types implement trait `ToTokens`:
|
||||
&'a T
|
||||
&'a mut T
|
||||
Box<T>
|
||||
Cow<'a, T>
|
||||
Option<T>
|
||||
Rc<T>
|
||||
RepInterp<T>
|
||||
String
|
||||
and 23 others
|
||||
bool
|
||||
char
|
||||
isize
|
||||
i8
|
||||
i16
|
||||
i32
|
||||
i64
|
||||
i128
|
||||
and $N others
|
||||
= note: this error originates in the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
@ -4,5 +4,5 @@ struct Ipv4Addr;
|
||||
|
||||
fn main() {
|
||||
let ip = Ipv4Addr;
|
||||
_ = quote! { #(#ip)* };
|
||||
let _ = quote! { #(#ip)* };
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied
|
||||
--> tests/ui/not-repeatable.rs:7:9
|
||||
--> tests/ui/not-repeatable.rs:7:13
|
||||
|
|
||||
3 | struct Ipv4Addr;
|
||||
| ---------------
|
||||
@ -10,8 +10,8 @@ error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its
|
||||
| doesn't satisfy `Ipv4Addr: ext::RepIteratorExt`
|
||||
| doesn't satisfy `Ipv4Addr: ext::RepToTokensExt`
|
||||
...
|
||||
7 | _ = quote! { #(#ip)* };
|
||||
| ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
|
||||
7 | let _ = quote! { #(#ip)* };
|
||||
| ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`Ipv4Addr: Iterator`
|
||||
|
@ -1,8 +1,10 @@
|
||||
error[E0308]: mismatched types
|
||||
--> tests/ui/wrong-type-span.rs:6:20
|
||||
--> tests/ui/wrong-type-span.rs:6:5
|
||||
|
|
||||
6 | quote_spanned!(span=> #x);
|
||||
| ---------------^^^^------
|
||||
| | |
|
||||
| | expected struct `Span`, found `&str`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| expected `Span`, found `&str`
|
||||
| expected due to this
|
||||
|
|
||||
= note: this error originates in the macro `quote_spanned` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
Loading…
Reference in New Issue
Block a user