mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-14 17:35:03 +01:00
vendor dbg-pls
This commit is contained in:
parent
a633546c8f
commit
57ba4cef3c
23 changed files with 2240 additions and 419 deletions
412
Cargo.lock
generated
412
Cargo.lock
generated
|
|
@ -2,267 +2,37 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adler"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "0.7.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bincode"
|
|
||||||
version = "1.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bumpalo"
|
|
||||||
version = "3.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.73"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crc32fast"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dbg-pls"
|
name = "dbg-pls"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e845b944ea4a6b446aec7c221c48fd6e73f2ab38e1af720cac0f47895dcc4580"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dbg-pls-derive",
|
|
||||||
"itoa",
|
"itoa",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"prettyplease",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"ryu",
|
"ryu",
|
||||||
"syn",
|
"syn",
|
||||||
"syntect",
|
|
||||||
"textwrap",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dbg-pls-derive"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b46318b37603779055a193fbb0454bb762e284f72a4d3c231f4a6ab8d3eede31"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dilaria"
|
name = "dilaria"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
|
||||||
"dbg-pls",
|
"dbg-pls",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "flate2"
|
|
||||||
version = "1.0.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crc32fast",
|
|
||||||
"libc",
|
|
||||||
"miniz_oxide",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fnv"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indexmap"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"hashbrown",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazycell"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.124"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "line-wrap"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
|
|
||||||
dependencies = [
|
|
||||||
"safemem",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linked-hash-map"
|
|
||||||
version = "0.5.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
|
|
||||||
dependencies = [
|
|
||||||
"adler",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_threads"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "onig"
|
|
||||||
version = "6.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67ddfe2c93bb389eea6e6d713306880c7f6dcc99a75b659ce145d962c861b225"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"onig_sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "onig_sys"
|
|
||||||
version = "69.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5dd3eee045c84695b53b20255bb7317063df090b68e18bfac0abb6c39cf7f33e"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkg-config"
|
|
||||||
version = "0.3.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "plist"
|
|
||||||
version = "1.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225"
|
|
||||||
dependencies = [
|
|
||||||
"base64",
|
|
||||||
"indexmap",
|
|
||||||
"line-wrap",
|
|
||||||
"serde",
|
|
||||||
"time",
|
|
||||||
"xml-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "prettyplease"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3b83ec2d0af5c5c556257ff52c9f98934e243b9fd39604bfb2a9b75ec2e97f18"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.37"
|
version = "1.0.37"
|
||||||
|
|
@ -281,78 +51,12 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.5.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.6.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.9"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safemem"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "same-file"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.136"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.136"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_json"
|
|
||||||
version = "1.0.79"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
|
||||||
dependencies = [
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smawk"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.91"
|
version = "1.0.91"
|
||||||
|
|
@ -364,124 +68,8 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syntect"
|
|
||||||
version = "4.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b20815bbe80ee0be06e6957450a841185fcf690fe0178f14d77a05ce2caa031"
|
|
||||||
dependencies = [
|
|
||||||
"bincode",
|
|
||||||
"bitflags",
|
|
||||||
"flate2",
|
|
||||||
"fnv",
|
|
||||||
"lazy_static",
|
|
||||||
"lazycell",
|
|
||||||
"onig",
|
|
||||||
"plist",
|
|
||||||
"regex-syntax",
|
|
||||||
"serde",
|
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
|
||||||
"walkdir",
|
|
||||||
"yaml-rust",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "textwrap"
|
|
||||||
version = "0.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
|
||||||
dependencies = [
|
|
||||||
"smawk",
|
|
||||||
"unicode-linebreak",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "time"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
|
|
||||||
dependencies = [
|
|
||||||
"itoa",
|
|
||||||
"libc",
|
|
||||||
"num_threads",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-linebreak"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f"
|
|
||||||
dependencies = [
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "walkdir"
|
|
||||||
version = "2.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
|
||||||
dependencies = [
|
|
||||||
"same-file",
|
|
||||||
"winapi",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[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"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xml-rs"
|
|
||||||
version = "0.8.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yaml-rust"
|
|
||||||
version = "0.4.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
|
||||||
dependencies = [
|
|
||||||
"linked-hash-map",
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,4 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
dbg-pls = { path = "./dbg-pls" }
|
||||||
dbg-pls = { version = "0.2.2", features = ["colors", "derive"] }
|
|
||||||
|
|
|
||||||
2
dbg-pls/.gitignore
vendored
Normal file
2
dbg-pls/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
52
dbg-pls/Cargo.toml
Normal file
52
dbg-pls/Cargo.toml
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
[workspace]
|
||||||
|
members = ["debug-derive"]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "dbg-pls"
|
||||||
|
version = "0.2.2"
|
||||||
|
authors = ["Conrad Ludgate <conradludgate@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
description = "Syntax aware pretty-printing debugging"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/conradludgate/dbg-pls"
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
include = [
|
||||||
|
"src",
|
||||||
|
"README.md",
|
||||||
|
"assets/syntaxes/Rust/Rust.sublime-syntax",
|
||||||
|
"assets/themes/sublime-monokai-extended/Monokai Extended.tmTheme",
|
||||||
|
]
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syn = { version = "1", features = ["full"] }
|
||||||
|
proc-macro2 = "1"
|
||||||
|
quote = "1"
|
||||||
|
itoa = "1"
|
||||||
|
ryu = "1"
|
||||||
|
|
||||||
|
# derive
|
||||||
|
dbg-pls-derive = { version = "0.2.1", path = "debug-derive", optional = true }
|
||||||
|
|
||||||
|
# pretty
|
||||||
|
prettyplease = { version = "0.1", optional = true }
|
||||||
|
textwrap = { version = "0.15", optional = true }
|
||||||
|
|
||||||
|
# colors
|
||||||
|
syntect = { version = "4.6.0", optional = true }
|
||||||
|
once_cell = "1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
dbg-pls = { path = ".", features = ["derive", "pretty", "colors"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
derive = ["dbg-pls-derive"]
|
||||||
|
pretty = ["prettyplease", "textwrap"]
|
||||||
|
colors = ["pretty", "syntect"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
17
dbg-pls/debug-derive/Cargo.toml
Normal file
17
dbg-pls/debug-derive/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "dbg-pls-derive"
|
||||||
|
version = "0.2.1"
|
||||||
|
authors = ["Conrad Ludgate <conradludgate@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
description = "derive(Debug)"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/conradludgate/dbg-pls"
|
||||||
|
readme = "../README.md"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1.0"
|
||||||
|
syn = "1.0"
|
||||||
|
proc-macro2 = "1.0"
|
||||||
117
dbg-pls/debug-derive/src/debug.rs
Normal file
117
dbg-pls/debug-derive/src/debug.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
use crate::pat::{named_idents, unnamed_idents, PatternImpl};
|
||||||
|
use proc_macro2::{Ident, TokenStream as TokenStream2};
|
||||||
|
use quote::{quote, ToTokens};
|
||||||
|
use syn::{spanned::Spanned, Data, DataEnum, DataStruct, DeriveInput, Fields, Path, Variant};
|
||||||
|
|
||||||
|
pub struct DebugImpl<T>(pub T);
|
||||||
|
|
||||||
|
impl ToTokens for DebugImpl<(Path, DeriveInput)> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let (path, input) = &self.0;
|
||||||
|
|
||||||
|
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||||
|
|
||||||
|
let ident = &input.ident;
|
||||||
|
let body = DebugImpl((ident, &input.data));
|
||||||
|
|
||||||
|
tokens.extend(quote! {
|
||||||
|
impl #impl_generics #path::DebugPls for #ident #ty_generics #where_clause {
|
||||||
|
fn fmt(&self, f: #path::Formatter<'_>) {
|
||||||
|
#body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a Data)> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let (name, data) = self.0;
|
||||||
|
match data {
|
||||||
|
Data::Struct(s) => DebugImpl((name, s)).to_tokens(tokens),
|
||||||
|
Data::Enum(e) => DebugImpl((name, e)).to_tokens(tokens),
|
||||||
|
Data::Union(_) => tokens
|
||||||
|
.extend(syn::Error::new(self.span(), "unions not supported").into_compile_error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a DataStruct)> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let (name, data) = self.0;
|
||||||
|
let pat = PatternImpl(&data.fields);
|
||||||
|
tokens.extend(quote! {
|
||||||
|
let #name #pat = self;
|
||||||
|
});
|
||||||
|
DebugImpl((name, &data.fields)).to_tokens(tokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a DataEnum)> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let (name, data) = self.0;
|
||||||
|
let variants = data.variants.iter().map(|v| DebugImpl((name, v)));
|
||||||
|
tokens.extend(quote! {
|
||||||
|
match self {
|
||||||
|
#( #variants )*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a Variant)> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let (name, variant) = self.0;
|
||||||
|
let Variant {
|
||||||
|
attrs: _,
|
||||||
|
ident,
|
||||||
|
fields,
|
||||||
|
discriminant: _,
|
||||||
|
} = &variant;
|
||||||
|
let pattern = PatternImpl(fields);
|
||||||
|
let debug = DebugImpl((ident, fields));
|
||||||
|
|
||||||
|
tokens.extend(quote! {
|
||||||
|
#name::#ident #pattern => { #debug }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToTokens for DebugImpl<(&'a Ident, &'a Fields)> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let (name, fields) = self.0;
|
||||||
|
let name = name.to_string();
|
||||||
|
match fields {
|
||||||
|
Fields::Named(named) => {
|
||||||
|
tokens.extend(quote! {
|
||||||
|
f.debug_struct(#name)
|
||||||
|
});
|
||||||
|
named_idents(named).for_each(|ident| {
|
||||||
|
let name = ident.to_string();
|
||||||
|
tokens.extend(quote! {
|
||||||
|
.field(#name, #ident)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
tokens.extend(quote! {
|
||||||
|
.finish()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Fields::Unnamed(unnamed) => {
|
||||||
|
tokens.extend(quote! {
|
||||||
|
f.debug_tuple_struct(#name)
|
||||||
|
});
|
||||||
|
unnamed_idents(unnamed).for_each(|ident| {
|
||||||
|
tokens.extend(quote! {
|
||||||
|
.field(#ident)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
tokens.extend(quote! {
|
||||||
|
.finish()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Fields::Unit => tokens.extend(quote! {
|
||||||
|
f.debug_ident(#name)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
dbg-pls/debug-derive/src/lib.rs
Normal file
61
dbg-pls/debug-derive/src/lib.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
use debug::DebugImpl;
|
||||||
|
use predicate::predicate;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::ToTokens;
|
||||||
|
use syn::{parse_macro_input, DeriveInput, parse_quote, Attribute, Path};
|
||||||
|
|
||||||
|
mod debug;
|
||||||
|
mod pat;
|
||||||
|
mod predicate;
|
||||||
|
|
||||||
|
/// Derives the standard `DebugPls` implementation.
|
||||||
|
///
|
||||||
|
/// Works exactly like [`Debug`]
|
||||||
|
#[proc_macro_derive(DebugPls, attributes(dbg_pls))]
|
||||||
|
pub fn derive(input: TokenStream) -> TokenStream {
|
||||||
|
let mut input = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
||||||
|
let path = match get_crate(&input.attrs) {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(err) => return err.into_compile_error().into_token_stream().into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
predicate(&mut input, path.clone());
|
||||||
|
DebugImpl((path, input)).into_token_stream().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crate(attrs: &[Attribute]) -> syn::Result<Path> {
|
||||||
|
fn parse_crate(lit: syn::Lit) -> syn::Result<Path> {
|
||||||
|
match lit {
|
||||||
|
syn::Lit::Str(s) => syn::parse_str(&s.value()),
|
||||||
|
_ => Err(syn::Error::new(lit.span(), "invalid crate name")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_meta(meta: syn::Meta) -> Option<syn::Result<Path>> {
|
||||||
|
if let syn::Meta::List(list) = meta {
|
||||||
|
for meta in list.nested {
|
||||||
|
if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = meta {
|
||||||
|
if let Some(ident) = nv.path.get_ident() {
|
||||||
|
if *ident == "crate" {
|
||||||
|
return Some(parse_crate(nv.lit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
for attr in attrs {
|
||||||
|
if let Some(ident) = attr.path.get_ident() {
|
||||||
|
if *ident == "dbg_pls" {
|
||||||
|
if let Some(path) = parse_meta(Attribute::parse_meta(attr)?).transpose()? {
|
||||||
|
return Ok(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(parse_quote! { ::dbg_pls })
|
||||||
|
}
|
||||||
46
dbg-pls/debug-derive/src/pat.rs
Normal file
46
dbg-pls/debug-derive/src/pat.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use proc_macro2::{Delimiter, Group, Ident, TokenStream as TokenStream2, TokenTree};
|
||||||
|
use quote::{format_ident, quote, ToTokens};
|
||||||
|
use syn::{spanned::Spanned, Fields, FieldsNamed, FieldsUnnamed};
|
||||||
|
|
||||||
|
pub struct PatternImpl<T>(pub T);
|
||||||
|
|
||||||
|
impl<'a> ToTokens for PatternImpl<&'a Fields> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
match &self.0 {
|
||||||
|
Fields::Named(named) => PatternImpl(named).to_tokens(tokens),
|
||||||
|
Fields::Unnamed(unnamed) => PatternImpl(unnamed).to_tokens(tokens),
|
||||||
|
Fields::Unit => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToTokens for PatternImpl<&'a FieldsNamed> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let idents = named_idents(self.0);
|
||||||
|
let inner = quote! { #(#idents),* };
|
||||||
|
tokens.extend([TokenTree::Group(Group::new(Delimiter::Brace, inner))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToTokens for PatternImpl<&'a FieldsUnnamed> {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let idents = unnamed_idents(self.0);
|
||||||
|
let inner = quote! { #(#idents),* };
|
||||||
|
tokens.extend([TokenTree::Group(Group::new(Delimiter::Parenthesis, inner))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unnamed_idents(fields: &FieldsUnnamed) -> impl Iterator<Item = Ident> + '_ {
|
||||||
|
fields
|
||||||
|
.unnamed
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, field)| format_ident!("val{}", i, span = field.span()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn named_idents(fields: &FieldsNamed) -> impl Iterator<Item = &Ident> + '_ {
|
||||||
|
fields
|
||||||
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|field| field.ident.as_ref().unwrap())
|
||||||
|
}
|
||||||
57
dbg-pls/debug-derive/src/predicate.rs
Normal file
57
dbg-pls/debug-derive/src/predicate.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
use quote::format_ident;
|
||||||
|
use syn::{
|
||||||
|
punctuated::Punctuated, token, Data, DeriveInput, Field, Fields, Path, PredicateType,
|
||||||
|
TraitBound, TypeParamBound, WhereClause, WherePredicate,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn predicate(input: &mut DeriveInput, path: Path) {
|
||||||
|
let mut pred = Pred {
|
||||||
|
wc: input.generics.make_where_clause(),
|
||||||
|
path,
|
||||||
|
};
|
||||||
|
|
||||||
|
match &input.data {
|
||||||
|
Data::Struct(s) => pred.fields(&s.fields),
|
||||||
|
Data::Enum(e) => e.variants.iter().for_each(|var| pred.fields(&var.fields)),
|
||||||
|
Data::Union(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Pred<'a> {
|
||||||
|
wc: &'a mut WhereClause,
|
||||||
|
path: Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Pred<'a> {
|
||||||
|
fn dbg_pls(&mut self, field: &Field) {
|
||||||
|
let mut bounds = Punctuated::new();
|
||||||
|
|
||||||
|
let mut path = self.path.clone();
|
||||||
|
path.segments.push(syn::PathSegment {
|
||||||
|
ident: format_ident!("DebugPls"),
|
||||||
|
arguments: syn::PathArguments::None,
|
||||||
|
});
|
||||||
|
|
||||||
|
bounds.push(TypeParamBound::Trait(TraitBound {
|
||||||
|
paren_token: None,
|
||||||
|
modifier: syn::TraitBoundModifier::None,
|
||||||
|
lifetimes: None,
|
||||||
|
path,
|
||||||
|
}));
|
||||||
|
|
||||||
|
self.wc.predicates.push(WherePredicate::Type(PredicateType {
|
||||||
|
lifetimes: None,
|
||||||
|
bounded_ty: field.ty.clone(),
|
||||||
|
colon_token: token::Colon::default(),
|
||||||
|
bounds,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fields(&mut self, fields: &Fields) {
|
||||||
|
match fields {
|
||||||
|
syn::Fields::Named(named) => named.named.iter().for_each(|f| self.dbg_pls(f)),
|
||||||
|
syn::Fields::Unnamed(unnamed) => unnamed.unnamed.iter().for_each(|f| self.dbg_pls(f)),
|
||||||
|
syn::Fields::Unit => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
175
dbg-pls/src/colors.rs
Normal file
175
dbg-pls/src/colors.rs
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
// use bat::PrettyPrinter;
|
||||||
|
|
||||||
|
// use crate::{pretty::process, DebugPls};
|
||||||
|
|
||||||
|
// /// Prints the pretty printed code to stdout
|
||||||
|
// pub fn print_colorful(value: &dyn DebugPls) {
|
||||||
|
// let output = process(value);
|
||||||
|
// let _ = PrettyPrinter::new()
|
||||||
|
// .input_from_bytes(output.as_bytes())
|
||||||
|
// .language("rust")
|
||||||
|
// .line_numbers(true)
|
||||||
|
// .print();
|
||||||
|
// }
|
||||||
|
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use syntect::{
|
||||||
|
easy::HighlightLines,
|
||||||
|
highlighting::{Theme, ThemeSet},
|
||||||
|
parsing::{SyntaxDefinition, SyntaxSet, SyntaxSetBuilder},
|
||||||
|
util::{as_24_bit_terminal_escaped, LinesWithEndings},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{pretty::pretty_string, DebugPls, Formatter};
|
||||||
|
|
||||||
|
fn syntax() -> &'static SyntaxSet {
|
||||||
|
static INSTANCE: OnceCell<SyntaxSet> = OnceCell::new();
|
||||||
|
INSTANCE.get_or_init(|| {
|
||||||
|
let mut syntax_set = SyntaxSetBuilder::new();
|
||||||
|
syntax_set.add(
|
||||||
|
SyntaxDefinition::load_from_str(
|
||||||
|
include_str!("../assets/syntaxes/Rust/Rust.sublime-syntax"),
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
syntax_set.build()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn theme() -> &'static Theme {
|
||||||
|
static INSTANCE: OnceCell<Theme> = OnceCell::new();
|
||||||
|
INSTANCE.get_or_init(|| {
|
||||||
|
let s = include_str!("../assets/themes/sublime-monokai-extended/Monokai Extended.tmTheme");
|
||||||
|
ThemeSet::load_from_reader(&mut Cursor::new(s.as_bytes())).unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight(s: &str, mut w: impl std::fmt::Write) -> std::fmt::Result {
|
||||||
|
let ps = syntax();
|
||||||
|
let syntax = ps.find_syntax_by_name("Rust").unwrap();
|
||||||
|
let theme = theme();
|
||||||
|
|
||||||
|
let mut h = HighlightLines::new(syntax, theme);
|
||||||
|
|
||||||
|
for line in LinesWithEndings::from(s) {
|
||||||
|
let ranges = h.highlight(line, ps);
|
||||||
|
write!(w, "{}", as_24_bit_terminal_escaped(&ranges[..], false))?;
|
||||||
|
}
|
||||||
|
write!(w, "\x1b[0m") // reset the color
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation detail for the `color!` macro
|
||||||
|
pub struct ColorStr<'a>(pub &'a str);
|
||||||
|
|
||||||
|
impl<'a> std::fmt::Display for ColorStr<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let expr = syn::parse_str(self.0).map_err(|_| std::fmt::Error)?;
|
||||||
|
highlight(&pretty_string(expr), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Color<'a>(&'a dyn DebugPls);
|
||||||
|
|
||||||
|
impl<'a> std::fmt::Debug for Color<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
highlight(&pretty_string(Formatter::process(self.0)), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::fmt::Display for Color<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Debug::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "colors")))]
|
||||||
|
/// Wraps a [`Debug`] type into a [`std::fmt::Debug`] type for use in regular [`format!`]
|
||||||
|
pub fn color(value: &impl DebugPls) -> impl std::fmt::Debug + std::fmt::Display + '_ {
|
||||||
|
Color(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "colors")))]
|
||||||
|
#[macro_export]
|
||||||
|
/// Prints and returns the value of a given expression for quick and dirty
|
||||||
|
/// debugging. Same as [`std::dbg`]
|
||||||
|
///
|
||||||
|
/// An example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use dbg_pls::color;
|
||||||
|
/// let a = 2;
|
||||||
|
/// let b = color!(a * 2) + 1;
|
||||||
|
/// // ^-- prints: [src/main.rs:2] a * 2 = 4
|
||||||
|
/// // with syntax highlighting
|
||||||
|
/// assert_eq!(b, 5);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The macro works by using the [`DebugPls`] implementation of the type of
|
||||||
|
/// the given expression to print the value to [stderr] along with the
|
||||||
|
/// source location of the macro invocation as well as the source code
|
||||||
|
/// of the expression.
|
||||||
|
///
|
||||||
|
/// Invoking the macro on an expression moves and takes ownership of it
|
||||||
|
/// before returning the evaluated expression unchanged. If the type
|
||||||
|
/// of the expression does not implement `Copy` and you don't want
|
||||||
|
/// to give up ownership, you can instead borrow with `color!(&expr)`
|
||||||
|
/// for some expression `expr`.
|
||||||
|
///
|
||||||
|
/// The `color!` macro works exactly the same in release builds.
|
||||||
|
/// This is useful when debugging issues that only occur in release
|
||||||
|
/// builds or when debugging in release mode is significantly faster.
|
||||||
|
///
|
||||||
|
/// Note that the macro is intended as a debugging tool and therefore you
|
||||||
|
/// should avoid having uses of it in version control for long periods
|
||||||
|
/// (other than in tests and similar).
|
||||||
|
/// Debug output from production code is better done with other facilities
|
||||||
|
/// such as the [`debug!`] macro from the [`log`] crate.
|
||||||
|
///
|
||||||
|
/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
|
||||||
|
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
|
||||||
|
/// [`log`]: https://crates.io/crates/log
|
||||||
|
macro_rules! color {
|
||||||
|
() => {
|
||||||
|
::std::eprintln!("[{}:{}]", ::std::file!(), ::std::line!())
|
||||||
|
};
|
||||||
|
($val:expr $(,)?) => {
|
||||||
|
match $val {
|
||||||
|
tmp => {
|
||||||
|
::std::eprintln!(
|
||||||
|
"[{}:{}] {} => {}",
|
||||||
|
::std::file!(),
|
||||||
|
::std::line!(),
|
||||||
|
$crate::__private::ColorStr(::std::stringify!($val)),
|
||||||
|
$crate::color(&tmp)
|
||||||
|
);
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($($val:expr),+ $(,)?) => {
|
||||||
|
($($crate::color!($val)),+,)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::color;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn colors() {
|
||||||
|
let map = color! {
|
||||||
|
HashMap::from([
|
||||||
|
("hello", 1),
|
||||||
|
("world", 2),
|
||||||
|
])
|
||||||
|
};
|
||||||
|
// map is moved through properly
|
||||||
|
assert_eq!(map, HashMap::from([("hello", 1), ("world", 2),]));
|
||||||
|
}
|
||||||
|
}
|
||||||
69
dbg-pls/src/debug_list.rs
Normal file
69
dbg-pls/src/debug_list.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
/// A helper designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for list-like structures.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo(Vec<i32>);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
/// f.debug_list().entries(&self.0).finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let value = Foo(vec![10, 11]);
|
||||||
|
/// assert_eq!(format!("{}", pretty(&value)), "[10, 11]");
|
||||||
|
/// ```
|
||||||
|
pub struct DebugList<'a> {
|
||||||
|
formatter: Formatter<'a>,
|
||||||
|
expr: syn::ExprArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DebugList<'a> {
|
||||||
|
pub(crate) fn new(formatter: Formatter<'a>) -> Self {
|
||||||
|
DebugList {
|
||||||
|
formatter,
|
||||||
|
expr: syn::ExprArray {
|
||||||
|
attrs: vec![],
|
||||||
|
bracket_token: syn::token::Bracket::default(),
|
||||||
|
elems: syn::punctuated::Punctuated::default(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a new entry to the list output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn entry(mut self, entry: &dyn DebugPls) -> Self {
|
||||||
|
self.expr.elems.push(Formatter::process(entry));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds all the entries to the list output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn entries<D, I>(mut self, entries: I) -> Self
|
||||||
|
where
|
||||||
|
D: DebugPls,
|
||||||
|
I: IntoIterator<Item = D>,
|
||||||
|
{
|
||||||
|
self.extend(entries);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes off the list
|
||||||
|
pub fn finish(self) {
|
||||||
|
self.formatter.write_expr(self.expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'f, D: DebugPls> Extend<D> for DebugList<'f> {
|
||||||
|
fn extend<T: IntoIterator<Item = D>>(&mut self, iter: T) {
|
||||||
|
self.expr
|
||||||
|
.elems
|
||||||
|
.extend(iter.into_iter().map(|entry| Formatter::process(&entry)));
|
||||||
|
}
|
||||||
|
}
|
||||||
126
dbg-pls/src/debug_map.rs
Normal file
126
dbg-pls/src/debug_map.rs
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
/// A helper designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for maps.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
/// use std::collections::BTreeMap;
|
||||||
|
///
|
||||||
|
/// struct Foo(BTreeMap<String, i32>);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_map().entries(&self.0).finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// let mut value = Foo(BTreeMap::from([
|
||||||
|
/// ("Hello".to_string(), 5),
|
||||||
|
/// ("World".to_string(), 10),
|
||||||
|
/// ]));
|
||||||
|
/// assert_eq!(
|
||||||
|
/// format!("{}", pretty(&value)),
|
||||||
|
/// "{
|
||||||
|
/// [\"Hello\"] = 5;
|
||||||
|
/// [\"World\"] = 10;
|
||||||
|
/// }",
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
pub struct DebugMap<'a> {
|
||||||
|
formatter: Formatter<'a>,
|
||||||
|
set: syn::Block,
|
||||||
|
key: Option<syn::Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DebugMap<'a> {
|
||||||
|
pub(crate) fn new(formatter: Formatter<'a>) -> Self {
|
||||||
|
DebugMap {
|
||||||
|
formatter,
|
||||||
|
set: syn::Block {
|
||||||
|
brace_token: syn::token::Brace::default(),
|
||||||
|
stmts: vec![],
|
||||||
|
},
|
||||||
|
key: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the key part to the map output.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// `key` must be called before `value` and each call to `key` must be followed
|
||||||
|
/// by a corresponding call to `value`. Otherwise this method will panic.
|
||||||
|
#[must_use]
|
||||||
|
pub fn key(mut self, key: &dyn DebugPls) -> Self {
|
||||||
|
if self.key.replace(Formatter::process(key)).is_some() {
|
||||||
|
panic!("attempted to begin a new map entry without completing the previous one");
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the value part to the map output.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// `key` must be called before `value` and each call to `key` must be followed
|
||||||
|
/// by a corresponding call to `value`. Otherwise this method will panic.
|
||||||
|
#[must_use]
|
||||||
|
pub fn value(mut self, value: &dyn DebugPls) -> Self {
|
||||||
|
let key = self
|
||||||
|
.key
|
||||||
|
.take()
|
||||||
|
.expect("attempted to format a map value before its key");
|
||||||
|
let value = Formatter::process(value);
|
||||||
|
let entry = syn::ExprAssign {
|
||||||
|
attrs: vec![],
|
||||||
|
left: Box::new(
|
||||||
|
syn::ExprArray {
|
||||||
|
attrs: vec![],
|
||||||
|
bracket_token: syn::token::Bracket::default(),
|
||||||
|
elems: Punctuated::from_iter([key]),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
eq_token: syn::token::Eq::default(),
|
||||||
|
right: Box::new(value),
|
||||||
|
};
|
||||||
|
self.set
|
||||||
|
.stmts
|
||||||
|
.push(syn::Stmt::Semi(entry.into(), syn::token::Semi::default()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the entry to the map output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn entry(self, key: &dyn DebugPls, value: &dyn DebugPls) -> Self {
|
||||||
|
self.key(key).value(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds all the entries to the map output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn entries<K, V, I>(self, entries: I) -> Self
|
||||||
|
where
|
||||||
|
K: DebugPls,
|
||||||
|
V: DebugPls,
|
||||||
|
I: IntoIterator<Item = (K, V)>,
|
||||||
|
{
|
||||||
|
entries
|
||||||
|
.into_iter()
|
||||||
|
.fold(self, |f, (key, value)| f.entry(&key, &value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes off the map.
|
||||||
|
pub fn finish(self) {
|
||||||
|
self.formatter.write_expr(syn::ExprBlock {
|
||||||
|
attrs: vec![],
|
||||||
|
label: None,
|
||||||
|
block: self.set,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
80
dbg-pls/src/debug_set.rs
Normal file
80
dbg-pls/src/debug_set.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
/// A helper designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for sets.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
/// use std::collections::BTreeSet;
|
||||||
|
///
|
||||||
|
/// struct Foo(BTreeSet<String>);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_set().entries(&self.0).finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// let mut value = Foo(BTreeSet::from([
|
||||||
|
/// "Hello".to_string(),
|
||||||
|
/// "World".to_string(),
|
||||||
|
/// ]));
|
||||||
|
/// assert_eq!(
|
||||||
|
/// format!("{}", pretty(&value)),
|
||||||
|
/// "{
|
||||||
|
/// \"Hello\";
|
||||||
|
/// \"World\"
|
||||||
|
/// }",
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
pub struct DebugSet<'a> {
|
||||||
|
formatter: Formatter<'a>,
|
||||||
|
set: syn::Block,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DebugSet<'a> {
|
||||||
|
pub(crate) fn new(formatter: Formatter<'a>) -> Self {
|
||||||
|
DebugSet {
|
||||||
|
formatter,
|
||||||
|
set: syn::Block {
|
||||||
|
brace_token: syn::token::Brace::default(),
|
||||||
|
stmts: vec![],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the entry to the set output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn entry(mut self, value: &dyn DebugPls) -> Self {
|
||||||
|
let expr = Formatter::process(value);
|
||||||
|
self.set
|
||||||
|
.stmts
|
||||||
|
.push(syn::Stmt::Semi(expr, syn::token::Semi::default()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds all the entries to the set output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn entries<V, I>(self, entries: I) -> Self
|
||||||
|
where
|
||||||
|
V: DebugPls,
|
||||||
|
I: IntoIterator<Item = V>,
|
||||||
|
{
|
||||||
|
entries.into_iter().fold(self, |f, entry| f.entry(&entry))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes off the set.
|
||||||
|
pub fn finish(mut self) {
|
||||||
|
// remove the last semicolon
|
||||||
|
if let Some(syn::Stmt::Semi(entry, _)) = self.set.stmts.pop() {
|
||||||
|
self.set.stmts.push(syn::Stmt::Expr(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.formatter.write_expr(syn::ExprBlock {
|
||||||
|
attrs: vec![],
|
||||||
|
label: None,
|
||||||
|
block: self.set,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
77
dbg-pls/src/debug_struct.rs
Normal file
77
dbg-pls/src/debug_struct.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
use syn::__private::Span;
|
||||||
|
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
/// A helper designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for structs.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo {
|
||||||
|
/// bar: i32,
|
||||||
|
/// baz: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_struct("Foo")
|
||||||
|
/// .field("bar", &self.bar)
|
||||||
|
/// .field("baz", &self.baz)
|
||||||
|
/// .finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// let value = Foo {
|
||||||
|
/// bar: 10,
|
||||||
|
/// baz: "Hello World".to_string(),
|
||||||
|
/// };
|
||||||
|
/// assert_eq!(
|
||||||
|
/// format!("{}", pretty(&value)),
|
||||||
|
/// "Foo { bar: 10, baz: \"Hello World\" }",
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
pub struct DebugStruct<'a> {
|
||||||
|
formatter: Formatter<'a>,
|
||||||
|
expr: syn::ExprStruct,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DebugStruct<'a> {
|
||||||
|
pub(crate) fn new(formatter: Formatter<'a>, name: &str) -> Self {
|
||||||
|
DebugStruct {
|
||||||
|
formatter,
|
||||||
|
expr: syn::ExprStruct {
|
||||||
|
attrs: vec![],
|
||||||
|
path: syn::Ident::new(name, Span::call_site()).into(),
|
||||||
|
brace_token: syn::token::Brace::default(),
|
||||||
|
fields: syn::punctuated::Punctuated::new(),
|
||||||
|
dot2_token: None,
|
||||||
|
rest: None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the field to the struct output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn field(mut self, name: &str, value: &dyn DebugPls) -> Self {
|
||||||
|
self.expr.fields.push(syn::FieldValue {
|
||||||
|
expr: Formatter::process(value),
|
||||||
|
attrs: vec![],
|
||||||
|
member: syn::Member::Named(syn::Ident::new(name, Span::call_site())),
|
||||||
|
colon_token: Some(syn::token::Colon::default()),
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes off the struct.
|
||||||
|
pub fn finish(self) {
|
||||||
|
self.formatter.write_expr(self.expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes off the struct with `..`.
|
||||||
|
pub fn finish_non_exhaustive(mut self) {
|
||||||
|
self.expr.dot2_token = Some(syn::token::Dot2::default());
|
||||||
|
self.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
53
dbg-pls/src/debug_tuple.rs
Normal file
53
dbg-pls/src/debug_tuple.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
/// A helper designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for tuples.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo(i32, String);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_tuple()
|
||||||
|
/// .field(&self.0)
|
||||||
|
/// .field(&self.1)
|
||||||
|
/// .finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let value = Foo(10, "Hello".to_string());
|
||||||
|
/// assert_eq!(format!("{}", pretty(&value)), "(10, \"Hello\")");
|
||||||
|
/// ```
|
||||||
|
pub struct DebugTuple<'a> {
|
||||||
|
formatter: Formatter<'a>,
|
||||||
|
expr: syn::ExprTuple,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DebugTuple<'a> {
|
||||||
|
pub(crate) fn new(formatter: Formatter<'a>) -> Self {
|
||||||
|
DebugTuple {
|
||||||
|
formatter,
|
||||||
|
expr: syn::ExprTuple {
|
||||||
|
attrs: vec![],
|
||||||
|
paren_token: syn::token::Paren::default(),
|
||||||
|
elems: syn::punctuated::Punctuated::new(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the field to the tuple output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn field(mut self, value: &dyn DebugPls) -> Self {
|
||||||
|
self.expr.elems.push(Formatter::process(value));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes off the tuple.
|
||||||
|
pub fn finish(self) {
|
||||||
|
self.formatter.write_expr(self.expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
dbg-pls/src/debug_tuple_struct.rs
Normal file
60
dbg-pls/src/debug_tuple_struct.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
use syn::__private::Span;
|
||||||
|
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
/// A helper designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for tuple structs.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo(i32, String);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_tuple_struct("Foo")
|
||||||
|
/// .field(&self.0)
|
||||||
|
/// .field(&self.1)
|
||||||
|
/// .finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let value = Foo(10, "Hello".to_string());
|
||||||
|
/// assert_eq!(format!("{}", pretty(&value)), "Foo(10, \"Hello\")");
|
||||||
|
/// ```
|
||||||
|
pub struct DebugTupleStruct<'a> {
|
||||||
|
formatter: Formatter<'a>,
|
||||||
|
expr: syn::ExprCall,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DebugTupleStruct<'a> {
|
||||||
|
pub(crate) fn new(formatter: Formatter<'a>, name: &str) -> Self {
|
||||||
|
DebugTupleStruct {
|
||||||
|
formatter,
|
||||||
|
expr: syn::ExprCall {
|
||||||
|
attrs: vec![],
|
||||||
|
func: Box::new(syn::Expr::Path(syn::ExprPath {
|
||||||
|
attrs: vec![],
|
||||||
|
qself: None,
|
||||||
|
path: syn::Ident::new(name, Span::call_site()).into(),
|
||||||
|
})),
|
||||||
|
paren_token: syn::token::Paren::default(),
|
||||||
|
args: syn::punctuated::Punctuated::new(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the field to the tuple struct output.
|
||||||
|
#[must_use]
|
||||||
|
pub fn field(mut self, value: &dyn DebugPls) -> Self {
|
||||||
|
self.expr.args.push(Formatter::process(value));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes off the tuple struct.
|
||||||
|
pub fn finish(self) {
|
||||||
|
self.formatter.write_expr(self.expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
dbg-pls/src/impls.rs
Normal file
2
dbg-pls/src/impls.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
mod syn_impls;
|
||||||
|
mod std;
|
||||||
162
dbg-pls/src/impls/std.rs
Normal file
162
dbg-pls/src/impls/std.rs
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
mod collections;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ops::ControlFlow,
|
||||||
|
rc::Rc,
|
||||||
|
sync::{Arc, Mutex, MutexGuard, TryLockError},
|
||||||
|
task::Poll,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
use syn::__private::Span;
|
||||||
|
|
||||||
|
impl<T: ?Sized + DebugPls> DebugPls for Box<T> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
DebugPls::fmt(&**self, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, D: DebugPls + ?Sized> DebugPls for &'a D {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
D::fmt(self, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + DebugPls> DebugPls for Rc<T> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
DebugPls::fmt(&**self, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + DebugPls> DebugPls for Arc<T> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
DebugPls::fmt(&**self, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + DebugPls> DebugPls for MutexGuard<'_, T> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
DebugPls::fmt(&**self, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + DebugPls> DebugPls for Mutex<T> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
let d = f.debug_struct("Mutex");
|
||||||
|
match self.try_lock() {
|
||||||
|
Ok(guard) => d.field("data", &&*guard),
|
||||||
|
Err(TryLockError::Poisoned(err)) => d.field("data", &&**err.get_ref()),
|
||||||
|
Err(TryLockError::WouldBlock) => d.field("data", &"<locked>"),
|
||||||
|
}
|
||||||
|
.field("poisoned", &self.is_poisoned())
|
||||||
|
.finish_non_exhaustive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! debug_integers {
|
||||||
|
($($T:ident)*) => {$(
|
||||||
|
impl DebugPls for $T {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
let mut buf = itoa::Buffer::new();
|
||||||
|
f.write_expr(syn::ExprLit {
|
||||||
|
attrs: vec![],
|
||||||
|
lit: syn::LitInt::new(buf.format(*self), Span::call_site()).into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*};
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_integers! {
|
||||||
|
i8 i16 i32 i64 i128 isize
|
||||||
|
u8 u16 u32 u64 u128 usize
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! debug_floats {
|
||||||
|
($ty:ident) => {
|
||||||
|
impl DebugPls for $ty {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
let mut buf = ryu::Buffer::new();
|
||||||
|
f.write_expr(syn::ExprLit {
|
||||||
|
attrs: vec![],
|
||||||
|
lit: syn::LitFloat::new(buf.format(*self), Span::call_site()).into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_floats! { f32 }
|
||||||
|
debug_floats! { f64 }
|
||||||
|
|
||||||
|
impl DebugPls for bool {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
match self {
|
||||||
|
true => f.debug_ident("true"),
|
||||||
|
false => f.debug_ident("false"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DebugPls> DebugPls for [D] {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_list().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DebugPls, const N: usize> DebugPls for [D; N] {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_list().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPls for str {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.write_expr(syn::ExprLit {
|
||||||
|
attrs: vec![],
|
||||||
|
lit: syn::LitStr::new(self, Span::call_site()).into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPls for String {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
DebugPls::fmt(self.as_str(), f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: DebugPls, E: DebugPls> DebugPls for Result<T, E> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
match self {
|
||||||
|
Ok(t) => f.debug_tuple_struct("Ok").field(t).finish(),
|
||||||
|
Err(e) => f.debug_tuple_struct("Err").field(e).finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: DebugPls, C: DebugPls> DebugPls for ControlFlow<B, C> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
match self {
|
||||||
|
ControlFlow::Break(b) => f.debug_tuple_struct("Break").field(b).finish(),
|
||||||
|
ControlFlow::Continue(c) => f.debug_tuple_struct("Continue").field(c).finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: DebugPls> DebugPls for Option<T> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
match self {
|
||||||
|
Some(t) => f.debug_tuple_struct("Some").field(t).finish(),
|
||||||
|
None => f.debug_ident("None"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: DebugPls> DebugPls for Poll<T> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
match self {
|
||||||
|
Poll::Ready(t) => f.debug_tuple_struct("Ready").field(t).finish(),
|
||||||
|
Poll::Pending => f.debug_ident("Pending"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
dbg-pls/src/impls/std/collections.rs
Normal file
51
dbg-pls/src/impls/std/collections.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque, LinkedList, BinaryHeap};
|
||||||
|
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
impl<K: DebugPls, V: DebugPls, S: ::std::hash::BuildHasher> DebugPls for HashMap<K, V, S> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_map().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: DebugPls, V: DebugPls> DebugPls for BTreeMap<K, V> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_map().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: DebugPls, S: ::std::hash::BuildHasher> DebugPls for HashSet<V, S> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_set().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: DebugPls> DebugPls for BTreeSet<V> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_set().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DebugPls> DebugPls for Vec<D> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_list().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DebugPls> DebugPls for VecDeque<D> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_list().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DebugPls> DebugPls for LinkedList<D> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_list().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: DebugPls> DebugPls for BinaryHeap<D> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_list().entries(self).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
155
dbg-pls/src/impls/syn_impls.rs
Normal file
155
dbg-pls/src/impls/syn_impls.rs
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
use syn::{
|
||||||
|
punctuated::{Pair, Punctuated},
|
||||||
|
token::{Bracket, Comma},
|
||||||
|
Attribute, Expr, ExprArray, ExprLit, Lit, LitInt, LitStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
impl DebugPls for Expr {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
match self {
|
||||||
|
Expr::Array(val0) => f.debug_tuple_struct("Array").field(val0).finish(),
|
||||||
|
// Expr::Assign(val0) => f.debug_tuple_struct("Assign").field(val0).finish(),
|
||||||
|
// Expr::AssignOp(val0) => f.debug_tuple_struct("AssignOp").field(val0).finish(),
|
||||||
|
// Expr::Async(val0) => f.debug_tuple_struct("Async").field(val0).finish(),
|
||||||
|
// Expr::Await(val0) => f.debug_tuple_struct("Await").field(val0).finish(),
|
||||||
|
// Expr::Binary(val0) => f.debug_tuple_struct("Binary").field(val0).finish(),
|
||||||
|
// Expr::Block(val0) => f.debug_tuple_struct("Block").field(val0).finish(),
|
||||||
|
// Expr::Box(val0) => f.debug_tuple_struct("Box").field(val0).finish(),
|
||||||
|
// Expr::Break(val0) => f.debug_tuple_struct("Break").field(val0).finish(),
|
||||||
|
// Expr::Call(val0) => f.debug_tuple_struct("Call").field(val0).finish(),
|
||||||
|
// Expr::Cast(val0) => f.debug_tuple_struct("Cast").field(val0).finish(),
|
||||||
|
// Expr::Closure(val0) => f.debug_tuple_struct("Closure").field(val0).finish(),
|
||||||
|
// Expr::Continue(val0) => f.debug_tuple_struct("Continue").field(val0).finish(),
|
||||||
|
// Expr::Field(val0) => f.debug_tuple_struct("Field").field(val0).finish(),
|
||||||
|
// Expr::ForLoop(val0) => f.debug_tuple_struct("ForLoop").field(val0).finish(),
|
||||||
|
// Expr::Group(val0) => f.debug_tuple_struct("Group").field(val0).finish(),
|
||||||
|
// Expr::If(val0) => f.debug_tuple_struct("If").field(val0).finish(),
|
||||||
|
// Expr::Index(val0) => f.debug_tuple_struct("Index").field(val0).finish(),
|
||||||
|
// Expr::Let(val0) => f.debug_tuple_struct("Let").field(val0).finish(),
|
||||||
|
Expr::Lit(val0) => f.debug_tuple_struct("Lit").field(val0).finish(),
|
||||||
|
// Expr::Loop(val0) => f.debug_tuple_struct("Loop").field(val0).finish(),
|
||||||
|
// Expr::Macro(val0) => f.debug_tuple_struct("Macro").field(val0).finish(),
|
||||||
|
// Expr::Match(val0) => f.debug_tuple_struct("Match").field(val0).finish(),
|
||||||
|
// Expr::MethodCall(val0) => f.debug_tuple_struct("MethodCall").field(val0).finish(),
|
||||||
|
// Expr::Paren(val0) => f.debug_tuple_struct("Paren").field(val0).finish(),
|
||||||
|
// Expr::Path(val0) => f.debug_tuple_struct("Path").field(val0).finish(),
|
||||||
|
// Expr::Range(val0) => f.debug_tuple_struct("Range").field(val0).finish(),
|
||||||
|
// Expr::Reference(val0) => f.debug_tuple_struct("Reference").field(val0).finish(),
|
||||||
|
// Expr::Repeat(val0) => f.debug_tuple_struct("Repeat").field(val0).finish(),
|
||||||
|
// Expr::Return(val0) => f.debug_tuple_struct("Return").field(val0).finish(),
|
||||||
|
// Expr::Struct(val0) => f.debug_tuple_struct("Struct").field(val0).finish(),
|
||||||
|
// Expr::Try(val0) => f.debug_tuple_struct("Try").field(val0).finish(),
|
||||||
|
// Expr::TryBlock(val0) => f.debug_tuple_struct("TryBlock").field(val0).finish(),
|
||||||
|
// Expr::Tuple(val0) => f.debug_tuple_struct("Tuple").field(val0).finish(),
|
||||||
|
// Expr::Type(val0) => f.debug_tuple_struct("Type").field(val0).finish(),
|
||||||
|
// Expr::Unary(val0) => f.debug_tuple_struct("Unary").field(val0).finish(),
|
||||||
|
// Expr::Unsafe(val0) => f.debug_tuple_struct("Unsafe").field(val0).finish(),
|
||||||
|
// Expr::Verbatim(val0) => f.debug_tuple_struct("Verbatim").field(val0).finish(),
|
||||||
|
// Expr::While(val0) => f.debug_tuple_struct("While").field(val0).finish(),
|
||||||
|
// Expr::Yield(val0) => f.debug_tuple_struct("Yield").field(val0).finish(),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPls for ExprArray {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_struct("ExprArray")
|
||||||
|
.field("attrs", &self.attrs)
|
||||||
|
.field("bracket_token", &self.bracket_token)
|
||||||
|
.field("elems", &self.elems)
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPls for ExprLit {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_struct("ExprLit")
|
||||||
|
.field("attrs", &self.attrs)
|
||||||
|
.field("lit", &self.lit)
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPls for Lit {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
match self {
|
||||||
|
Lit::Str(v0) => f.debug_tuple_struct("Str").field(v0).finish(),
|
||||||
|
// Lit::ByteStr(v0) => f.debug_tuple_struct("ByteStr").field(v0).finish(),
|
||||||
|
// Lit::Byte(v0) => f.debug_tuple_struct("Byte").field(v0).finish(),
|
||||||
|
// Lit::Char(v0) => f.debug_tuple_struct("Char").field(v0).finish(),
|
||||||
|
Lit::Int(v0) => f.debug_tuple_struct("Int").field(v0).finish(),
|
||||||
|
// Lit::Float(v0) => f.debug_tuple_struct("Float").field(v0).finish(),
|
||||||
|
// Lit::Bool(v0) => f.debug_tuple_struct("Bool").field(v0).finish(),
|
||||||
|
// Lit::Verbatim(v0) => f.debug_tuple_struct("Verbatim").field(v0).finish(),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPls for LitStr {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_struct("LitStr")
|
||||||
|
.field("value", &self.value())
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPls for LitInt {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_struct("LitInt")
|
||||||
|
.field("value", &self.base10_digits())
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPls for Attribute {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_struct("Attribute").finish_non_exhaustive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: DebugPls, P: DebugPls> DebugPls for Punctuated<T, P> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
self.pairs()
|
||||||
|
.fold(f.debug_list(), |f, pair| match pair {
|
||||||
|
Pair::Punctuated(t, p) => f.entry(t).entry(p),
|
||||||
|
Pair::End(t) => f.entry(t),
|
||||||
|
})
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! debug_units {
|
||||||
|
($($T:ident),*) => {$(
|
||||||
|
impl DebugPls for $T {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_ident(stringify!($T))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*};
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_units![Comma, Bracket];
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::color;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pretty_colors() {
|
||||||
|
let code = r#"
|
||||||
|
[
|
||||||
|
"Hello, World! I am a long string",
|
||||||
|
420,
|
||||||
|
"Wait, you can't mix and match types in arrays, is this python?",
|
||||||
|
69,
|
||||||
|
"Nice."
|
||||||
|
]
|
||||||
|
"#;
|
||||||
|
let expr: syn::Expr = syn::parse_str(code).unwrap();
|
||||||
|
println!("{}", color(&expr));
|
||||||
|
}
|
||||||
|
}
|
||||||
707
dbg-pls/src/lib.rs
Normal file
707
dbg-pls/src/lib.rs
Normal file
|
|
@ -0,0 +1,707 @@
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
//! Syntax aware debug printing.
|
||||||
|
//!
|
||||||
|
//! Makes use of `syn` and `prettyplease` in order to provide the most
|
||||||
|
//! canonincal rust debug lines as possible, quickly.
|
||||||
|
//!
|
||||||
|
//! # Example usage
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use dbg_pls::{pretty, DebugPls};
|
||||||
|
//!
|
||||||
|
//! #[derive(DebugPls, Copy, Clone)]
|
||||||
|
//! pub struct Demo {
|
||||||
|
//! foo: i32,
|
||||||
|
//! bar: &'static str,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! let mut val = [Demo { foo: 5, bar: "hello" }; 10];
|
||||||
|
//! val[6].bar = "Hello, world! I am a very long string";
|
||||||
|
//!
|
||||||
|
//! let output = format!("{}", pretty(&val));
|
||||||
|
//! let expected = r#"[
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "Hello, world! I am a very long string",
|
||||||
|
//! },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! ]"#;
|
||||||
|
//!
|
||||||
|
//! assert_eq!(output, expected);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Example with highlighting
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use dbg_pls::{color, DebugPls};
|
||||||
|
//!
|
||||||
|
//! #[derive(DebugPls, Copy, Clone)]
|
||||||
|
//! pub struct Demo {
|
||||||
|
//! foo: i32,
|
||||||
|
//! bar: &'static str,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! let mut val = [Demo { foo: 5, bar: "hello" }; 10];
|
||||||
|
//! val[6].bar = "Hello, world! I am a very long string";
|
||||||
|
//!
|
||||||
|
//! println!("{}", color(&val));
|
||||||
|
//! ```
|
||||||
|
//! Outputs:
|
||||||
|
//!
|
||||||
|
//! 
|
||||||
|
//!
|
||||||
|
//! # Why
|
||||||
|
//!
|
||||||
|
//! For the sake of demonstration, let's take a look at the snippet from above.
|
||||||
|
//! It provides an array of 10 `Demo` structs. You could imagine this to
|
||||||
|
//! be representative of a complex deep struct.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! #[derive(Debug, Copy, Clone)]
|
||||||
|
//! pub struct Demo {
|
||||||
|
//! foo: i32,
|
||||||
|
//! bar: &'static str,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! let mut val = [Demo { foo: 5, bar: "hello" }; 10];
|
||||||
|
//! val[6].bar = "Hello, world! I am a very long string";
|
||||||
|
//!
|
||||||
|
//! println!("{:?}", val);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! This outputs
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! [Demo { foo: 5, bar: "hello" }, Demo { foo: 5, bar: "hello" }, Demo { foo: 5, bar: "hello" }, Demo { foo: 5, bar: "hello" }, Demo { foo: 5, bar: "hello" }, Demo { foo: 5, bar: "hello" }, Demo { foo: 5, bar: "Hello, world! I am a very long string" }, Demo { foo: 5, bar: "hello" }, Demo { foo: 5, bar: "hello" }, Demo { foo: 5, bar: "hello" }]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Switching to the alternative output format `{:#?}` you get the following
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! [
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "Hello, world! I am a very long string",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "hello",
|
||||||
|
//! },
|
||||||
|
//! ]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Both of these are very unweildy to read through. Compare that to our `pretty` formatting:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use dbg_pls::pretty;
|
||||||
|
//! # let val = 0;
|
||||||
|
//! println!("{}", pretty(&val));
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! And you will see
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! [
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo {
|
||||||
|
//! foo: 5,
|
||||||
|
//! bar: "Hello, world! I am a very long string",
|
||||||
|
//! },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! Demo { foo: 5, bar: "hello" },
|
||||||
|
//! ]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # How it works
|
||||||
|
//!
|
||||||
|
//! All [`DebugPls`] implementations are forced to output only valid
|
||||||
|
//! [`syn::Expr`] values. These are then formatted using [`prettyplease::unparse`].
|
||||||
|
//! Finally, it uses [`syntect`] to provide syntax highlighting, with theme provided by
|
||||||
|
//! <https://github.com/jonschlinkert/sublime-monokai-extended>
|
||||||
|
|
||||||
|
use syn::__private::{Span, TokenStream2};
|
||||||
|
|
||||||
|
mod impls;
|
||||||
|
|
||||||
|
mod debug_list;
|
||||||
|
mod debug_map;
|
||||||
|
mod debug_set;
|
||||||
|
mod debug_struct;
|
||||||
|
mod debug_tuple;
|
||||||
|
mod debug_tuple_struct;
|
||||||
|
pub use debug_list::DebugList;
|
||||||
|
pub use debug_map::DebugMap;
|
||||||
|
pub use debug_set::DebugSet;
|
||||||
|
pub use debug_struct::DebugStruct;
|
||||||
|
pub use debug_tuple::DebugTuple;
|
||||||
|
pub use debug_tuple_struct::DebugTupleStruct;
|
||||||
|
|
||||||
|
#[cfg(feature = "pretty")]
|
||||||
|
mod pretty;
|
||||||
|
#[cfg(feature = "pretty")]
|
||||||
|
pub use pretty::pretty;
|
||||||
|
|
||||||
|
#[cfg(feature = "colors")]
|
||||||
|
mod colors;
|
||||||
|
#[cfg(feature = "colors")]
|
||||||
|
pub use colors::color;
|
||||||
|
|
||||||
|
#[cfg(feature = "derive")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||||
|
pub use dbg_pls_derive::DebugPls;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod __private {
|
||||||
|
#[cfg(feature = "pretty")]
|
||||||
|
pub use crate::pretty::Str as PrettyStr;
|
||||||
|
#[cfg(feature = "colors")]
|
||||||
|
pub use crate::colors::ColorStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Syntax aware pretty-printed debug formatting.
|
||||||
|
///
|
||||||
|
/// `DebugPls` should format the output in a programmer-facing, debugging context.
|
||||||
|
///
|
||||||
|
/// Generally speaking, you should just `derive` a `Debug` implementation.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Deriving an implementation:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use dbg_pls::{pretty, DebugPls};
|
||||||
|
/// #[derive(DebugPls)]
|
||||||
|
/// struct Point {
|
||||||
|
/// x: i32,
|
||||||
|
/// y: i32,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let origin = Point { x: 0, y: 0 };
|
||||||
|
///
|
||||||
|
/// assert_eq!(format!("The origin is: {}", pretty(&origin)), "The origin is: Point { x: 0, y: 0 }");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Manually implementing:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
/// struct Point {
|
||||||
|
/// x: i32,
|
||||||
|
/// y: i32,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Point {
|
||||||
|
/// fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
/// f.debug_struct("Point")
|
||||||
|
/// .field("x", &self.x)
|
||||||
|
/// .field("y", &self.y)
|
||||||
|
/// .finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let origin = Point { x: 0, y: 0 };
|
||||||
|
///
|
||||||
|
/// assert_eq!(format!("The origin is: {}", pretty(&origin)), "The origin is: Point { x: 0, y: 0 }");
|
||||||
|
/// ```
|
||||||
|
pub trait DebugPls {
|
||||||
|
/// Formats the value using the given formatter.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Position {
|
||||||
|
/// longitude: f32,
|
||||||
|
/// latitude: f32,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Position {
|
||||||
|
/// fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
/// f.debug_tuple()
|
||||||
|
/// .field(&self.longitude)
|
||||||
|
/// .field(&self.latitude)
|
||||||
|
/// .finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let position = Position { longitude: 1.987, latitude: 2.983 };
|
||||||
|
/// assert_eq!(format!("{}", pretty(&position)), "(1.987, 2.983)");
|
||||||
|
/// ```
|
||||||
|
fn fmt(&self, f: Formatter<'_>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tool for formatting, used within [`DebugPls`] implementations
|
||||||
|
pub struct Formatter<'a> {
|
||||||
|
expr: &'a mut syn::Expr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Formatter<'a> {
|
||||||
|
pub(crate) fn process(value: &dyn DebugPls) -> syn::Expr {
|
||||||
|
let mut expr = syn::Expr::Verbatim(TokenStream2::new());
|
||||||
|
value.fmt(Formatter { expr: &mut expr });
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes a wrap expression into the formatter.
|
||||||
|
/// This is typically reserved for more advanced uses
|
||||||
|
pub fn write_expr(self, expr: impl Into<syn::Expr>) {
|
||||||
|
*self.expr = expr.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`DebugStruct`] builder designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for structs.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo {
|
||||||
|
/// bar: i32,
|
||||||
|
/// baz: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_struct("Foo")
|
||||||
|
/// .field("bar", &self.bar)
|
||||||
|
/// .field("baz", &self.baz)
|
||||||
|
/// .finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// let value = Foo {
|
||||||
|
/// bar: 10,
|
||||||
|
/// baz: "Hello World".to_string(),
|
||||||
|
/// };
|
||||||
|
/// assert_eq!(
|
||||||
|
/// format!("{}", pretty(&value)),
|
||||||
|
/// "Foo { bar: 10, baz: \"Hello World\" }",
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
#[must_use]
|
||||||
|
pub fn debug_struct(self, name: &str) -> DebugStruct<'a> {
|
||||||
|
DebugStruct::new(self, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`DebugTuple`] builder designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for tuples.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo(i32, String);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_tuple()
|
||||||
|
/// .field(&self.0)
|
||||||
|
/// .field(&self.1)
|
||||||
|
/// .finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let value = Foo(10, "Hello".to_string());
|
||||||
|
/// assert_eq!(format!("{}", pretty(&value)), "(10, \"Hello\")");
|
||||||
|
/// ```
|
||||||
|
#[must_use]
|
||||||
|
pub fn debug_tuple(self) -> DebugTuple<'a> {
|
||||||
|
DebugTuple::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`DebugTupleStruct`] builder designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for tuple structs.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo(i32, String);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_tuple_struct("Foo")
|
||||||
|
/// .field(&self.0)
|
||||||
|
/// .field(&self.1)
|
||||||
|
/// .finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let value = Foo(10, "Hello".to_string());
|
||||||
|
/// assert_eq!(format!("{}", pretty(&value)), "Foo(10, \"Hello\")");
|
||||||
|
/// ```
|
||||||
|
#[must_use]
|
||||||
|
pub fn debug_tuple_struct(self, name: &str) -> DebugTupleStruct<'a> {
|
||||||
|
DebugTupleStruct::new(self, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`DebugList`] builder designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for list-like structures.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo(Vec<i32>);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
/// f.debug_list().entries(&self.0).finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let value = Foo(vec![10, 11]);
|
||||||
|
/// assert_eq!(format!("{}", pretty(&value)), "[10, 11]");
|
||||||
|
/// ```
|
||||||
|
#[must_use]
|
||||||
|
pub fn debug_list(self) -> DebugList<'a> {
|
||||||
|
DebugList::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`DebugMap`] builder designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for maps.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
/// use std::collections::BTreeMap;
|
||||||
|
///
|
||||||
|
/// struct Foo(BTreeMap<String, i32>);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_map().entries(&self.0).finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// let mut value = Foo(BTreeMap::from([
|
||||||
|
/// ("Hello".to_string(), 5),
|
||||||
|
/// ("World".to_string(), 10),
|
||||||
|
/// ]));
|
||||||
|
/// assert_eq!(
|
||||||
|
/// format!("{}", pretty(&value)),
|
||||||
|
/// "{
|
||||||
|
/// [\"Hello\"] = 5;
|
||||||
|
/// [\"World\"] = 10;
|
||||||
|
/// }",
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
#[must_use]
|
||||||
|
pub fn debug_map(self) -> DebugMap<'a> {
|
||||||
|
DebugMap::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`DebugSet`] builder designed to assist with creation of
|
||||||
|
/// [`DebugPls`] implementations for sets.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
/// use std::collections::BTreeSet;
|
||||||
|
///
|
||||||
|
/// struct Foo(BTreeSet<String>);
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter) {
|
||||||
|
/// f.debug_set().entries(&self.0).finish()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// let mut value = Foo(BTreeSet::from([
|
||||||
|
/// "Hello".to_string(),
|
||||||
|
/// "World".to_string(),
|
||||||
|
/// ]));
|
||||||
|
/// assert_eq!(
|
||||||
|
/// format!("{}", pretty(&value)),
|
||||||
|
/// "{
|
||||||
|
/// \"Hello\";
|
||||||
|
/// \"World\"
|
||||||
|
/// }",
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
#[must_use]
|
||||||
|
pub fn debug_set(self) -> DebugSet<'a> {
|
||||||
|
DebugSet::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes an identifier into the formatter. Useful for unit structs/variants
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use dbg_pls::{pretty, DebugPls, Formatter};
|
||||||
|
///
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// impl DebugPls for Foo {
|
||||||
|
/// fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
/// f.debug_ident("Foo");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(format!("{}", pretty(&Foo)), "Foo");
|
||||||
|
/// ```
|
||||||
|
pub fn debug_ident(self, name: &str) {
|
||||||
|
let path: syn::Path = syn::Ident::new(name, Span::call_site()).into();
|
||||||
|
self.write_expr(syn::ExprPath {
|
||||||
|
attrs: vec![],
|
||||||
|
qself: None,
|
||||||
|
path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(DebugPls, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
#[dbg_pls(crate = "crate")]
|
||||||
|
pub struct Demo {
|
||||||
|
foo: i32,
|
||||||
|
bar: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_struct() {
|
||||||
|
let val = Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "hello",
|
||||||
|
};
|
||||||
|
assert_eq!(pretty(&val).to_string(), r#"Demo { foo: 5, bar: "hello" }"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_struct_big() {
|
||||||
|
let val = Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "Hello, world! I am a very long string",
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
pretty(&val).to_string(),
|
||||||
|
r#"Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "Hello, world! I am a very long string",
|
||||||
|
}"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_nested_struct() {
|
||||||
|
let mut val = [Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "hello",
|
||||||
|
}; 10];
|
||||||
|
val[6].bar = "Hello, world! I am a very long string";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pretty(&val).to_string(),
|
||||||
|
r#"[
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "Hello, world! I am a very long string",
|
||||||
|
},
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
Demo { foo: 5, bar: "hello" },
|
||||||
|
]"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_small_set() {
|
||||||
|
let set = BTreeSet::from([420, 69]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pretty(&set).to_string(),
|
||||||
|
r#"{
|
||||||
|
69;
|
||||||
|
420
|
||||||
|
}"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_nested_set() {
|
||||||
|
let set = BTreeSet::from([
|
||||||
|
Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "hello",
|
||||||
|
},
|
||||||
|
Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "Hello, world! I am a very long string",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pretty(&set).to_string(),
|
||||||
|
r#"{
|
||||||
|
Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "Hello, world! I am a very long string",
|
||||||
|
};
|
||||||
|
Demo { foo: 5, bar: "hello" }
|
||||||
|
}"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_map() {
|
||||||
|
let map = BTreeMap::from([("hello", 60), ("Hello, world! I am a very long string", 12)]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pretty(&map).to_string(),
|
||||||
|
r#"{
|
||||||
|
["Hello, world! I am a very long string"] = 12;
|
||||||
|
["hello"] = 60;
|
||||||
|
}"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_nested_map() {
|
||||||
|
let map = BTreeMap::from([
|
||||||
|
(
|
||||||
|
Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "hello",
|
||||||
|
},
|
||||||
|
60,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "Hello, world! I am a very long string",
|
||||||
|
},
|
||||||
|
12,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pretty(&map).to_string(),
|
||||||
|
r#"{
|
||||||
|
[
|
||||||
|
Demo {
|
||||||
|
foo: 5,
|
||||||
|
bar: "Hello, world! I am a very long string",
|
||||||
|
},
|
||||||
|
] = 12;
|
||||||
|
[Demo { foo: 5, bar: "hello" }] = 60;
|
||||||
|
}"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DebugPls)]
|
||||||
|
#[dbg_pls(crate = "crate")]
|
||||||
|
pub struct Generic<T> {
|
||||||
|
arg: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_generic() {
|
||||||
|
let generic = Generic { arg: "string" };
|
||||||
|
assert_eq!(pretty(&generic).to_string(), r#"Generic { arg: "string" }"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DebugPls)]
|
||||||
|
#[dbg_pls(crate = "crate")]
|
||||||
|
pub struct Generic2<T> {
|
||||||
|
arg: Wrapped<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Wrapped<T>(T);
|
||||||
|
impl<T> DebugPls for Wrapped<T> {
|
||||||
|
fn fmt(&self, f: Formatter<'_>) {
|
||||||
|
f.debug_struct("Wrapped").finish_non_exhaustive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NonDebug;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_generic2() {
|
||||||
|
let generic = Generic { arg: Wrapped(NonDebug) };
|
||||||
|
assert_eq!(pretty(&generic).to_string(), r#"Generic { arg: Wrapped {} }"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DebugPls)]
|
||||||
|
#[dbg_pls(crate = "crate")]
|
||||||
|
pub enum Option2<T> {
|
||||||
|
Some(T),
|
||||||
|
None,
|
||||||
|
Wtf { foo: i32 }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn debug_enum_generic() {
|
||||||
|
let some = Option2::Some(42);
|
||||||
|
assert_eq!(pretty(&some).to_string(), r#"Some(42)"#);
|
||||||
|
|
||||||
|
let none = Option2::<i32>::None;
|
||||||
|
assert_eq!(pretty(&none).to_string(), r#"None"#);
|
||||||
|
|
||||||
|
let wtf = Option2::<i32>::Wtf { foo: 42 };
|
||||||
|
assert_eq!(pretty(&wtf).to_string(), r#"Wtf { foo: 42 }"#);
|
||||||
|
}
|
||||||
|
}
|
||||||
149
dbg-pls/src/pretty.rs
Normal file
149
dbg-pls/src/pretty.rs
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
use syn::__private::Span;
|
||||||
|
|
||||||
|
use crate::{DebugPls, Formatter};
|
||||||
|
|
||||||
|
pub(crate) fn pretty_string(expr: syn::Expr) -> String {
|
||||||
|
// unparse requires a `syn::File`, so we are forced to wrap
|
||||||
|
// our expression in some junk. This is equivalent to
|
||||||
|
// ```rust
|
||||||
|
// const _: () = {
|
||||||
|
// #expr
|
||||||
|
// };
|
||||||
|
// ```
|
||||||
|
let file = syn::File {
|
||||||
|
shebang: None,
|
||||||
|
attrs: vec![],
|
||||||
|
items: vec![syn::Item::Const(syn::ItemConst {
|
||||||
|
expr: Box::new(expr),
|
||||||
|
// junk...
|
||||||
|
attrs: vec![],
|
||||||
|
vis: syn::Visibility::Inherited,
|
||||||
|
const_token: syn::token::Const::default(),
|
||||||
|
ident: syn::Ident::new("_", Span::call_site()),
|
||||||
|
colon_token: syn::token::Colon::default(),
|
||||||
|
ty: Box::new(syn::Type::Tuple(syn::TypeTuple {
|
||||||
|
paren_token: syn::token::Paren::default(),
|
||||||
|
elems: syn::punctuated::Punctuated::default(),
|
||||||
|
})),
|
||||||
|
eq_token: syn::token::Eq::default(),
|
||||||
|
semi_token: syn::token::Semi::default(),
|
||||||
|
})],
|
||||||
|
};
|
||||||
|
let output = prettyplease::unparse(&file);
|
||||||
|
|
||||||
|
// strip out the junk
|
||||||
|
let output = &output[14..];
|
||||||
|
let output = &output[..output.len() - 2];
|
||||||
|
textwrap::dedent(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation detail for the `pretty!` macro
|
||||||
|
pub struct Str<'a>(pub &'a str);
|
||||||
|
|
||||||
|
impl<'a> std::fmt::Display for Str<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let expr = syn::parse_str(self.0).map_err(|_| std::fmt::Error)?;
|
||||||
|
f.write_str(&pretty_string(expr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Pretty<'a>(&'a dyn DebugPls);
|
||||||
|
|
||||||
|
impl<'a> std::fmt::Debug for Pretty<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(&pretty_string(Formatter::process(self.0)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::fmt::Display for Pretty<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Debug::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "pretty")))]
|
||||||
|
/// Wraps a [`Debug`] type into a [`std::fmt::Debug`] type for use in regular [`format!`]
|
||||||
|
pub fn pretty(value: &impl DebugPls) -> impl std::fmt::Debug + std::fmt::Display + '_ {
|
||||||
|
Pretty(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "pretty")))]
|
||||||
|
#[macro_export]
|
||||||
|
/// Prints and returns the value of a given expression for quick and dirty
|
||||||
|
/// debugging. Same as [`std::dbg`]
|
||||||
|
///
|
||||||
|
/// An example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use dbg_pls::pretty;
|
||||||
|
/// let a = 2;
|
||||||
|
/// let b = pretty!(a * 2) + 1;
|
||||||
|
/// // ^-- prints: [src/main.rs:2] a * 2 = 4
|
||||||
|
/// assert_eq!(b, 5);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The macro works by using the [`DebugPls`] implementation of the type of
|
||||||
|
/// the given expression to print the value to [stderr] along with the
|
||||||
|
/// source location of the macro invocation as well as the source code
|
||||||
|
/// of the expression.
|
||||||
|
///
|
||||||
|
/// Invoking the macro on an expression moves and takes ownership of it
|
||||||
|
/// before returning the evaluated expression unchanged. If the type
|
||||||
|
/// of the expression does not implement `Copy` and you don't want
|
||||||
|
/// to give up ownership, you can instead borrow with `pretty!(&expr)`
|
||||||
|
/// for some expression `expr`.
|
||||||
|
///
|
||||||
|
/// The `pretty!` macro works exactly the same in release builds.
|
||||||
|
/// This is useful when debugging issues that only occur in release
|
||||||
|
/// builds or when debugging in release mode is significantly faster.
|
||||||
|
///
|
||||||
|
/// Note that the macro is intended as a debugging tool and therefore you
|
||||||
|
/// should avoid having uses of it in version control for long periods
|
||||||
|
/// (other than in tests and similar).
|
||||||
|
/// Debug output from production code is better done with other facilities
|
||||||
|
/// such as the [`debug!`] macro from the [`log`] crate.
|
||||||
|
///
|
||||||
|
/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
|
||||||
|
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
|
||||||
|
/// [`log`]: https://crates.io/crates/log
|
||||||
|
macro_rules! pretty {
|
||||||
|
() => {
|
||||||
|
::std::eprintln!("[{}:{}]", ::std::file!(), ::std::line!())
|
||||||
|
};
|
||||||
|
($val:expr $(,)?) => {
|
||||||
|
match $val {
|
||||||
|
tmp => {
|
||||||
|
::std::eprintln!(
|
||||||
|
"[{}:{}] {} => {}",
|
||||||
|
::std::file!(),
|
||||||
|
::std::line!(),
|
||||||
|
$crate::__private::PrettyStr(::std::stringify!($val)),
|
||||||
|
$crate::pretty(&tmp)
|
||||||
|
);
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($($val:expr),+ $(,)?) => {
|
||||||
|
($($crate::pretty!($val)),+,)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::pretty;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pretty_macro() {
|
||||||
|
let map = pretty! {
|
||||||
|
HashMap::from([
|
||||||
|
("hello", 1),
|
||||||
|
("world", 2),
|
||||||
|
])
|
||||||
|
};
|
||||||
|
// map is moved through properly
|
||||||
|
assert_eq!(map, HashMap::from([("hello", 1), ("world", 2),]));
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/lib.rs
26
src/lib.rs
|
|
@ -3,20 +3,36 @@ pub fn foo(parent: Parent<'_>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn requires_parent_fulfill_trait(_: impl dbg_pls::DebugPls) {}
|
pub fn requires_parent_fulfill_trait(_: impl dbg_pls::DebugPls) {}
|
||||||
|
|
||||||
#[derive(dbg_pls::DebugPls)]
|
|
||||||
pub enum Parent<'a> {
|
pub enum Parent<'a> {
|
||||||
A(&'a A<'a>),
|
A(&'a A<'a>),
|
||||||
B(&'a B<'a>),
|
B(&'a B<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> dbg_pls::DebugPls for Parent<'a>
|
||||||
#[derive(dbg_pls::DebugPls)]
|
where
|
||||||
|
&'a A<'a>: dbg_pls::DebugPls,
|
||||||
|
&'a B<'a>: dbg_pls::DebugPls,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: dbg_pls::Formatter<'_>) {}
|
||||||
|
}
|
||||||
pub struct A<'a> {
|
pub struct A<'a> {
|
||||||
parent: Parent<'a>,
|
parent: Parent<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(dbg_pls::DebugPls)]
|
impl<'a> dbg_pls::DebugPls for A<'a>
|
||||||
|
where
|
||||||
|
Parent<'a>: dbg_pls::DebugPls,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: dbg_pls::Formatter<'_>) {}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct B<'a> {
|
pub struct B<'a> {
|
||||||
parent: Parent<'a>,
|
parent: Parent<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> dbg_pls::DebugPls for B<'a>
|
||||||
|
where
|
||||||
|
Parent<'a>: dbg_pls::DebugPls,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: dbg_pls::Formatter<'_>) {}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue