From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- third_party/rust/displaydoc/.cargo-checksum.json | 1 + third_party/rust/displaydoc/CHANGELOG.md | 50 +++ third_party/rust/displaydoc/Cargo.lock | 264 +++++++++++++ third_party/rust/displaydoc/Cargo.toml | 114 ++++++ third_party/rust/displaydoc/LICENSE-APACHE | 201 ++++++++++ third_party/rust/displaydoc/LICENSE-MIT | 23 ++ third_party/rust/displaydoc/README.md | 115 ++++++ third_party/rust/displaydoc/README.tpl | 23 ++ third_party/rust/displaydoc/examples/simple.rs | 36 ++ third_party/rust/displaydoc/src/attr.rs | 137 +++++++ third_party/rust/displaydoc/src/expand.rs | 410 +++++++++++++++++++++ third_party/rust/displaydoc/src/fmt.rs | 159 ++++++++ third_party/rust/displaydoc/src/lib.rs | 187 ++++++++++ third_party/rust/displaydoc/tests/compile_tests.rs | 29 ++ third_party/rust/displaydoc/tests/happy.rs | 152 ++++++++ .../rust/displaydoc/tests/no_std/enum_prefix.rs | 36 ++ .../displaydoc/tests/no_std/enum_prefix_missing.rs | 35 ++ .../tests/no_std/enum_prefix_missing.stderr | 22 ++ .../rust/displaydoc/tests/no_std/multi_line.rs | 37 ++ .../rust/displaydoc/tests/no_std/multi_line.stderr | 22 ++ .../displaydoc/tests/no_std/multi_line_allow.rs | 38 ++ third_party/rust/displaydoc/tests/no_std/with.rs | 32 ++ .../rust/displaydoc/tests/no_std/without.rs | 28 ++ .../rust/displaydoc/tests/no_std/without.stderr | 22 ++ third_party/rust/displaydoc/tests/num_in_field.rs | 22 ++ .../rust/displaydoc/tests/std/enum_prefix.rs | 36 ++ .../displaydoc/tests/std/enum_prefix_missing.rs | 35 ++ .../tests/std/enum_prefix_missing.stderr | 22 ++ .../rust/displaydoc/tests/std/multi_line.rs | 1 + .../rust/displaydoc/tests/std/multi_line.stderr | 22 ++ .../rust/displaydoc/tests/std/multi_line_allow.rs | 38 ++ third_party/rust/displaydoc/tests/std/multiple.rs | 38 ++ third_party/rust/displaydoc/tests/std/without.rs | 1 + .../rust/displaydoc/tests/std/without.stderr | 22 ++ third_party/rust/displaydoc/tests/variantless.rs | 6 + third_party/rust/displaydoc/update-readme.sh | 5 + 36 files changed, 2421 insertions(+) create mode 100644 third_party/rust/displaydoc/.cargo-checksum.json create mode 100644 third_party/rust/displaydoc/CHANGELOG.md create mode 100644 third_party/rust/displaydoc/Cargo.lock create mode 100644 third_party/rust/displaydoc/Cargo.toml create mode 100644 third_party/rust/displaydoc/LICENSE-APACHE create mode 100644 third_party/rust/displaydoc/LICENSE-MIT create mode 100644 third_party/rust/displaydoc/README.md create mode 100644 third_party/rust/displaydoc/README.tpl create mode 100644 third_party/rust/displaydoc/examples/simple.rs create mode 100644 third_party/rust/displaydoc/src/attr.rs create mode 100644 third_party/rust/displaydoc/src/expand.rs create mode 100644 third_party/rust/displaydoc/src/fmt.rs create mode 100644 third_party/rust/displaydoc/src/lib.rs create mode 100644 third_party/rust/displaydoc/tests/compile_tests.rs create mode 100644 third_party/rust/displaydoc/tests/happy.rs create mode 100644 third_party/rust/displaydoc/tests/no_std/enum_prefix.rs create mode 100644 third_party/rust/displaydoc/tests/no_std/enum_prefix_missing.rs create mode 100644 third_party/rust/displaydoc/tests/no_std/enum_prefix_missing.stderr create mode 100644 third_party/rust/displaydoc/tests/no_std/multi_line.rs create mode 100644 third_party/rust/displaydoc/tests/no_std/multi_line.stderr create mode 100644 third_party/rust/displaydoc/tests/no_std/multi_line_allow.rs create mode 100644 third_party/rust/displaydoc/tests/no_std/with.rs create mode 100644 third_party/rust/displaydoc/tests/no_std/without.rs create mode 100644 third_party/rust/displaydoc/tests/no_std/without.stderr create mode 100644 third_party/rust/displaydoc/tests/num_in_field.rs create mode 100644 third_party/rust/displaydoc/tests/std/enum_prefix.rs create mode 100644 third_party/rust/displaydoc/tests/std/enum_prefix_missing.rs create mode 100644 third_party/rust/displaydoc/tests/std/enum_prefix_missing.stderr create mode 100644 third_party/rust/displaydoc/tests/std/multi_line.rs create mode 100644 third_party/rust/displaydoc/tests/std/multi_line.stderr create mode 100644 third_party/rust/displaydoc/tests/std/multi_line_allow.rs create mode 100644 third_party/rust/displaydoc/tests/std/multiple.rs create mode 100644 third_party/rust/displaydoc/tests/std/without.rs create mode 100644 third_party/rust/displaydoc/tests/std/without.stderr create mode 100644 third_party/rust/displaydoc/tests/variantless.rs create mode 100644 third_party/rust/displaydoc/update-readme.sh (limited to 'third_party/rust/displaydoc') diff --git a/third_party/rust/displaydoc/.cargo-checksum.json b/third_party/rust/displaydoc/.cargo-checksum.json new file mode 100644 index 0000000000..a1f0964fea --- /dev/null +++ b/third_party/rust/displaydoc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"ac4b11a820a3251453aa5eed99f2e34758281c4794234376532ab1686fc4092e","Cargo.lock":"764c7f380095ccd0c22e10470ed71a1c38899a502943f70baf1b0641f30d61a9","Cargo.toml":"6eac127183532630ea388e11f07a33c1a8537175d4f1269290eacd0b5010b41d","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"60628c334f71eba035e7ba4d5ba4df966c9de953260f9d1f28b0141ad06a07a8","README.tpl":"a8b023f5f39b795ef553c2b75551d6ad42db6597362c8909101f4bc8c8994bcc","examples/simple.rs":"dd37ed49175e86124cf58aba6fdcf4b4c2adc13a2414d4a2ba31cfab21638415","src/attr.rs":"1aeaf46ea739f63bf7eca5a575ca4345ff325c16e959fb59b5671b9a338d5ddc","src/expand.rs":"a0e6c062e00b9e68a0811a7d4d739e7572cd4a5dd962dc3519c0c8bfa1e84d8b","src/fmt.rs":"9734d3b51206f73ca8d9a513bee46d72215ff877797500887d43bc64af639c37","src/lib.rs":"de304b1de4a60700c0a031c6bd568da7ed24f5169edcfc16b7009e9e9494daed","tests/compile_tests.rs":"6cd211e343c42873a287b02581bd342b09ae508022fc82022714ebdc625935aa","tests/happy.rs":"ebd93ca6cea7c2ab77c59f990335ca34714e19365fddd40a6eca5f180bf7cb75","tests/no_std/enum_prefix.rs":"fd2a565ceddffe0433f83c6d0c9b15bc1db96fbf952f222ff04bc0dc1ea34d41","tests/no_std/enum_prefix_missing.rs":"4ed8aaef3d9274b377837b90fb9a80315df502b1c569de3213b7a2e7fa613322","tests/no_std/enum_prefix_missing.stderr":"add42a5efa90502483b2fcd0152289b62c1d5b790faf9e46d8d930e4e474b781","tests/no_std/multi_line.rs":"6ce3c1554f8bffa409f42a12517f2ef79e884ce22c79d2514455263a9254ae10","tests/no_std/multi_line.stderr":"ee076d8d02e187fe9651429a755599752b82be5910aa19e9312cf678779b2c03","tests/no_std/multi_line_allow.rs":"ef1f5a6b551e81ec6405626c939d81fe6db279bd5c2c66a2c5cc6e30a318cdbe","tests/no_std/with.rs":"3607edede6069527e792e000bfe0062f539ec342048aa2b2322556f6d6462bcc","tests/no_std/without.rs":"518cd04d73bd950e70f2d515d2cdae48b0f409fbefa2132b4d9a1b97e9c0a406","tests/no_std/without.stderr":"b3ade743ec5597f433cfb6ac378db239207d349bc99b21d9f75399a8df6ec4ae","tests/num_in_field.rs":"cd83f7d79ae065a97dcb53b2e92dc57e2f269e12433d1cd4644cb0ec6b2a4d0f","tests/std/enum_prefix.rs":"fd2a565ceddffe0433f83c6d0c9b15bc1db96fbf952f222ff04bc0dc1ea34d41","tests/std/enum_prefix_missing.rs":"4ed8aaef3d9274b377837b90fb9a80315df502b1c569de3213b7a2e7fa613322","tests/std/enum_prefix_missing.stderr":"ac4b4ac371b6e134bc1781854e3bc4df2afecdb29182a9c8328ee1d37c0fef3d","tests/std/multi_line.rs":"86726db8140e5bf9f690ac3f2d607a7a9d74b9b79fae7945480cff62cf3e8700","tests/std/multi_line.stderr":"ed9de88820f5a0cacdf26f955790b1c433c784a432cf723a963211011e1ccd7b","tests/std/multi_line_allow.rs":"ef1f5a6b551e81ec6405626c939d81fe6db279bd5c2c66a2c5cc6e30a318cdbe","tests/std/multiple.rs":"a4194da6b5bef919bb0107ddb91c548421ef9812d69894bef5e5b6f316af8eee","tests/std/without.rs":"80a59e296ee3c205960b9e8dd18c1d2b210d8fd096e89652d482b963010f340b","tests/std/without.stderr":"fc699e263f1148b1db7f5ea63f0d952c74f997c8155578ff4efaf1cd9f8db8d4","tests/variantless.rs":"84495a36014bdc090b8e5d97442bcfd3229d07f0d40579e450e71596ef9a7b50","update-readme.sh":"794668cc4eb58da01049effb0370db4799e7a70a9db777edfba83d92c33e821a"},"package":"487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"} \ No newline at end of file diff --git a/third_party/rust/displaydoc/CHANGELOG.md b/third_party/rust/displaydoc/CHANGELOG.md new file mode 100644 index 0000000000..4513b4ad47 --- /dev/null +++ b/third_party/rust/displaydoc/CHANGELOG.md @@ -0,0 +1,50 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + + +## [Unreleased] - ReleaseDate + +# [0.2.4] - 2022-05-02 + +## Added +- Updated `syn` dependency to 2.0 +- Support for empty enums +- Implicitly require fmt::Display on all type parameters unless overridden + +## Changed +- Bumped MSRV to 1.56 + +# [0.2.3] - 2021-07-16 +## Added +- Added `#[displaydoc("..")]` attribute for overriding a doc comment + +# [0.2.2] - 2021-07-01 +## Added +- Added prefix feature to use the doc comment from an enum and prepend it + before the error message from each variant. + +# [0.2.1] - 2021-03-26 +## Added +- Added opt in support for ignoring extra doc attributes + +# [0.2.0] - 2021-03-16 +## Changed + +- (BREAKING) disallow multiple `doc` attributes in display impl + [https://github.com/yaahc/displaydoc/pull/22]. Allowing and ignoring extra + doc attributes made it too easy to accidentally create a broken display + implementation with missing context without realizing it, this change turns + that into a hard error and directs users towards block comments if multiple + lines are needed. + + +[Unreleased]: https://github.com/yaahc/displaydoc/compare/v0.2.4...HEAD +[0.2.4]: https://github.com/yaahc/displaydoc/compare/v0.2.3...v0.2.4 +[0.2.3]: https://github.com/yaahc/displaydoc/compare/v0.2.2...v0.2.3 +[0.2.2]: https://github.com/yaahc/displaydoc/compare/v0.2.1...v0.2.2 +[0.2.1]: https://github.com/yaahc/displaydoc/compare/v0.2.0...v0.2.1 +[0.2.0]: https://github.com/yaahc/displaydoc/releases/tag/v0.2.0 diff --git a/third_party/rust/displaydoc/Cargo.lock b/third_party/rust/displaydoc/Cargo.lock new file mode 100644 index 0000000000..30580d9404 --- /dev/null +++ b/third_party/rust/displaydoc/Cargo.lock @@ -0,0 +1,264 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "basic-toml" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1" +dependencies = [ + "serde", +] + +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + +[[package]] +name = "displaydoc" +version = "0.2.4" +dependencies = [ + "libc", + "pretty_assertions", + "proc-macro2", + "quote", + "rustversion", + "static_assertions", + "syn 2.0.15", + "thiserror", + "trybuild", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "libc" +version = "0.2.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "pretty_assertions" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" +dependencies = [ + "ansi_term", + "ctor", + "difference", + "output_vt100", +] + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "serde" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" + +[[package]] +name = "serde_derive" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "trybuild" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501dbdbb99861e4ab6b60eb6a7493956a9defb644fd034bc4a5ef27c693c8a3a" +dependencies = [ + "basic-toml", + "glob", + "once_cell", + "serde", + "serde_derive", + "serde_json", + "termcolor", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/rust/displaydoc/Cargo.toml b/third_party/rust/displaydoc/Cargo.toml new file mode 100644 index 0000000000..1affcca6b7 --- /dev/null +++ b/third_party/rust/displaydoc/Cargo.toml @@ -0,0 +1,114 @@ +# 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" +name = "displaydoc" +version = "0.2.4" +authors = ["Jane Lusby "] +description = """ +A derive macro for implementing the display Trait via a doc comment and string interpolation +""" +homepage = "https://github.com/yaahc/displaydoc" +documentation = "https://docs.rs/displaydoc" +readme = "README.md" +keywords = [ + "display", + "derive", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/yaahc/displaydoc" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[package.metadata.release] +no-dev-version = true +pre-release-hook = ["./update-readme.sh"] + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "Unreleased" +replace = "{{version}}" + +[[package.metadata.release.pre-release-replacements]] +file = "src/lib.rs" +search = '#!\[doc\(html_root_url.*' +replace = "#![doc(html_root_url = \"https://docs.rs/{{crate_name}}/{{version}}\")]" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "ReleaseDate" +replace = "{{date}}" + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + + +# [Unreleased] - ReleaseDate""" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = '\.\.\.HEAD' +replace = "...{{tag_name}}" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +[Unreleased]: https://github.com/yaahc/{{crate_name}}/compare/{{tag_name}}...HEAD""" +exactly = 1 + +[lib] +path = "src/lib.rs" +proc-macro = true + +[dependencies.proc-macro2] +version = "1.0" + +[dependencies.quote] +version = "1.0" + +[dependencies.syn] +version = "2.0" + +[dev-dependencies.libc] +version = "0.2" +default-features = false + +[dev-dependencies.pretty_assertions] +version = "0.6.1" + +[dev-dependencies.rustversion] +version = "1.0.0" + +[dev-dependencies.static_assertions] +version = "1.1" + +[dev-dependencies.thiserror] +version = "1.0.24" + +[dev-dependencies.trybuild] +version = "1.0" + +[features] +default = ["std"] +std = [] diff --git a/third_party/rust/displaydoc/LICENSE-APACHE b/third_party/rust/displaydoc/LICENSE-APACHE new file mode 100644 index 0000000000..f47c941141 --- /dev/null +++ b/third_party/rust/displaydoc/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + 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. diff --git a/third_party/rust/displaydoc/LICENSE-MIT b/third_party/rust/displaydoc/LICENSE-MIT new file mode 100644 index 0000000000..458723b374 --- /dev/null +++ b/third_party/rust/displaydoc/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/displaydoc/README.md b/third_party/rust/displaydoc/README.md new file mode 100644 index 0000000000..b8fa09157d --- /dev/null +++ b/third_party/rust/displaydoc/README.md @@ -0,0 +1,115 @@ +derive(Display) /// `From` +=============== + +[![Latest Version](https://img.shields.io/crates/v/displaydoc.svg)](https://crates.io/crates/displaydoc) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/displaydoc) + +This library provides a convenient derive macro for the standard library's +[`core::fmt::Display`] trait. + +[`core::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html + +```toml +[dependencies] +displaydoc = "0.2" +``` + +*Compiler support: requires rustc 1.56+* + +
+ +### Example + +*Demonstration alongside the [`Error`][std::error::Error] derive macro from [`thiserror`](https://docs.rs/thiserror/1.0.25/thiserror/index.html), +to propagate source locations from [`io::Error`][std::io::Error] with the `#[source]` attribute:* +```rust +use std::io; +use displaydoc::Display; +use thiserror::Error; + +#[derive(Display, Error, Debug)] +pub enum DataStoreError { + /// data store disconnected + Disconnect(#[source] io::Error), + /// the data for key `{0}` is not available + Redaction(String), + /// invalid header (expected {expected:?}, found {found:?}) + InvalidHeader { + expected: String, + found: String, + }, + /// unknown data store error + Unknown, +} + +let error = DataStoreError::Redaction("CLASSIFIED CONTENT".to_string()); +assert!("the data for key `CLASSIFIED CONTENT` is not available" == &format!("{}", error)); +``` +*Note that although [`io::Error`][std::io::Error] implements `Display`, we do not add it to the +generated message for `DataStoreError::Disconnect`, since it is already made available via +`#[source]`. See further context on avoiding duplication in error reports at the rust blog +[here](https://github.com/yaahc/blog.rust-lang.org/blob/master/posts/inside-rust/2021-05-15-What-the-error-handling-project-group-is-working-towards.md#duplicate-information-issue).* + +
+ +### Details + +- A `fmt::Display` impl is generated for your enum if you provide + a docstring comment on each variant as shown above in the example. The + `Display` derive macro supports a shorthand for interpolating fields from + the error: + - `/// {var}` ⟶ `write!("{}", self.var)` + - `/// {0}` ⟶ `write!("{}", self.0)` + - `/// {var:?}` ⟶ `write!("{:?}", self.var)` + - `/// {0:?}` ⟶ `write!("{:?}", self.0)` +- This also works with structs and [generic types][crate::Display#generic-type-parameters]: +```rust +/// oh no, an error: {0} +#[derive(Display)] +pub struct Error(pub E); + +let error: Error<&str> = Error("muahaha i am an error"); +assert!("oh no, an error: muahaha i am an error" == &format!("{}", error)); +``` + +- Two optional attributes can be added to your types next to the derive: + + - `#[ignore_extra_doc_attributes]` makes the macro ignore any doc + comment attributes (or `///` lines) after the first. Multi-line + comments using `///` are otherwise treated as an error, so use this + attribute or consider switching to block doc comments (`/** */`). + + - `#[prefix_enum_doc_attributes]` combines the doc comment message on + your enum itself with the messages for each variant, in the format + “enum: variant”. When added to an enum, the doc comment on the enum + becomes mandatory. When added to any other type, it has no effect. + +- In case you want to have an independent doc comment, the + `#[displaydoc("...")` atrribute may be used on the variant or struct to + override it. + +
+ +### FAQ + +1. **Is this crate `no_std` compatible?** + * Yes! This crate implements the [`core::fmt::Display`] trait, not the [`std::fmt::Display`] trait, so it should work in `std` and `no_std` environments. Just add `default-features = false`. + +2. **Does this crate work with `Path` and `PathBuf` via the `Display` trait?** + * Yuuup. This crate uses @dtolnay's [autoref specialization technique](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md) to add a special trait for types to get the display impl. It then specializes for `Path` and `PathBuf`, and when either of these types are found, it calls `self.display()` to get a `std::path::Display<'_>` type which can be used with the `Display` format specifier! + + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/rust/displaydoc/README.tpl b/third_party/rust/displaydoc/README.tpl new file mode 100644 index 0000000000..b131fb8aa4 --- /dev/null +++ b/third_party/rust/displaydoc/README.tpl @@ -0,0 +1,23 @@ +derive(Display) /// `From` +=============== + +[![Latest Version](https://img.shields.io/crates/v/displaydoc.svg)](https://crates.io/crates/displaydoc) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/displaydoc) + +{{readme}} + + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/rust/displaydoc/examples/simple.rs b/third_party/rust/displaydoc/examples/simple.rs new file mode 100644 index 0000000000..1f9fd11983 --- /dev/null +++ b/third_party/rust/displaydoc/examples/simple.rs @@ -0,0 +1,36 @@ +use displaydoc::Display; + +#[derive(Debug, Display)] +pub enum DataStoreError { + /// data store disconnected + Disconnect, + /// the data for key `{0}` is not available + Redaction(String), + /// invalid header (expected {expected:?}, found {found:?}) + InvalidHeader { expected: String, found: String }, + /// unknown data store error + Unknown, +} + +fn main() { + let disconnect = DataStoreError::Disconnect; + println!( + "Enum value `Disconnect` should be printed as:\n\t{}", + disconnect + ); + + let redaction = DataStoreError::Redaction(String::from("Dummy")); + println!( + "Enum value `Redaction` should be printed as:\n\t{}", + redaction + ); + + let invalid_header = DataStoreError::InvalidHeader { + expected: String::from("https"), + found: String::from("http"), + }; + println!( + "Enum value `InvalidHeader` should be printed as:\n\t{}", + invalid_header + ); +} diff --git a/third_party/rust/displaydoc/src/attr.rs b/third_party/rust/displaydoc/src/attr.rs new file mode 100644 index 0000000000..a965d04deb --- /dev/null +++ b/third_party/rust/displaydoc/src/attr.rs @@ -0,0 +1,137 @@ +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::{Attribute, LitStr, Meta, Result}; + +#[derive(Clone)] +pub(crate) struct Display { + pub(crate) fmt: LitStr, + pub(crate) args: TokenStream, +} + +pub(crate) struct VariantDisplay { + pub(crate) r#enum: Option, + pub(crate) variant: Display, +} + +impl ToTokens for Display { + fn to_tokens(&self, tokens: &mut TokenStream) { + let fmt = &self.fmt; + let args = &self.args; + tokens.extend(quote! { + write!(formatter, #fmt #args) + }); + } +} + +impl ToTokens for VariantDisplay { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(ref r#enum) = self.r#enum { + r#enum.to_tokens(tokens); + tokens.extend(quote! { ?; write!(formatter, ": ")?; }); + } + self.variant.to_tokens(tokens); + } +} + +pub(crate) struct AttrsHelper { + ignore_extra_doc_attributes: bool, + prefix_enum_doc_attributes: bool, +} + +impl AttrsHelper { + pub(crate) fn new(attrs: &[Attribute]) -> Self { + let ignore_extra_doc_attributes = attrs + .iter() + .any(|attr| attr.path().is_ident("ignore_extra_doc_attributes")); + let prefix_enum_doc_attributes = attrs + .iter() + .any(|attr| attr.path().is_ident("prefix_enum_doc_attributes")); + + Self { + ignore_extra_doc_attributes, + prefix_enum_doc_attributes, + } + } + + pub(crate) fn display(&self, attrs: &[Attribute]) -> Result> { + let displaydoc_attr = attrs.iter().find(|attr| attr.path().is_ident("displaydoc")); + + if let Some(displaydoc_attr) = displaydoc_attr { + let lit = displaydoc_attr + .parse_args() + .expect("#[displaydoc(\"foo\")] must contain string arguments"); + let mut display = Display { + fmt: lit, + args: TokenStream::new(), + }; + + display.expand_shorthand(); + return Ok(Some(display)); + } + + let num_doc_attrs = attrs + .iter() + .filter(|attr| attr.path().is_ident("doc")) + .count(); + + if !self.ignore_extra_doc_attributes && num_doc_attrs > 1 { + panic!("Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive."); + } + + for attr in attrs { + if attr.path().is_ident("doc") { + let lit = match &attr.meta { + Meta::NameValue(syn::MetaNameValue { + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }), + .. + }) => lit, + _ => unimplemented!(), + }; + + // Make an attempt at cleaning up multiline doc comments. + let doc_str = lit + .value() + .lines() + .map(|line| line.trim().trim_start_matches('*').trim()) + .collect::>() + .join("\n"); + + let lit = LitStr::new(doc_str.trim(), lit.span()); + + let mut display = Display { + fmt: lit, + args: TokenStream::new(), + }; + + display.expand_shorthand(); + return Ok(Some(display)); + } + } + + Ok(None) + } + + pub(crate) fn display_with_input( + &self, + r#enum: &[Attribute], + variant: &[Attribute], + ) -> Result> { + let r#enum = if self.prefix_enum_doc_attributes { + let result = self + .display(r#enum)? + .expect("Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself."); + + Some(result) + } else { + None + }; + + Ok(self + .display(variant)? + .map(|variant| VariantDisplay { r#enum, variant })) + } +} diff --git a/third_party/rust/displaydoc/src/expand.rs b/third_party/rust/displaydoc/src/expand.rs new file mode 100644 index 0000000000..8a84390be2 --- /dev/null +++ b/third_party/rust/displaydoc/src/expand.rs @@ -0,0 +1,410 @@ +use super::attr::AttrsHelper; +use proc_macro2::{Span, TokenStream}; +use quote::{format_ident, quote}; +use syn::{ + punctuated::Punctuated, + token::{Colon, Comma, PathSep, Plus, Where}, + Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Path, PathArguments, + PathSegment, PredicateType, Result, TraitBound, TraitBoundModifier, Type, TypeParam, + TypeParamBound, TypePath, WhereClause, WherePredicate, +}; + +use std::collections::HashMap; + +pub(crate) fn derive(input: &DeriveInput) -> Result { + let impls = match &input.data { + Data::Struct(data) => impl_struct(input, data), + Data::Enum(data) => impl_enum(input, data), + Data::Union(_) => Err(Error::new_spanned(input, "Unions are not supported")), + }?; + + let helpers = specialization(); + let dummy_const = format_ident!("_DERIVE_Display_FOR_{}", input.ident); + Ok(quote! { + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const #dummy_const: () = { + #helpers + #impls + }; + }) +} + +#[cfg(feature = "std")] +fn specialization() -> TokenStream { + quote! { + trait DisplayToDisplayDoc { + fn __displaydoc_display(&self) -> Self; + } + + impl DisplayToDisplayDoc for &T { + fn __displaydoc_display(&self) -> Self { + self + } + } + + // If the `std` feature gets enabled we want to ensure that any crate + // using displaydoc can still reference the std crate, which is already + // being compiled in by whoever enabled the `std` feature in + // `displaydoc`, even if the crates using displaydoc are no_std. + extern crate std; + + trait PathToDisplayDoc { + fn __displaydoc_display(&self) -> std::path::Display<'_>; + } + + impl PathToDisplayDoc for std::path::Path { + fn __displaydoc_display(&self) -> std::path::Display<'_> { + self.display() + } + } + + impl PathToDisplayDoc for std::path::PathBuf { + fn __displaydoc_display(&self) -> std::path::Display<'_> { + self.display() + } + } + } +} + +#[cfg(not(feature = "std"))] +fn specialization() -> TokenStream { + quote! {} +} + +fn impl_struct(input: &DeriveInput, data: &DataStruct) -> Result { + let ty = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let where_clause = generate_where_clause(&input.generics, where_clause); + + let helper = AttrsHelper::new(&input.attrs); + + let display = helper.display(&input.attrs)?.map(|display| { + let pat = match &data.fields { + Fields::Named(fields) => { + let var = fields.named.iter().map(|field| &field.ident); + quote!(Self { #(#var),* }) + } + Fields::Unnamed(fields) => { + let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i)); + quote!(Self(#(#var),*)) + } + Fields::Unit => quote!(_), + }; + quote! { + impl #impl_generics core::fmt::Display for #ty #ty_generics #where_clause { + fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + // NB: This destructures the fields of `self` into named variables (for unnamed + // fields, it uses _0, _1, etc as above). The `#[allow(unused_variables)]` + // section means it doesn't have to parse the individual field references out of + // the docstring. + #[allow(unused_variables)] + let #pat = self; + #display + } + } + } + }); + + Ok(quote! { #display }) +} + +/// Create a `where` predicate for `ident`, without any [bound][TypeParamBound]s yet. +fn new_empty_where_type_predicate(ident: Ident) -> PredicateType { + let mut path_segments = Punctuated::::new(); + path_segments.push_value(PathSegment { + ident, + arguments: PathArguments::None, + }); + PredicateType { + lifetimes: None, + bounded_ty: Type::Path(TypePath { + qself: None, + path: Path { + leading_colon: None, + segments: path_segments, + }, + }), + colon_token: Colon { + spans: [Span::call_site()], + }, + bounds: Punctuated::::new(), + } +} + +/// Create a `where` clause that we can add [WherePredicate]s to. +fn new_empty_where_clause() -> WhereClause { + WhereClause { + where_token: Where { + span: Span::call_site(), + }, + predicates: Punctuated::::new(), + } +} + +enum UseGlobalPrefix { + LeadingColon, + #[allow(dead_code)] + NoLeadingColon, +} + +/// Create a path with segments composed of [Idents] *without* any [PathArguments]. +fn join_paths(name_segments: &[&str], use_global_prefix: UseGlobalPrefix) -> Path { + let mut segments = Punctuated::::new(); + assert!(!name_segments.is_empty()); + segments.push_value(PathSegment { + ident: Ident::new(name_segments[0], Span::call_site()), + arguments: PathArguments::None, + }); + for name in name_segments[1..].iter() { + segments.push_punct(PathSep { + spans: [Span::call_site(), Span::mixed_site()], + }); + segments.push_value(PathSegment { + ident: Ident::new(name, Span::call_site()), + arguments: PathArguments::None, + }); + } + Path { + leading_colon: match use_global_prefix { + UseGlobalPrefix::LeadingColon => Some(PathSep { + spans: [Span::call_site(), Span::mixed_site()], + }), + UseGlobalPrefix::NoLeadingColon => None, + }, + segments, + } +} + +/// Push `new_type_predicate` onto the end of `where_clause`. +fn append_where_clause_type_predicate( + where_clause: &mut WhereClause, + new_type_predicate: PredicateType, +) { + // Push a comma at the end if there are already any `where` predicates. + if !where_clause.predicates.is_empty() { + where_clause.predicates.push_punct(Comma { + spans: [Span::call_site()], + }); + } + where_clause + .predicates + .push_value(WherePredicate::Type(new_type_predicate)); +} + +/// Add a requirement for [core::fmt::Display] to a `where` predicate for some type. +fn add_display_constraint_to_type_predicate( + predicate_that_needs_a_display_impl: &mut PredicateType, +) { + // Create a `Path` of `::core::fmt::Display`. + let display_path = join_paths(&["core", "fmt", "Display"], UseGlobalPrefix::LeadingColon); + + let display_bound = TypeParamBound::Trait(TraitBound { + paren_token: None, + modifier: TraitBoundModifier::None, + lifetimes: None, + path: display_path, + }); + if !predicate_that_needs_a_display_impl.bounds.is_empty() { + predicate_that_needs_a_display_impl.bounds.push_punct(Plus { + spans: [Span::call_site()], + }); + } + + predicate_that_needs_a_display_impl + .bounds + .push_value(display_bound); +} + +/// Map each declared generic type parameter to the set of all trait boundaries declared on it. +/// +/// These boundaries may come from the declaration site: +/// pub enum E { ... } +/// or a `where` clause after the parameter declarations: +/// pub enum E where T: MyTrait { ... } +/// This method will return the boundaries from both of those cases. +fn extract_trait_constraints_from_source( + where_clause: &WhereClause, + type_params: &[&TypeParam], +) -> HashMap> { + // Add trait bounds provided at the declaration site of type parameters for the struct/enum. + let mut param_constraint_mapping: HashMap> = type_params + .iter() + .map(|type_param| { + let trait_bounds: Vec = type_param + .bounds + .iter() + .flat_map(|bound| match bound { + TypeParamBound::Trait(trait_bound) => Some(trait_bound), + _ => None, + }) + .cloned() + .collect(); + (type_param.ident.clone(), trait_bounds) + }) + .collect(); + + // Add trait bounds from `where` clauses, which may be type parameters or types containing + // those parameters. + for predicate in where_clause.predicates.iter() { + // We only care about type and not lifetime constraints here. + if let WherePredicate::Type(ref pred_ty) = predicate { + let ident = match &pred_ty.bounded_ty { + Type::Path(TypePath { path, qself: None }) => match path.get_ident() { + None => continue, + Some(ident) => ident, + }, + _ => continue, + }; + // We ignore any type constraints that aren't direct references to type + // parameters of the current enum of struct definition. No types can be + // constrained in a `where` clause unless they are a type parameter or a generic + // type instantiated with one of the type parameters, so by only allowing single + // identifiers, we can be sure that the constrained type is a type parameter + // that is contained in `param_constraint_mapping`. + if let Some((_, ref mut known_bounds)) = param_constraint_mapping + .iter_mut() + .find(|(id, _)| *id == ident) + { + for bound in pred_ty.bounds.iter() { + // We only care about trait bounds here. + if let TypeParamBound::Trait(ref bound) = bound { + known_bounds.push(bound.clone()); + } + } + } + } + } + + param_constraint_mapping +} + +/// Hygienically add `where _: Display` to the set of [TypeParamBound]s for `ident`, creating such +/// a set if necessary. +fn ensure_display_in_where_clause_for_type(where_clause: &mut WhereClause, ident: Ident) { + for pred_ty in where_clause + .predicates + .iter_mut() + // Find the `where` predicate constraining the current type param, if it exists. + .flat_map(|predicate| match predicate { + WherePredicate::Type(pred_ty) => Some(pred_ty), + // We're looking through type constraints, not lifetime constraints. + _ => None, + }) + { + // Do a complicated destructuring in order to check if the type being constrained in this + // `where` clause is the type we're looking for, so we can use the mutable reference to + // `pred_ty` if so. + let matches_desired_type = matches!( + &pred_ty.bounded_ty, + Type::Path(TypePath { path, .. }) if Some(&ident) == path.get_ident()); + if matches_desired_type { + add_display_constraint_to_type_predicate(pred_ty); + return; + } + } + + // If there is no `where` predicate for the current type param, we will construct one. + let mut new_type_predicate = new_empty_where_type_predicate(ident); + add_display_constraint_to_type_predicate(&mut new_type_predicate); + append_where_clause_type_predicate(where_clause, new_type_predicate); +} + +/// For all declared type parameters, add a [core::fmt::Display] constraint, unless the type +/// parameter already has any type constraint. +fn ensure_where_clause_has_display_for_all_unconstrained_members( + where_clause: &mut WhereClause, + type_params: &[&TypeParam], +) { + let param_constraint_mapping = extract_trait_constraints_from_source(where_clause, type_params); + + for (ident, known_bounds) in param_constraint_mapping.into_iter() { + // If the type parameter has any constraints already, we don't want to touch it, to avoid + // breaking use cases where a type parameter only needs to impl `Debug`, for example. + if known_bounds.is_empty() { + ensure_display_in_where_clause_for_type(where_clause, ident); + } + } +} + +/// Generate a `where` clause that ensures all generic type parameters `impl` +/// [core::fmt::Display] unless already constrained. +/// +/// This approach allows struct/enum definitions deriving [crate::Display] to avoid hardcoding +/// a [core::fmt::Display] constraint into every type parameter. +/// +/// If the type parameter isn't already constrained, we add a `where _: Display` clause to our +/// display implementation to expect to be able to format every enum case or struct member. +/// +/// In fact, we would preferably only require `where _: Display` or `where _: Debug` where the +/// format string actually requires it. However, while [`std::fmt` defines a formal syntax for +/// `format!()`][format syntax], it *doesn't* expose the actual logic to parse the format string, +/// which appears to live in [`rustc_parse_format`]. While we use the [`syn`] crate to parse rust +/// syntax, it also doesn't currently provide any method to introspect a `format!()` string. It +/// would be nice to contribute this upstream in [`syn`]. +/// +/// [format syntax]: std::fmt#syntax +/// [`rustc_parse_format`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse_format/index.html +fn generate_where_clause(generics: &Generics, where_clause: Option<&WhereClause>) -> WhereClause { + let mut where_clause = where_clause.cloned().unwrap_or_else(new_empty_where_clause); + let type_params: Vec<&TypeParam> = generics.type_params().collect(); + ensure_where_clause_has_display_for_all_unconstrained_members(&mut where_clause, &type_params); + where_clause +} + +fn impl_enum(input: &DeriveInput, data: &DataEnum) -> Result { + let ty = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let where_clause = generate_where_clause(&input.generics, where_clause); + + let helper = AttrsHelper::new(&input.attrs); + + let displays = data + .variants + .iter() + .map(|variant| helper.display_with_input(&input.attrs, &variant.attrs)) + .collect::>>()?; + + if data.variants.is_empty() { + Ok(quote! { + impl #impl_generics core::fmt::Display for #ty #ty_generics #where_clause { + fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + unreachable!("empty enums cannot be instantiated and thus cannot be printed") + } + } + }) + } else if displays.iter().any(Option::is_some) { + let arms = data + .variants + .iter() + .zip(displays) + .map(|(variant, display)| { + let display = + display.ok_or_else(|| Error::new_spanned(variant, "missing doc comment"))?; + let ident = &variant.ident; + Ok(match &variant.fields { + Fields::Named(fields) => { + let var = fields.named.iter().map(|field| &field.ident); + quote!(Self::#ident { #(#var),* } => { #display }) + } + Fields::Unnamed(fields) => { + let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i)); + quote!(Self::#ident(#(#var),*) => { #display }) + } + Fields::Unit => quote!(Self::#ident => { #display }), + }) + }) + .collect::>>()?; + Ok(quote! { + impl #impl_generics core::fmt::Display for #ty #ty_generics #where_clause { + fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + #[allow(unused_variables)] + match self { + #(#arms,)* + } + } + } + }) + } else { + Err(Error::new_spanned(input, "Missing doc comments")) + } +} diff --git a/third_party/rust/displaydoc/src/fmt.rs b/third_party/rust/displaydoc/src/fmt.rs new file mode 100644 index 0000000000..3334a82ff2 --- /dev/null +++ b/third_party/rust/displaydoc/src/fmt.rs @@ -0,0 +1,159 @@ +use crate::attr::Display; +use proc_macro2::TokenStream; +use quote::quote_spanned; +use syn::{Ident, LitStr}; + +macro_rules! peek_next { + ($read:ident) => { + match $read.chars().next() { + Some(next) => next, + None => return, + } + }; +} + +impl Display { + // Transform `"error {var}"` to `"error {}", var`. + pub(crate) fn expand_shorthand(&mut self) { + let span = self.fmt.span(); + let fmt = self.fmt.value(); + let mut read = fmt.as_str(); + let mut out = String::new(); + let mut args = TokenStream::new(); + + while let Some(brace) = read.find('{') { + out += &read[..=brace]; + read = &read[brace + 1..]; + + // skip cases where we find a {{ + if read.starts_with('{') { + out.push('{'); + read = &read[1..]; + continue; + } + + let next = peek_next!(read); + + let var = match next { + '0'..='9' => take_int(&mut read), + 'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read), + _ => return, + }; + + let ident = Ident::new(&var, span); + + let next = peek_next!(read); + + let arg = if cfg!(feature = "std") && next == '}' { + quote_spanned!(span=> , #ident.__displaydoc_display()) + } else { + quote_spanned!(span=> , #ident) + }; + + args.extend(arg); + } + + out += read; + self.fmt = LitStr::new(&out, self.fmt.span()); + self.args = args; + } +} + +fn take_int(read: &mut &str) -> String { + let mut int = String::new(); + int.push('_'); + for (i, ch) in read.char_indices() { + match ch { + '0'..='9' => int.push(ch), + _ => { + *read = &read[i..]; + break; + } + } + } + int +} + +fn take_ident(read: &mut &str) -> String { + let mut ident = String::new(); + for (i, ch) in read.char_indices() { + match ch { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch), + _ => { + *read = &read[i..]; + break; + } + } + } + ident +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + use proc_macro2::Span; + + fn assert(input: &str, fmt: &str, args: &str) { + let mut display = Display { + fmt: LitStr::new(input, Span::call_site()), + args: TokenStream::new(), + }; + display.expand_shorthand(); + assert_eq!(fmt, display.fmt.value()); + assert_eq!(args, display.args.to_string()); + } + + #[test] + fn test_expand() { + assert("fn main() {{ }}", "fn main() {{ }}", ""); + } + + #[test] + #[cfg_attr(not(feature = "std"), ignore)] + fn test_std_expand() { + assert( + "{v} {v:?} {0} {0:?}", + "{} {:?} {} {:?}", + ", v . __displaydoc_display () , v , _0 . __displaydoc_display () , _0", + ); + assert("error {var}", "error {}", ", var . __displaydoc_display ()"); + + assert( + "error {var1}", + "error {}", + ", var1 . __displaydoc_display ()", + ); + + assert( + "error {var1var}", + "error {}", + ", var1var . __displaydoc_display ()", + ); + + assert( + "The path {0}", + "The path {}", + ", _0 . __displaydoc_display ()", + ); + assert("The path {0:?}", "The path {:?}", ", _0"); + } + + #[test] + #[cfg_attr(feature = "std", ignore)] + fn test_nostd_expand() { + assert( + "{v} {v:?} {0} {0:?}", + "{} {:?} {} {:?}", + ", v , v , _0 , _0", + ); + assert("error {var}", "error {}", ", var"); + + assert("The path {0}", "The path {}", ", _0"); + assert("The path {0:?}", "The path {:?}", ", _0"); + + assert("error {var1}", "error {}", ", var1"); + + assert("error {var1var}", "error {}", ", var1var"); + } +} diff --git a/third_party/rust/displaydoc/src/lib.rs b/third_party/rust/displaydoc/src/lib.rs new file mode 100644 index 0000000000..e4653d6755 --- /dev/null +++ b/third_party/rust/displaydoc/src/lib.rs @@ -0,0 +1,187 @@ +//! This library provides a convenient derive macro for the standard library's +//! [`core::fmt::Display`] trait. +//! +//! [`core::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html +//! +//! ```toml +//! [dependencies] +//! displaydoc = "0.2" +//! ``` +//! +//! *Compiler support: requires rustc 1.56+* +//! +//!
+//! +//! ## Example +//! +//! *Demonstration alongside the [`Error`][std::error::Error] derive macro from [`thiserror`](https://docs.rs/thiserror/1.0.25/thiserror/index.html), +//! to propagate source locations from [`io::Error`][std::io::Error] with the `#[source]` attribute:* +//! ```rust +//! use std::io; +//! use displaydoc::Display; +//! use thiserror::Error; +//! +//! #[derive(Display, Error, Debug)] +//! pub enum DataStoreError { +//! /// data store disconnected +//! Disconnect(#[source] io::Error), +//! /// the data for key `{0}` is not available +//! Redaction(String), +//! /// invalid header (expected {expected:?}, found {found:?}) +//! InvalidHeader { +//! expected: String, +//! found: String, +//! }, +//! /// unknown data store error +//! Unknown, +//! } +//! +//! let error = DataStoreError::Redaction("CLASSIFIED CONTENT".to_string()); +//! assert!("the data for key `CLASSIFIED CONTENT` is not available" == &format!("{}", error)); +//! ``` +//! *Note that although [`io::Error`][std::io::Error] implements `Display`, we do not add it to the +//! generated message for `DataStoreError::Disconnect`, since it is already made available via +//! `#[source]`. See further context on avoiding duplication in error reports at the rust blog +//! [here](https://github.com/yaahc/blog.rust-lang.org/blob/master/posts/inside-rust/2021-05-15-What-the-error-handling-project-group-is-working-towards.md#duplicate-information-issue).* +//! +//!
+//! +//! ## Details +//! +//! - A `fmt::Display` impl is generated for your enum if you provide +//! a docstring comment on each variant as shown above in the example. The +//! `Display` derive macro supports a shorthand for interpolating fields from +//! the error: +//! - `/// {var}` ⟶ `write!("{}", self.var)` +//! - `/// {0}` ⟶ `write!("{}", self.0)` +//! - `/// {var:?}` ⟶ `write!("{:?}", self.var)` +//! - `/// {0:?}` ⟶ `write!("{:?}", self.0)` +//! - This also works with structs and [generic types][crate::Display#generic-type-parameters]: +//! ```rust +//! # use displaydoc::Display; +//! /// oh no, an error: {0} +//! #[derive(Display)] +//! pub struct Error(pub E); +//! +//! let error: Error<&str> = Error("muahaha i am an error"); +//! assert!("oh no, an error: muahaha i am an error" == &format!("{}", error)); +//! ``` +//! +//! - Two optional attributes can be added to your types next to the derive: +//! +//! - `#[ignore_extra_doc_attributes]` makes the macro ignore any doc +//! comment attributes (or `///` lines) after the first. Multi-line +//! comments using `///` are otherwise treated as an error, so use this +//! attribute or consider switching to block doc comments (`/** */`). +//! +//! - `#[prefix_enum_doc_attributes]` combines the doc comment message on +//! your enum itself with the messages for each variant, in the format +//! “enum: variant”. When added to an enum, the doc comment on the enum +//! becomes mandatory. When added to any other type, it has no effect. +//! +//! - In case you want to have an independent doc comment, the +//! `#[displaydoc("...")` atrribute may be used on the variant or struct to +//! override it. +//! +//!
+//! +//! ## FAQ +//! +//! 1. **Is this crate `no_std` compatible?** +//! * Yes! This crate implements the [`core::fmt::Display`] trait, not the [`std::fmt::Display`] trait, so it should work in `std` and `no_std` environments. Just add `default-features = false`. +//! +//! 2. **Does this crate work with `Path` and `PathBuf` via the `Display` trait?** +//! * Yuuup. This crate uses @dtolnay's [autoref specialization technique](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md) to add a special trait for types to get the display impl. It then specializes for `Path` and `PathBuf`, and when either of these types are found, it calls `self.display()` to get a `std::path::Display<'_>` type which can be used with the `Display` format specifier! +#![doc(html_root_url = "https://docs.rs/displaydoc/0.2.3")] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn( + rust_2018_idioms, + unreachable_pub, + bad_style, + dead_code, + improper_ctypes, + non_shorthand_field_patterns, + no_mangle_generic_items, + overflowing_literals, + path_statements, + patterns_in_fns_without_body, + private_in_public, + unconditional_recursion, + unused, + unused_allocation, + unused_comparisons, + unused_parens, + while_true +)] +#![allow(clippy::try_err)] + +#[allow(unused_extern_crates)] +extern crate proc_macro; + +mod attr; +mod expand; +mod fmt; + +use proc_macro::TokenStream; +use syn::{parse_macro_input, DeriveInput}; + +/// [Custom `#[derive(...)]` macro](https://doc.rust-lang.org/edition-guide/rust-2018/macros/custom-derive.html) +/// for implementing [`fmt::Display`][core::fmt::Display] via doc comment attributes. +/// +/// ### Generic Type Parameters +/// +/// Type parameters to an enum or struct using this macro should *not* need to +/// have an explicit `Display` constraint at the struct or enum definition +/// site. A `Display` implementation for the `derive`d struct or enum is +/// generated assuming each type parameter implements `Display`, but that should +/// be possible without adding the constraint to the struct definition itself: +/// ```rust +/// use displaydoc::Display; +/// +/// /// oh no, an error: {0} +/// #[derive(Display)] +/// pub struct Error(pub E); +/// +/// // No need to require `E: Display`, since `displaydoc::Display` adds that implicitly. +/// fn generate_error(e: E) -> Error { Error(e) } +/// +/// assert!("oh no, an error: muahaha" == &format!("{}", generate_error("muahaha"))); +/// ``` +/// +/// ### Using [`Debug`][core::fmt::Debug] Implementations with Type Parameters +/// However, if a type parameter must instead be constrained with the +/// [`Debug`][core::fmt::Debug] trait so that some field may be printed with +/// `{:?}`, that constraint must currently still also be specified redundantly +/// at the struct or enum definition site. If a struct or enum field is being +/// formatted with `{:?}` via [`displaydoc`][crate], and a generic type +/// parameter must implement `Debug` to do that, then that struct or enum +/// definition will need to propagate the `Debug` constraint to every type +/// parameter it's instantiated with: +/// ```rust +/// use core::fmt::Debug; +/// use displaydoc::Display; +/// +/// /// oh no, an error: {0:?} +/// #[derive(Display)] +/// pub struct Error(pub E); +/// +/// // `E: Debug` now has to propagate to callers. +/// fn generate_error(e: E) -> Error { Error(e) } +/// +/// assert!("oh no, an error: \"cool\"" == &format!("{}", generate_error("cool"))); +/// +/// // Try this with a struct that doesn't impl `Display` at all, unlike `str`. +/// #[derive(Debug)] +/// pub struct Oh; +/// assert!("oh no, an error: Oh" == &format!("{}", generate_error(Oh))); +/// ``` +#[proc_macro_derive( + Display, + attributes(ignore_extra_doc_attributes, prefix_enum_doc_attributes, displaydoc) +)] +pub fn derive_error(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + expand::derive(&input) + .unwrap_or_else(|err| err.to_compile_error()) + .into() +} diff --git a/third_party/rust/displaydoc/tests/compile_tests.rs b/third_party/rust/displaydoc/tests/compile_tests.rs new file mode 100644 index 0000000000..ac7427a75b --- /dev/null +++ b/third_party/rust/displaydoc/tests/compile_tests.rs @@ -0,0 +1,29 @@ +#[allow(unused_attributes)] +#[rustversion::attr(not(nightly), ignore)] +#[test] +fn no_std() { + let t = trybuild::TestCases::new(); + #[cfg(not(feature = "std"))] + t.compile_fail("tests/no_std/without.rs"); + #[cfg(not(feature = "std"))] + t.compile_fail("tests/no_std/multi_line.rs"); + #[cfg(not(feature = "std"))] + t.pass("tests/no_std/multi_line_allow.rs"); + #[cfg(not(feature = "std"))] + t.compile_fail("tests/no_std/enum_prefix_missing.rs"); + #[cfg(not(feature = "std"))] + t.pass("tests/no_std/enum_prefix.rs"); + #[cfg(feature = "std")] + t.compile_fail("tests/std/without.rs"); + #[cfg(feature = "std")] + t.compile_fail("tests/std/multi_line.rs"); + #[cfg(feature = "std")] + t.pass("tests/std/multi_line_allow.rs"); + #[cfg(feature = "std")] + t.compile_fail("tests/std/enum_prefix_missing.rs"); + #[cfg(feature = "std")] + t.pass("tests/std/enum_prefix.rs"); + #[cfg(feature = "std")] + t.pass("tests/std/multiple.rs"); + t.pass("tests/no_std/with.rs"); +} diff --git a/third_party/rust/displaydoc/tests/happy.rs b/third_party/rust/displaydoc/tests/happy.rs new file mode 100644 index 0000000000..f8fde9c612 --- /dev/null +++ b/third_party/rust/displaydoc/tests/happy.rs @@ -0,0 +1,152 @@ +use displaydoc::Display; + +#[cfg(feature = "std")] +use std::path::PathBuf; + +#[derive(Display)] +/// Just a basic struct {thing} +struct HappyStruct { + thing: &'static str, +} + +#[derive(Display)] +#[ignore_extra_doc_attributes] +/// Just a basic struct {thing} +/// and this line should get ignored +struct HappyStruct2 { + thing: &'static str, +} + +#[derive(Display)] +enum Happy { + /// I really like Variant1 + Variant1, + /// Variant2 is pretty swell 2 + Variant2, + /// Variant3 is okay {sometimes} + Variant3 { sometimes: &'static str }, + /** + * Variant4 wants to have a lot of lines + * + * Lets see how this works out for it + */ + Variant4, + /// Variant5 has a parameter {0} and some regular comments + // A regular comment that won't get picked + Variant5(u32), + + /// The path {0} + #[cfg(feature = "std")] + Variant6(PathBuf), + + /// These docs are ignored + #[displaydoc("Variant7 has a parameter {0} and uses #[displaydoc]")] + /// These docs are also ignored + Variant7(u32), +} + +// Used for testing indented doc comments +mod inner_mod { + use super::Display; + + #[derive(Display)] + pub enum InnerHappy { + /// I really like Variant1 + Variant1, + /// Variant2 is pretty swell 2 + Variant2, + /// Variant3 is okay {sometimes} + Variant3 { sometimes: &'static str }, + /** + * Variant4 wants to have a lot of lines + * + * Lets see how this works out for it + */ + Variant4, + /// Variant5 has a parameter {0} and some regular comments + // A regular comment that won't get picked + Variant5(u32), + + /** what happens if we + * put text on the first line? + */ + Variant6, + + /** + what happens if we don't use *? + */ + Variant7, + + /** + * + * what about extra new lines? + */ + Variant8, + } +} + +fn assert_display(input: T, expected: &'static str) { + let out = format!("{}", input); + assert_eq!(expected, out); +} + +#[test] +fn does_it_print() { + assert_display(Happy::Variant1, "I really like Variant1"); + assert_display(Happy::Variant2, "Variant2 is pretty swell 2"); + assert_display(Happy::Variant3 { sometimes: "hi" }, "Variant3 is okay hi"); + assert_display( + Happy::Variant4, + "Variant4 wants to have a lot of lines\n\nLets see how this works out for it", + ); + assert_display( + Happy::Variant5(2), + "Variant5 has a parameter 2 and some regular comments", + ); + assert_display( + Happy::Variant7(2), + "Variant7 has a parameter 2 and uses #[displaydoc]", + ); + assert_display(HappyStruct { thing: "hi" }, "Just a basic struct hi"); + + assert_display(HappyStruct2 { thing: "hi2" }, "Just a basic struct hi2"); + + assert_display(inner_mod::InnerHappy::Variant1, "I really like Variant1"); + assert_display( + inner_mod::InnerHappy::Variant2, + "Variant2 is pretty swell 2", + ); + assert_display( + inner_mod::InnerHappy::Variant3 { sometimes: "hi" }, + "Variant3 is okay hi", + ); + assert_display( + inner_mod::InnerHappy::Variant4, + "Variant4 wants to have a lot of lines\n\nLets see how this works out for it", + ); + assert_display( + inner_mod::InnerHappy::Variant5(2), + "Variant5 has a parameter 2 and some regular comments", + ); + assert_display( + inner_mod::InnerHappy::Variant6, + "what happens if we\nput text on the first line?", + ); + assert_display( + inner_mod::InnerHappy::Variant7, + "what happens if we don\'t use *?", + ); + assert_display( + inner_mod::InnerHappy::Variant8, + "what about extra new lines?", + ); +} + +#[test] +#[cfg(feature = "std")] +fn does_it_print_path() { + assert_display( + Happy::Variant6(PathBuf::from("/var/log/happy")), + "The path /var/log/happy", + ); +} diff --git a/third_party/rust/displaydoc/tests/no_std/enum_prefix.rs b/third_party/rust/displaydoc/tests/no_std/enum_prefix.rs new file mode 100644 index 0000000000..b8482cac8f --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/enum_prefix.rs @@ -0,0 +1,36 @@ +#![cfg_attr(not(feature = "std"), feature(lang_items, start))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(not(feature = "std"), start)] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +use displaydoc::Display; + +/// this type is pretty swell +#[derive(Display)] +#[prefix_enum_doc_attributes] +enum TestType { + /// this variant is too + Variant1, + + /// this variant is two + Variant2, +} + +static_assertions::assert_impl_all!(TestType: core::fmt::Display); + +#[cfg(feature = "std")] +fn main() {} diff --git a/third_party/rust/displaydoc/tests/no_std/enum_prefix_missing.rs b/third_party/rust/displaydoc/tests/no_std/enum_prefix_missing.rs new file mode 100644 index 0000000000..474073e8f3 --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/enum_prefix_missing.rs @@ -0,0 +1,35 @@ +#![cfg_attr(not(feature = "std"), feature(lang_items, start))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(not(feature = "std"), start)] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +use displaydoc::Display; + +#[derive(Display)] +#[prefix_enum_doc_attributes] +enum TestType { + /// this variant is too + Variant1, + + /// this variant is two + Variant2, +} + +static_assertions::assert_impl_all!(TestType: core::fmt::Display); + +#[cfg(feature = "std")] +fn main() {} diff --git a/third_party/rust/displaydoc/tests/no_std/enum_prefix_missing.stderr b/third_party/rust/displaydoc/tests/no_std/enum_prefix_missing.stderr new file mode 100644 index 0000000000..8d4023258e --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/enum_prefix_missing.stderr @@ -0,0 +1,22 @@ +error: proc-macro derive panicked + --> $DIR/enum_prefix_missing.rs:22:10 + | +22 | #[derive(Display)] + | ^^^^^^^ + | + = help: message: Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself. + +error[E0277]: `TestType` doesn't implement `Display` + --> $DIR/enum_prefix_missing.rs:32:37 + | +32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display); + | ^^^^^^^^ `TestType` cannot be formatted with the default formatter + | + = help: the trait `Display` is not implemented for `TestType` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `assert_impl_all` + --> $DIR/enum_prefix_missing.rs:32:1 + | +32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/displaydoc/tests/no_std/multi_line.rs b/third_party/rust/displaydoc/tests/no_std/multi_line.rs new file mode 100644 index 0000000000..351f6a4ebb --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/multi_line.rs @@ -0,0 +1,37 @@ +#![cfg_attr(not(feature = "std"), feature(lang_items, start))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(not(feature = "std"), start)] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +use displaydoc::Display; + +/// this type is pretty swell +#[derive(Display)] +enum TestType { + /// This one is okay + Variant1, + + /// Multi + /// line + /// doc. + Variant2, +} + +static_assertions::assert_impl_all!(TestType: core::fmt::Display); + +#[cfg(feature = "std")] +fn main() {} diff --git a/third_party/rust/displaydoc/tests/no_std/multi_line.stderr b/third_party/rust/displaydoc/tests/no_std/multi_line.stderr new file mode 100644 index 0000000000..ae4956e302 --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/multi_line.stderr @@ -0,0 +1,22 @@ +error: proc-macro derive panicked + --> $DIR/multi_line.rs:23:10 + | +23 | #[derive(Display)] + | ^^^^^^^ + | + = help: message: Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive. + +error[E0277]: `TestType` doesn't implement `Display` + --> $DIR/multi_line.rs:34:37 + | +34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display); + | ^^^^^^^^ `TestType` cannot be formatted with the default formatter + | + = help: the trait `Display` is not implemented for `TestType` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `assert_impl_all` + --> $DIR/multi_line.rs:34:1 + | +34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/displaydoc/tests/no_std/multi_line_allow.rs b/third_party/rust/displaydoc/tests/no_std/multi_line_allow.rs new file mode 100644 index 0000000000..22511d9e71 --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/multi_line_allow.rs @@ -0,0 +1,38 @@ +#![cfg_attr(not(feature = "std"), feature(lang_items, start))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(not(feature = "std"), start)] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +use displaydoc::Display; + +/// this type is pretty swell +#[derive(Display)] +#[ignore_extra_doc_attributes] +enum TestType { + /// This one is okay + Variant1, + + /// Multi + /// line + /// doc. + Variant2, +} + +static_assertions::assert_impl_all!(TestType: core::fmt::Display); + +#[cfg(feature = "std")] +fn main() {} diff --git a/third_party/rust/displaydoc/tests/no_std/with.rs b/third_party/rust/displaydoc/tests/no_std/with.rs new file mode 100644 index 0000000000..eba74609da --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/with.rs @@ -0,0 +1,32 @@ +#![feature(lang_items, start)] +#![no_std] + +#[start] +#[cfg(not(feature = "std"))] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} + +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +#[cfg(feature = "std")] +fn main() {} + +use displaydoc::Display; + +/// this type is pretty swell +#[derive(Display)] +struct FakeType; + +static_assertions::assert_impl_all!(FakeType: core::fmt::Display); diff --git a/third_party/rust/displaydoc/tests/no_std/without.rs b/third_party/rust/displaydoc/tests/no_std/without.rs new file mode 100644 index 0000000000..aab3164f08 --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/without.rs @@ -0,0 +1,28 @@ +#![cfg_attr(not(feature = "std"), feature(lang_items, start))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(not(feature = "std"), start)] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +use displaydoc::Display; + +/// this type is pretty swell +struct FakeType; + +static_assertions::assert_impl_all!(FakeType: core::fmt::Display); + +#[cfg(feature = "std")] +fn main() {} diff --git a/third_party/rust/displaydoc/tests/no_std/without.stderr b/third_party/rust/displaydoc/tests/no_std/without.stderr new file mode 100644 index 0000000000..afcea63f75 --- /dev/null +++ b/third_party/rust/displaydoc/tests/no_std/without.stderr @@ -0,0 +1,22 @@ +warning: unused import: `displaydoc::Display` + --> $DIR/without.rs:20:5 + | +20 | use displaydoc::Display; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +error[E0277]: `FakeType` doesn't implement `Display` + --> $DIR/without.rs:25:37 + | +25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display); + | ^^^^^^^^ `FakeType` cannot be formatted with the default formatter + | + = help: the trait `Display` is not implemented for `FakeType` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `assert_impl_all` + --> $DIR/without.rs:25:1 + | +25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/displaydoc/tests/num_in_field.rs b/third_party/rust/displaydoc/tests/num_in_field.rs new file mode 100644 index 0000000000..ab90f0d76a --- /dev/null +++ b/third_party/rust/displaydoc/tests/num_in_field.rs @@ -0,0 +1,22 @@ +/// {foo1} {foo2} +#[derive(displaydoc::Display)] +pub struct Test { + foo1: String, + foo2: String, +} + +fn assert_display(input: T, expected: &'static str) { + let out = format!("{}", input); + assert_eq!(expected, out); +} + +#[test] +fn does_it_print() { + assert_display( + Test { + foo1: "hi".into(), + foo2: "hello".into(), + }, + "hi hello", + ); +} diff --git a/third_party/rust/displaydoc/tests/std/enum_prefix.rs b/third_party/rust/displaydoc/tests/std/enum_prefix.rs new file mode 100644 index 0000000000..b8482cac8f --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/enum_prefix.rs @@ -0,0 +1,36 @@ +#![cfg_attr(not(feature = "std"), feature(lang_items, start))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(not(feature = "std"), start)] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +use displaydoc::Display; + +/// this type is pretty swell +#[derive(Display)] +#[prefix_enum_doc_attributes] +enum TestType { + /// this variant is too + Variant1, + + /// this variant is two + Variant2, +} + +static_assertions::assert_impl_all!(TestType: core::fmt::Display); + +#[cfg(feature = "std")] +fn main() {} diff --git a/third_party/rust/displaydoc/tests/std/enum_prefix_missing.rs b/third_party/rust/displaydoc/tests/std/enum_prefix_missing.rs new file mode 100644 index 0000000000..474073e8f3 --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/enum_prefix_missing.rs @@ -0,0 +1,35 @@ +#![cfg_attr(not(feature = "std"), feature(lang_items, start))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(not(feature = "std"), start)] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +use displaydoc::Display; + +#[derive(Display)] +#[prefix_enum_doc_attributes] +enum TestType { + /// this variant is too + Variant1, + + /// this variant is two + Variant2, +} + +static_assertions::assert_impl_all!(TestType: core::fmt::Display); + +#[cfg(feature = "std")] +fn main() {} diff --git a/third_party/rust/displaydoc/tests/std/enum_prefix_missing.stderr b/third_party/rust/displaydoc/tests/std/enum_prefix_missing.stderr new file mode 100644 index 0000000000..fe4b5ef70b --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/enum_prefix_missing.stderr @@ -0,0 +1,22 @@ +error: proc-macro derive panicked + --> $DIR/enum_prefix_missing.rs:22:10 + | +22 | #[derive(Display)] + | ^^^^^^^ + | + = help: message: Missing doc comment on enum with #[prefix_enum_doc_attributes]. Please remove the attribute or add a doc comment to the enum itself. + +error[E0277]: `TestType` doesn't implement `std::fmt::Display` + --> $DIR/enum_prefix_missing.rs:32:37 + | +32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display); + | ^^^^^^^^ `TestType` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `TestType` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `assert_impl_all` + --> $DIR/enum_prefix_missing.rs:32:1 + | +32 | static_assertions::assert_impl_all!(TestType: core::fmt::Display); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/displaydoc/tests/std/multi_line.rs b/third_party/rust/displaydoc/tests/std/multi_line.rs new file mode 100644 index 0000000000..5b0f2cfdfd --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/multi_line.rs @@ -0,0 +1 @@ +../no_std/multi_line.rs \ No newline at end of file diff --git a/third_party/rust/displaydoc/tests/std/multi_line.stderr b/third_party/rust/displaydoc/tests/std/multi_line.stderr new file mode 100644 index 0000000000..a8b6602b88 --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/multi_line.stderr @@ -0,0 +1,22 @@ +error: proc-macro derive panicked + --> $DIR/multi_line.rs:23:10 + | +23 | #[derive(Display)] + | ^^^^^^^ + | + = help: message: Multi-line comments are disabled by default by displaydoc. Please consider using block doc comments (/** */) or adding the #[ignore_extra_doc_attributes] attribute to your type next to the derive. + +error[E0277]: `TestType` doesn't implement `std::fmt::Display` + --> $DIR/multi_line.rs:34:37 + | +34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display); + | ^^^^^^^^ `TestType` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `TestType` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `assert_impl_all` + --> $DIR/multi_line.rs:34:1 + | +34 | static_assertions::assert_impl_all!(TestType: core::fmt::Display); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/displaydoc/tests/std/multi_line_allow.rs b/third_party/rust/displaydoc/tests/std/multi_line_allow.rs new file mode 100644 index 0000000000..22511d9e71 --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/multi_line_allow.rs @@ -0,0 +1,38 @@ +#![cfg_attr(not(feature = "std"), feature(lang_items, start))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(not(feature = "std"), start)] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +use displaydoc::Display; + +/// this type is pretty swell +#[derive(Display)] +#[ignore_extra_doc_attributes] +enum TestType { + /// This one is okay + Variant1, + + /// Multi + /// line + /// doc. + Variant2, +} + +static_assertions::assert_impl_all!(TestType: core::fmt::Display); + +#[cfg(feature = "std")] +fn main() {} diff --git a/third_party/rust/displaydoc/tests/std/multiple.rs b/third_party/rust/displaydoc/tests/std/multiple.rs new file mode 100644 index 0000000000..b0a4de0f74 --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/multiple.rs @@ -0,0 +1,38 @@ +#![feature(lang_items, start)] +#![no_std] + +#[start] +#[cfg(not(feature = "std"))] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +#[lang = "eh_personality"] +#[no_mangle] +#[cfg(not(feature = "std"))] +pub extern "C" fn rust_eh_personality() {} + +#[panic_handler] +#[cfg(not(feature = "std"))] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { + libc::abort(); + } +} + +#[cfg(feature = "std")] +fn main() {} + +use displaydoc::Display; + +/// this type is pretty swell +#[derive(Display)] +struct FakeType; + +static_assertions::assert_impl_all!(FakeType: core::fmt::Display); + +/// this type is pretty swell2 +#[derive(Display)] +struct FakeType2; + +static_assertions::assert_impl_all!(FakeType2: core::fmt::Display); diff --git a/third_party/rust/displaydoc/tests/std/without.rs b/third_party/rust/displaydoc/tests/std/without.rs new file mode 100644 index 0000000000..6b5b714882 --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/without.rs @@ -0,0 +1 @@ +../no_std/without.rs \ No newline at end of file diff --git a/third_party/rust/displaydoc/tests/std/without.stderr b/third_party/rust/displaydoc/tests/std/without.stderr new file mode 100644 index 0000000000..552ae826fc --- /dev/null +++ b/third_party/rust/displaydoc/tests/std/without.stderr @@ -0,0 +1,22 @@ +warning: unused import: `displaydoc::Display` + --> $DIR/without.rs:20:5 + | +20 | use displaydoc::Display; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +error[E0277]: `FakeType` doesn't implement `std::fmt::Display` + --> $DIR/without.rs:25:37 + | +25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display); + | ^^^^^^^^ `FakeType` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `FakeType` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `assert_impl_all` + --> $DIR/without.rs:25:1 + | +25 | static_assertions::assert_impl_all!(FakeType: core::fmt::Display); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all` + = note: this error originates in the macro `static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/displaydoc/tests/variantless.rs b/third_party/rust/displaydoc/tests/variantless.rs new file mode 100644 index 0000000000..bc23ed4645 --- /dev/null +++ b/third_party/rust/displaydoc/tests/variantless.rs @@ -0,0 +1,6 @@ +use displaydoc::Display; + +#[derive(Display)] +enum EmptyInside {} + +static_assertions::assert_impl_all!(EmptyInside: core::fmt::Display); diff --git a/third_party/rust/displaydoc/update-readme.sh b/third_party/rust/displaydoc/update-readme.sh new file mode 100644 index 0000000000..90db1a8174 --- /dev/null +++ b/third_party/rust/displaydoc/update-readme.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env bash + +cargo readme > ./README.md +git add ./README.md +git commit -m "Update readme" || true -- cgit v1.2.3