From 4c8b913a4a088d578216f055b3e53f4f50ab47b5 Mon Sep 17 00:00:00 2001 From: Zack Slayton Date: Fri, 10 Jan 2025 09:46:27 -0500 Subject: [PATCH] Shows e-exprs inside container literals, delimited END (#186) * Shows e-exprs inside container literals, delimited END * Improves rendering of eexps, arg groups, comments * Upgrade ion-rs to rc.11 --- Cargo.lock | 410 +++++------ Cargo.toml | 2 +- src/bin/ion/commands/generate/generator.rs | 2 +- src/bin/ion/commands/hash.rs | 11 +- src/bin/ion/commands/inspect.rs | 783 ++++++++++++--------- src/bin/ion/commands/mod.rs | 2 +- src/bin/ion/commands/schema/validate.rs | 2 +- src/bin/ion/commands/symtab/filter.rs | 2 +- src/bin/ion/hex_reader.rs | 12 +- src/bin/ion/output.rs | 4 +- 10 files changed, 662 insertions(+), 568 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c070b19..986e493f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,9 +34,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -49,43 +49,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arrayvec" @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "serde", @@ -223,9 +223,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.30" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ "jobserver", "libc", @@ -251,9 +251,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -304,22 +304,22 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "b95dca1b68188a08ca6af9d96a6576150f598824bdb528c1190460c2940a0b48" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "9ab52925392148efd3f7562f2136a81ffb778076bcc85727c6e020d6dd57cf15" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.2", + "clap_lex 0.7.4", "strsim 0.11.1", "terminal_size", ] @@ -335,31 +335,31 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "compact_str" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644" +checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" dependencies = [ "castaway", "cfg-if", @@ -386,9 +386,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -404,9 +404,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -423,9 +423,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -464,7 +464,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -475,7 +475,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -486,7 +486,7 @@ checksum = "4e018fccbeeb50ff26562ece792ed06659b9c2dae79ece77c4456bb10d9bf79b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -517,7 +517,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -527,7 +527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -592,12 +592,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -621,9 +621,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -691,7 +691,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -758,9 +758,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", - "bstr 1.10.0", + "bstr 1.11.3", "log", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax", ] @@ -793,9 +793,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hermit-abi" @@ -878,7 +878,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "same-file", "walkdir", "winapi-util", @@ -897,12 +897,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "serde", ] @@ -942,7 +942,7 @@ dependencies = [ "anyhow", "assert_cmd", "base64 0.21.7", - "clap 4.5.20", + "clap 4.5.25", "colored", "convert_case", "derive_builder", @@ -961,15 +961,15 @@ dependencies = [ "tempfile", "tera", "termcolor", - "thiserror", + "thiserror 1.0.69", "zstd", ] [[package]] name = "ion-rs" -version = "1.0.0-rc.10" +version = "1.0.0-rc.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3220cf0ff4ed8d316f359437847f8ce19d38ffdb2e588747efe4704aa00a97" +checksum = "1635de5984b66df8c9061125d02235c7e04c575d45cd93dbd85e14e307c06695" dependencies = [ "arrayvec", "base64 0.12.3", @@ -979,7 +979,6 @@ dependencies = [ "delegate", "digest 0.9.0", "ice_code", - "nom", "num-integer", "num-traits", "phf", @@ -987,7 +986,8 @@ dependencies = [ "serde", "serde_with", "smallvec", - "thiserror", + "thiserror 1.0.69", + "winnow", ] [[package]] @@ -1000,7 +1000,7 @@ dependencies = [ "ion-rs", "num-traits", "regex", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1029,9 +1029,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -1044,10 +1044,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1068,15 +1069,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linux-raw-sys" @@ -1086,9 +1087,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "log" @@ -1119,31 +1120,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -1222,20 +1207,20 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.10", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" dependencies = [ "pest", "pest_generator", @@ -1243,22 +1228,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "pest_meta" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" dependencies = [ "once_cell", "pest", @@ -1267,9 +1252,9 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros", "phf_shared", @@ -1277,9 +1262,9 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", "phf_shared", @@ -1287,9 +1272,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", "rand", @@ -1297,31 +1282,31 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1363,15 +1348,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", @@ -1379,18 +1364,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1436,13 +1421,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax", ] @@ -1454,9 +1439,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1497,9 +1482,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc_version" @@ -1512,12 +1497,12 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.27" +version = "0.37.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" dependencies = [ "bitflags 1.3.2", - "errno 0.3.9", + "errno 0.3.10", "io-lifetimes", "libc", "linux-raw-sys 0.3.8", @@ -1526,22 +1511,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ "bitflags 2.6.0", - "errno 0.3.9", + "errno 0.3.10", "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.52.0", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", ] [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" @@ -1560,37 +1545,37 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "itoa", "memchr", "ryu", @@ -1599,15 +1584,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_derive", "serde_json", @@ -1617,14 +1602,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] @@ -1682,9 +1667,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" @@ -1742,9 +1727,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -1760,7 +1745,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix 0.37.27", + "rustix 0.37.28", "windows-sys 0.45.0", ] @@ -1797,19 +1782,19 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ - "rustix 0.38.37", + "rustix 0.38.43", "windows-sys 0.59.0", ] [[package]] name = "termtree" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "textwrap" @@ -1819,29 +1804,49 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "a3ac7f54ca534db81081ef1c1e7f6ea8a3ef428d2fc069097c079443d24124d3" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.10", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9465d30713b56a37ede7185763c3492a91be2f5fa68d958c44e41ab9248beb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", ] [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -1862,9 +1867,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -1934,9 +1939,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" @@ -1989,9 +1994,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -2000,24 +2005,23 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2025,22 +2029,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "winapi" @@ -2100,15 +2104,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" @@ -2296,6 +2291,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" +dependencies = [ + "memchr", +] + [[package]] name = "yansi" version = "0.5.1" @@ -2320,7 +2324,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.95", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c1b293af..70e6f1c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ flate2 = "1.0" infer = "0.15.0" # ion-rs version must be pinned because we are using experimental features # See https://github.com/amazon-ion/ion-cli/issues/155 -ion-rs = { version = "1.0.0-rc.10", features = ["experimental", "experimental-ion-hash"] } +ion-rs = { version = "1.0.0-rc.11", features = ["experimental", "experimental-ion-hash"] } tempfile = "3.2.0" ion-schema = "0.15.0" lowcharts = "0.5.8" diff --git a/src/bin/ion/commands/generate/generator.rs b/src/bin/ion/commands/generate/generator.rs index bac52dd3..e43cb880 100644 --- a/src/bin/ion/commands/generate/generator.rs +++ b/src/bin/ion/commands/generate/generator.rs @@ -105,7 +105,7 @@ impl<'a> CodeGenerator<'a, JavaLanguage> { } } -impl<'a, L: Language + 'static> CodeGenerator<'a, L> { +impl CodeGenerator<'_, L> { /// A [tera] filter that converts given tera string value to [upper camel case]. /// Returns error if the given value is not a string. /// diff --git a/src/bin/ion/commands/hash.rs b/src/bin/ion/commands/hash.rs index 89844fa3..44265e2c 100644 --- a/src/bin/ion/commands/hash.rs +++ b/src/bin/ion/commands/hash.rs @@ -6,6 +6,7 @@ use ion_rs::ion_hash::IonHasher; use ion_rs::*; use sha2::{Sha256, Sha512}; use sha3::{Sha3_256, Sha3_512}; +use std::fmt; use std::io::Write; // Macro to eliminate repetitive code for each hash algorithm. @@ -109,8 +110,14 @@ impl IonCliCommand for HashCommand { for elem in reader.elements() { let elem = elem?; let digest = hasher.hash_it(&elem)?; - let digest_string: String = - digest.iter().map(|b| format!("{:02x?}", b)).collect(); + let digest_string = digest.iter().fold( + String::with_capacity(digest.len() * 2), + |mut string, byte| { + use fmt::Write; + write!(&mut string, "{:02x}", byte).expect("infallible"); + string + }, + ); output.write_all(digest_string.as_bytes())?; output.write_all("\n".as_bytes())?; } diff --git a/src/bin/ion/commands/inspect.rs b/src/bin/ion/commands/inspect.rs index e7bfb33a..fbf7260e 100644 --- a/src/bin/ion/commands/inspect.rs +++ b/src/bin/ion/commands/inspect.rs @@ -223,6 +223,8 @@ struct IonInspector<'a, 'b> { skip_complete: bool, limit_bytes: usize, hide_expansion: bool, + ephemeral_depth: usize, + line_has_comment: bool, // Text Ion writer for formatting scalar values text_writer: v1_0::RawTextWriter>, } @@ -236,10 +238,10 @@ const BYTES_PER_ROW: usize = 8; /// Friendly trait alias (by way of an empty extension) for a closure that takes an output reference /// and a value and writes a comment for that value. Returns `true` if it wrote a comment, `false` /// otherwise. -trait CommentFn<'x>: FnMut(&mut CommandOutput, LazyValue<'x, AnyEncoding>) -> Result {} +trait CommentFn<'x>: FnMut(&mut CommandOutput, ValueExpr<'x, AnyEncoding>) -> Result {} impl<'x, F> CommentFn<'x> for F where - F: FnMut(&mut CommandOutput, LazyValue<'x, AnyEncoding>) -> Result + F: FnMut(&mut CommandOutput, ValueExpr<'x, AnyEncoding>) -> Result { } @@ -248,6 +250,13 @@ fn no_comment<'x>() -> impl CommentFn<'x> { |_, _| Ok(false) } +/// Whether a struct's fields should be rendered with special treatment for LST fields. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum StructKind { + Standard, + SymbolTable, +} + impl<'a, 'b> IonInspector<'a, 'b> { fn new( out: &'a mut CommandOutput<'b>, @@ -263,7 +272,9 @@ impl<'a, 'b> IonInspector<'a, 'b> { hide_expansion, skip_complete: bytes_to_skip == 0, limit_bytes, + line_has_comment: false, text_writer, + ephemeral_depth: 0, }; Ok(inspector) } @@ -303,8 +314,6 @@ impl<'a, 'b> IonInspector<'a, 'b> { self.confirm_encoding_is_supported(raw_item.encoding())?; } - let is_last_item = matches!(expr, EndOfStream(_)); - match self.select_action( TOP_LEVEL_DEPTH, &mut has_printed_skip_message, @@ -320,14 +329,14 @@ impl<'a, 'b> IonInspector<'a, 'b> { InspectorAction::LimitReached => break, } - if !is_first_item && !is_last_item && !expr.is_ephemeral() { + if !is_first_item && !expr.is_ephemeral() { // If this item is neither the first nor last in the stream, print a row separator. write!(self.output, "{ROW_SEPARATOR}")?; } match expr { EExp(eexp) => { - self.inspect_eexp(0, eexp)?; + self.inspect_eexp(0, "", eexp)?; } SymbolTable(lazy_struct) => { self.inspect_symbol_table(lazy_struct)?; @@ -336,11 +345,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { self.inspect_value(0, "", lazy_sexp.as_value(), no_comment())?; } Value(lazy_value) => { - if lazy_value.expanded().is_ephemeral() && self.hide_expansion { - // The user has requested that we not show ephemeral values from macros. - } else { - self.inspect_value(0, "", lazy_value, no_comment())?; - } + self.inspect_value(0, "", lazy_value, no_comment())?; } VersionMarker(marker) => { self.confirm_encoding_is_supported(marker.encoding())?; @@ -393,29 +398,64 @@ impl<'a, 'b> IonInspector<'a, 'b> { /// and then reset it upon completion. fn with_style( &mut self, - style: ColorSpec, - write_fn: impl FnOnce(&mut CommandOutput) -> Result<()>, + mut style: ColorSpec, + write_fn: impl FnOnce(&mut Self) -> Result<()>, ) -> Result<()> { + if self.is_inside_ephemeral() { + style = comment_style(); + } self.output.set_color(&style)?; - write_fn(self.output)?; + write_fn(self)?; self.output.reset()?; Ok(()) } /// Convenience method to set the output stream to the specified color/style, write `text`, /// and then reset the output stream's style again. - fn write_with_style(&mut self, style: ColorSpec, text: &str) -> Result<()> { - self.with_style(style, |out| { - out.write_all(text.as_bytes())?; + fn write_with_style(&mut self, style: ColorSpec, text: impl AsRef) -> Result<()> { + self.with_style(style, |this| { + this.output.write_all(text.as_ref().as_bytes())?; Ok(()) }) } + fn is_inside_ephemeral(&self) -> bool { + self.ephemeral_depth > 0 + } + + fn step_into_ephemeral(&mut self, block: BlockFn) -> Result<()> + where + BlockFn: FnOnce(&mut IonInspector) -> Result<()>, + { + self.ephemeral_depth += 1; + block(self)?; + self.ephemeral_depth -= 1; + Ok(()) + } + /// Convenience method to move output to the next line. fn newline(&mut self) -> Result<()> { + self.line_has_comment = false; Ok(self.output.write_all(b"\n")?) } + fn begin_comment(&mut self) -> Result<()> { + if !self.line_has_comment { + self.line_has_comment = true; + self.write_with_style(comment_style(), " // ")?; + } else { + // This line already has a comment, add a space before what follows + self.write_with_style(comment_style(), " ")?; + } + Ok(()) + } + + fn write_comment(&mut self, text: impl AsRef) -> Result<()> { + self.begin_comment()?; + self.write_with_style(comment_style(), text.as_ref())?; + Ok(()) + } + /// Inspects an Ion Version Marker. fn inspect_ivm(&mut self, marker: LazyRawAnyVersionMarker<'_>) -> Result<()> { const BINARY_IVM_LENGTH: usize = 4; @@ -433,17 +473,13 @@ impl<'a, 'b> IonInspector<'a, 'b> { BINARY_IVM_LENGTH, &mut formatter, )?; - self.with_style(BytesKind::VersionMarker.style(), |out| { + self.with_style(BytesKind::VersionMarker.style(), |this| { let (major, minor) = marker.major_minor(); - write!(out, "$ion_{major}_{minor}")?; + write!(this.output, "$ion_{major}_{minor}")?; Ok(()) })?; - self.with_style(comment_style(), |out| { - write!(out, " // Version marker")?; - Ok(()) - })?; - self.output.reset()?; + self.write_comment("Version marker")?; Ok(()) } @@ -451,14 +487,46 @@ impl<'a, 'b> IonInspector<'a, 'b> { let mut empty_bytes = BytesFormatter::new(BYTES_PER_ROW, vec![]); self.newline()?; self.write_offset_length_and_bytes(0, position, "", &mut empty_bytes)?; - self.write_with_style(comment_style(), "// End of stream") + self.write_comment("End of stream") + } + + fn inspect_macro_invocation<'x>( + &mut self, + depth: usize, + trailing_delimiter: &str, + invocation: MacroExpr, + ) -> Result<()> { + use MacroExprKind::*; + match invocation.kind() { + EExp(eexp_arg) => self.inspect_eexp(depth, trailing_delimiter, eexp_arg)?, + EExpArgGroup(arg_group) => { + self.inspect_eexp_arg_group(depth, arg_group, trailing_delimiter)? + } + TemplateMacro(_invocation) => { + // No-op; + } + TemplateArgGroup(_) => { + unreachable!("e-exp args by definition cannot be TDL macro invocations") + } + }; + Ok(()) } - fn inspect_eexp(&mut self, depth: usize, eexp: EExpression) -> Result<()> { + fn inspect_eexp<'x>( + &mut self, + depth: usize, + trailing_delimiter: &str, + eexp: EExpression, + ) -> Result<()> { let LazyRawAnyEExpressionKind::Binary_1_1(raw_eexp) = eexp.raw_invocation().kind() else { unreachable!("text e-expression") }; + if self.is_inside_ephemeral() { + return Ok(()); + } + + self.newline()?; let mut formatter = BytesFormatter::new( BYTES_PER_ROW, vec![ @@ -476,22 +544,26 @@ impl<'a, 'b> IonInspector<'a, 'b> { ), ], ); - self.newline()?; + self.write_offset_length_and_bytes( depth, eexp.range().start, eexp.span().len(), &mut formatter, )?; - self.with_style(eexp_style(), |out| { - if let Some(macro_name) = eexp.invoked_macro().name() { - write!(out, "(:{macro_name}")?; - } else { - write!(out, "(:{}", eexp.invoked_macro().id())?; - } - Ok(()) - })?; + if let Some(macro_name) = eexp.invoked_macro().name() { + self.write_with_style(eexp_style(), format!("(:{macro_name}"))?; + } else { + self.write_with_style(eexp_style(), format!("(:{}", eexp.invoked_macro().id()))?; + } + + // If this is a macro that doesn't take any parameters, close the e-expression on the same + // line of output and early return. + if eexp.invoked_macro().signature().parameters().is_empty() { + return self.write_with_style(eexp_style(), format!("){trailing_delimiter}")); + } + for (param, arg_result) in eexp .invoked_macro() .signature() @@ -502,34 +574,29 @@ impl<'a, 'b> IonInspector<'a, 'b> { let arg = arg_result?; match arg { ValueExpr::ValueLiteral(value) => { - self.inspect_value(depth + 1, "", LazyValue::from(value), |out, _value| { - write!(out, " // {}", param.name())?; - Ok(true) - })?; + self.inspect_value(depth + 1, "", LazyValue::from(value), no_comment())?; } ValueExpr::MacroInvocation(invocation) => { - use MacroExprKind::*; - match invocation.kind() { - EExp(eexp_arg) => self.inspect_eexp(depth + 1, eexp_arg)?, - EExpArgGroup(arg_group) => { - self.inspect_eexp_arg_group(depth + 1, arg_group)? - } - TemplateMacro(_) | TemplateArgGroup(_) => { - unreachable!("e-exp args by definition cannot be TDL macro invocations") - } - } + self.inspect_macro_invocation(depth + 1, "", invocation)?; } } + self.write_comment(param.name())?; } self.write_text_only_line(depth, eexp_style(), ")")?; + self.write_with_style(comment_style(), trailing_delimiter)?; Ok(()) } - fn inspect_eexp_arg_group( + fn inspect_eexp_arg_group<'x>( &mut self, depth: usize, arg_group: EExpArgGroup, + trailing_delimiter: &str, ) -> Result<()> { + if self.is_inside_ephemeral() { + return Ok(()); + } + self.newline()?; let AnyEExpArgGroupKind::Binary_1_1(raw_arg_group) = arg_group.raw_arg_group().kind() @@ -537,6 +604,12 @@ impl<'a, 'b> IonInspector<'a, 'b> { unreachable!("text e-expression arg group") }; + if arg_group.span().is_empty() { + // This arg group is set to the empty stream in the Arg encoding bitmap. It has no backing bytes. + self.write_blank_offset_length_and_bytes(depth)?; + return self.write_with_style(comment_style(), format!("(::){trailing_delimiter}")); + } + let mut formatter = BytesFormatter::new( BYTES_PER_ROW, vec![IonBytes::new( @@ -544,7 +617,6 @@ impl<'a, 'b> IonInspector<'a, 'b> { raw_arg_group.header_span().bytes(), )], ); - self.write_offset_length_and_bytes( depth, raw_arg_group.range().start, @@ -552,8 +624,16 @@ impl<'a, 'b> IonInspector<'a, 'b> { &mut formatter, )?; + // If it has backing bytes but it's still empty, write it on one line but use color. + if arg_group.expressions().is_exhausted() { + self.write_with_style(eexp_style(), format!("(::){trailing_delimiter}"))?; + + // There are no arguments, so we're done. + return Ok(()); + } + + // Otherwise, it has bytes and it's populated. self.write_with_style(eexp_style(), "(::")?; - self.write_with_style(comment_style(), " // arg group")?; // TODO: This impl will not evaluate nested e-expressions. let nested_exprs = MacroExprArgsIterator::from_eexp_arg_group(arg_group.expressions()); @@ -565,7 +645,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { ValueExpr::MacroInvocation(invocation) => { use MacroExprKind::*; match invocation.kind() { - EExp(eexp_arg) => self.inspect_eexp(depth + 1, eexp_arg)?, + EExp(eexp_arg) => self.inspect_eexp(depth + 1, "", eexp_arg)?, EExpArgGroup(_arg_group) => { unreachable!("e-exp arg groups cannot contain e-exp arg groups") } @@ -586,14 +666,43 @@ impl<'a, 'b> IonInspector<'a, 'b> { self.write_with_style(style, text) } + /// Inspects all values (however deeply nested) starting at the current level. + fn inspect_value_expr<'x>( + &mut self, + depth: usize, + trailing_delimiter: &str, + value_expr: ValueExpr<'x, AnyEncoding>, + mut comment_fn: impl CommentFn<'x>, + ) -> Result<()> { + match value_expr { + ValueExpr::ValueLiteral(value) => { + let lazy_value = LazyValue::from(value); + self.inspect_value(depth, trailing_delimiter, lazy_value, no_comment())?; + } + ValueExpr::MacroInvocation(invocation) => { + self.inspect_macro_invocation(depth, trailing_delimiter, invocation)?; + } + } + self.with_style(comment_style(), |this| { + comment_fn(this.output, value_expr)?; + Ok(()) + })?; + Ok(()) + } + /// Inspects all values (however deeply nested) starting at the current level. fn inspect_value<'x>( &mut self, depth: usize, - delimiter: &str, + trailing_delimiter: &str, value: LazyValue<'x, AnyEncoding>, comment_fn: impl CommentFn<'x>, ) -> Result<()> { + // If this value is ephemeral and the user has requested that ephemeral values not be shown... + if value.expanded().is_ephemeral() && self.hide_expansion { + // ...then this is a no-op. + return Ok(()); + } self.newline()?; if value.has_annotations() { self.inspect_annotations(depth, value)?; @@ -601,10 +710,10 @@ impl<'a, 'b> IonInspector<'a, 'b> { } use ValueRef::*; match value.read()? { - SExp(sexp) => self.inspect_sexp(depth, delimiter, sexp), - List(list) => self.inspect_list(depth, delimiter, list), - Struct(struct_) => self.inspect_struct(depth, delimiter, struct_), - _ => self.inspect_scalar(depth, delimiter, value, comment_fn), + SExp(sexp) => self.inspect_sexp(depth, trailing_delimiter, sexp), + List(list) => self.inspect_list(depth, trailing_delimiter, list, no_comment()), + Struct(struct_) => self.inspect_struct(depth, trailing_delimiter, struct_), + _ => self.inspect_scalar(depth, trailing_delimiter, value, comment_fn), } } @@ -621,7 +730,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { match value.expanded().source() { // If the value is backed by an encoded literal AND that literal wasn't passed as an // argument to an e-expression, inspect the encoded value. - ValueLiteral(value_literal) if !value.expanded().is_parameter() => { + ValueLiteral(value_literal) if !self.treat_as_ephemeral(value.expanded()) => { use LazyRawValueKind::*; match value_literal.kind() { Binary_1_0(bin_val) => { @@ -638,6 +747,10 @@ impl<'a, 'b> IonInspector<'a, 'b> { } } + fn treat_as_ephemeral(&self, value: LazyExpandedValue) -> bool { + self.is_inside_ephemeral() || value.is_ephemeral() + } + /// Inspects the s-expression `sexp`, including all of its child values. If this sexp appears /// in a list or struct, the caller can set `delimiter` to a comma (`","`) and it will be appended /// to the sexp's text representation. @@ -649,7 +762,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { ) -> Result<()> { use ExpandedSExpSource::*; match sexp.expanded().source() { - ValueLiteral(raw_sexp) => { + ValueLiteral(raw_sexp) if !self.treat_as_ephemeral(sexp.as_value().expanded()) => { use LazyRawSExpKind::*; match raw_sexp.kind() { Text_1_0(_) | Text_1_1(_) => unreachable!("text value"), @@ -661,24 +774,31 @@ impl<'a, 'b> IonInspector<'a, 'b> { } } } - Template(_, _element) => { - self.inspect_ephemeral_sequence(depth, "(", "", ")", delimiter, sexp, no_comment()) - } + _ => self.inspect_ephemeral_sequence( + depth, + "(", + "", + ")", + delimiter, + sexp.expanded().value_exprs(), + no_comment(), + ), } } /// Inspects the list `list`, including all of its child values. If this list appears inside /// a list or struct, the caller can set `delimiter` to a comma (`","`) and it will be appended /// to the list's text representation. - fn inspect_list( + fn inspect_list<'x>( &mut self, depth: usize, - delimiter: &str, - list: LazyList<'_, AnyEncoding>, + trailing_delimiter: &str, + list: LazyList<'x, AnyEncoding>, + value_comment_fn: impl CommentFn<'x>, ) -> Result<()> { use ExpandedListSource::*; match list.expanded().source() { - ValueLiteral(raw_list) => { + ValueLiteral(raw_list) if !self.treat_as_ephemeral(list.as_value().expanded()) => { use LazyRawListKind::*; match raw_list.kind() { Text_1_0(_) | Text_1_1(_) => unreachable!("text value"), @@ -687,57 +807,69 @@ impl<'a, 'b> IonInspector<'a, 'b> { "[", ",", "]", - delimiter, - list.iter(), + trailing_delimiter, + list.expanded().value_exprs(), v.as_value(), - no_comment(), + value_comment_fn, ), Binary_1_1(v) => self.inspect_literal_sequence( depth, "[", ",", "]", - delimiter, - list.iter(), + trailing_delimiter, + list.expanded().value_exprs(), v.as_value(), - no_comment(), + value_comment_fn, ), } } - Template(_, _element) => self.inspect_ephemeral_sequence( + _ => self.inspect_ephemeral_sequence( depth, "[", ",", "]", - delimiter, - list.iter(), - no_comment(), + trailing_delimiter, + list.expanded().value_exprs(), + value_comment_fn, ), } } + fn inspect_struct( + &mut self, + depth: usize, + trailing_delimiter: &str, + struct_: LazyStruct<'_, AnyEncoding>, + ) -> Result<()> { + self.inspect_struct_kind(depth, trailing_delimiter, struct_, StructKind::Standard) + } + /// Inspects the struct `struct_`, including all of its fields. If this struct appears inside /// a list or struct, the caller can set `delimiter` to a comma (`","`) and it will be appended /// to the struct's text representation. - fn inspect_struct( + fn inspect_struct_kind( &mut self, depth: usize, - delimiter: &str, + trailing_delimiter: &str, struct_: LazyStruct<'_, AnyEncoding>, + kind: StructKind, ) -> Result<()> { use ExpandedStructSource::*; match struct_.expanded().source() { - ValueLiteral(raw_struct) => { + ValueLiteral(raw_struct) if !self.treat_as_ephemeral(struct_.as_value().expanded()) => { use LazyRawValueKind::*; match raw_struct.as_value().kind() { - Binary_1_0(v) => self.inspect_literal_struct(depth, delimiter, struct_, v), - Binary_1_1(v) => self.inspect_literal_struct(depth, delimiter, struct_, v), + Binary_1_0(v) => { + self.inspect_literal_struct(depth, trailing_delimiter, struct_, v, kind) + } + Binary_1_1(v) => { + self.inspect_literal_struct(depth, trailing_delimiter, struct_, v, kind) + } Text_1_0(_) | Text_1_1(_) => unreachable!("text value"), } } - Template(..) | MakeStruct(..) | MakeField(..) => { - self.inspect_ephemeral_struct(depth, delimiter, struct_) - } + _ => self.inspect_ephemeral_struct(depth, trailing_delimiter, struct_, kind), } } @@ -747,18 +879,8 @@ impl<'a, 'b> IonInspector<'a, 'b> { self.newline()?; self.inspect_annotations(0, value)?; } - use ExpandedStructSource::*; - let raw_struct = match struct_.expanded().source() { - ValueLiteral(raw_struct) => raw_struct, - Template(..) | MakeStruct(..) | MakeField(..) => todo!("Ion 1.1 template symbol table"), - }; - - use LazyRawValueKind::*; - match raw_struct.as_value().kind() { - Binary_1_0(v) => self.inspect_literal_symbol_table(struct_, raw_struct, v), - Binary_1_1(v) => self.inspect_literal_symbol_table(struct_, raw_struct, v), - Text_1_0(_) | Text_1_1(_) => unreachable!("text value"), - } + self.newline()?; + self.inspect_struct_kind(0, "", struct_, StructKind::SymbolTable) } /// Determines the source of the annotations on the provided value (if any) and adds them to the @@ -771,6 +893,9 @@ impl<'a, 'b> IonInspector<'a, 'b> { return Ok(()); } match value.expanded().source() { + ExpandedValueSource::ValueLiteral(..) if self.is_inside_ephemeral() => { + self.inspect_ephemeral_annotations(depth, value.annotations()) + } ExpandedValueSource::ValueLiteral(raw_value) => { use LazyRawValueKind::*; match raw_value.kind() { @@ -831,12 +956,12 @@ impl<'a, 'b> IonInspector<'a, 'b> { annotations: impl Iterator>>, ) -> Result<()> { self.write_blank_offset_length_and_bytes(depth)?; - self.with_style(ephemeral_annotations_style(), |out| { + self.with_style(ephemeral_annotations_style(), |this| { for annotation in annotations { - IoValueFormatter::new(&mut *out) + IoValueFormatter::new(&mut *this.output) .value_formatter() .format_symbol(annotation?)?; - write!(out, "::")?; + write!(this.output, "::")?; } Ok(()) })?; @@ -852,16 +977,16 @@ impl<'a, 'b> IonInspector<'a, 'b> { ) -> Result<()> { let formatted_annotations = self.format_annotations(annotations)?; self.write_with_style(annotations_style(), formatted_annotations.as_str())?; - self.with_style(comment_style(), |out| { - write!(out, " // ")?; + self.write_comment("")?; + self.with_style(comment_style(), |this| { for (index, raw_annotation) in raw_annotations.enumerate() { if index > 0 { - write!(out, ", ")?; + write!(this.output, ", ")?; } match raw_annotation? { - RawSymbolRef::SymbolId(sid) => write!(out, "${sid}"), - RawSymbolRef::Text(_) => write!(out, ""), - RawSymbolRef::SystemSymbol_1_1(_) => write!(out, ""), + RawSymbolRef::SymbolId(sid) => write!(this.output, "${sid}"), + RawSymbolRef::Text(_) => write!(this.output, ""), + RawSymbolRef::SystemSymbol_1_1(_) => write!(this.output, ""), }?; } Ok(()) @@ -896,6 +1021,35 @@ impl<'a, 'b> IonInspector<'a, 'b> { self.write_offset_length_and_bytes(depth, range.start, range.len(), &mut formatter) } + fn inspect_literal_container_footer<'x, D: Decoder>( + &mut self, + depth: usize, + encoded_value: impl EncodedBinaryValue<'x, D>, + closing_delimiter: &str, + trailing_delimiter: &str, + ) -> Result<()> { + self.newline()?; + let delimited_end_span = encoded_value.delimited_end_span(); + if delimited_end_span.is_empty() { + self.write_blank_offset_length_and_bytes(depth)?; + } else { + let mut formatter = BytesFormatter::new( + BYTES_PER_ROW, + vec![IonBytes::new(BytesKind::Opcode, delimited_end_span.bytes())], + ); + self.write_offset_length_and_bytes( + depth, + delimited_end_span.range().start, + delimited_end_span.range().len(), + &mut formatter, + )?; + } + self.with_style(text_ion_style(), |this| { + write!(this.output, "{closing_delimiter}{trailing_delimiter}")?; + Ok(()) + }) + } + fn inspect_literal_sexp<'x, D: Decoder>( &mut self, depth: usize, @@ -909,12 +1063,13 @@ impl<'a, 'b> IonInspector<'a, 'b> { "", ")", delimiter, - sexp.iter(), + sexp.expanded().value_exprs(), encoded_value, no_comment(), ) } + #[allow(clippy::too_many_arguments)] fn inspect_literal_sequence<'x, D: Decoder>( &mut self, depth: usize, @@ -922,26 +1077,23 @@ impl<'a, 'b> IonInspector<'a, 'b> { value_delimiter: &str, closing_delimiter: &str, trailing_delimiter: &str, - nested_values: impl IntoIterator>>, + nested_values: impl IntoIterator>>, encoded_value: impl EncodedBinaryValue<'x, D>, value_comment_fn: impl CommentFn<'x>, ) -> Result<()> { self.inspect_literal_container_header(depth, encoded_value)?; - self.with_style(text_ion_style(), |out| { - write!(out, "{opening_delimiter}")?; - Ok(()) - })?; + self.write_with_style(text_ion_style(), opening_delimiter)?; self.inspect_sequence_body(depth + 1, value_delimiter, nested_values, value_comment_fn)?; - - self.newline()?; - self.write_blank_offset_length_and_bytes(depth)?; - self.with_style(text_ion_style(), |out| { - write!(out, "{closing_delimiter}{trailing_delimiter}")?; - Ok(()) - }) + self.inspect_literal_container_footer( + depth, + encoded_value, + closing_delimiter, + trailing_delimiter, + ) } + #[allow(clippy::too_many_arguments)] fn inspect_ephemeral_sequence<'x>( &mut self, depth: usize, @@ -949,22 +1101,23 @@ impl<'a, 'b> IonInspector<'a, 'b> { value_delimiter: &str, closing_delimiter: &str, trailing_delimiter: &str, - nested_values: impl IntoIterator>>, + nested_values: impl IntoIterator>>, value_comment_fn: impl CommentFn<'x>, ) -> Result<()> { self.write_blank_offset_length_and_bytes(depth)?; - self.with_style(ephemeral_value_style(), |out| { - write!(out, "{opening_delimiter}")?; - Ok(()) - })?; - - self.inspect_sequence_body(depth + 1, value_delimiter, nested_values, value_comment_fn)?; + self.step_into_ephemeral(|inspector| { + inspector.write_with_style(ephemeral_value_style(), opening_delimiter)?; + inspector.inspect_sequence_body( + depth + 1, + value_delimiter, + nested_values, + value_comment_fn, + )?; - self.newline()?; - self.write_blank_offset_length_and_bytes(depth)?; - self.with_style(ephemeral_value_style(), |out| { - write!(out, "{closing_delimiter}{trailing_delimiter}")?; - Ok(()) + inspector.newline()?; + inspector.write_blank_offset_length_and_bytes(depth)?; + inspector.write_with_style(ephemeral_value_style(), closing_delimiter)?; + inspector.write_with_style(ephemeral_value_style(), trailing_delimiter) }) } @@ -972,19 +1125,19 @@ impl<'a, 'b> IonInspector<'a, 'b> { &mut self, depth: usize, value_delimiter: &str, - nested_values: impl IntoIterator>>, + nested_value_exprs: impl IntoIterator>>, mut value_comment_fn: impl CommentFn<'x>, ) -> Result<()> { let mut has_printed_skip_message = false; - for value_res in nested_values { - let nested_value = value_res?; + for value_res in nested_value_exprs { + let nested_value_expr = value_res?; // If this value is a literal in the stream, see if it is in the bounds of byte // ranges we care about. match self.select_action( depth, &mut has_printed_skip_message, - &nested_value.raw(), + &nested_value_expr.range(), "values", "stepping out", )? { @@ -993,10 +1146,12 @@ impl<'a, 'b> IonInspector<'a, 'b> { InspectorAction::LimitReached => break, } - self.inspect_value(depth, value_delimiter, nested_value, no_comment())?; - self.output.set_color(&comment_style())?; - value_comment_fn(self.output, nested_value)?; - self.output.reset()?; + self.inspect_value_expr( + depth, + value_delimiter, + nested_value_expr, + &mut value_comment_fn, + )?; } Ok(()) } @@ -1026,6 +1181,36 @@ impl<'a, 'b> IonInspector<'a, 'b> { Ok(InspectorAction::Inspect) } + fn inspect_field_name( + &mut self, + depth: usize, + name: LazyExpandedFieldName, + ) -> Result<()> { + if !self.is_inside_ephemeral() { + // See if there are bytes to render + if let Some(raw_name) = name.raw() { + return self.inspect_literal_field_name(depth, (*raw_name).into(), name.read()?); + } + } + self.inspect_ephemeral_field_name(depth, name) + } + + fn inspect_ephemeral_field_name( + &mut self, + depth: usize, + name: LazyExpandedFieldName, + ) -> Result<()> { + self.newline()?; + self.write_blank_offset_length_and_bytes(depth)?; + self.with_style(ephemeral_field_id_style(), |this| { + IoValueFormatter::new(&mut *this.output) + .value_formatter() + .format_symbol(name.read()?)?; + write!(this.output, ": ")?; + Ok(()) + }) + } + fn inspect_literal_field_name( &mut self, depth: usize, @@ -1042,239 +1227,157 @@ impl<'a, 'b> IonInspector<'a, 'b> { vec![IonBytes::new(BytesKind::FieldId, raw_name_bytes)], ); self.write_offset_length_and_bytes(depth, offset, length, &mut formatter)?; - self.with_style(field_id_style(), |out| { - IoValueFormatter::new(out) + self.with_style(field_id_style(), |this| { + IoValueFormatter::new(&mut *this.output) .value_formatter() .format_symbol(name)?; Ok(()) })?; write!(self.output, ": ")?; + // Print a text Ion comment showing how the field name was encoded, ($SID or text) - self.with_style(comment_style(), |out| { - match raw_name.read()? { - RawSymbolRef::SymbolId(sid) => { - write!(out, " // ${sid}") - } - RawSymbolRef::Text(_) => { - write!(out, " // ") - } - RawSymbolRef::SystemSymbol_1_1(_) => { - write!(out, " // ") - } - }?; - Ok(()) - }) + match raw_name.read()? { + RawSymbolRef::SymbolId(sid) => self.write_comment(format!("<${sid}>")), + RawSymbolRef::Text(_) => self.write_comment(""), + RawSymbolRef::SystemSymbol_1_1(_) => self.write_comment(""), + } } /// Inspects all values (however deeply nested) starting at the current field. - fn inspect_field(&mut self, depth: usize, field: LazyField) -> Result<()> { - let name = field.name()?; - if let Some(raw_name) = field.raw_name() { - self.inspect_literal_field_name(depth, raw_name, name)?; - } else { - self.newline()?; - self.write_blank_offset_length_and_bytes(depth)?; - self.with_style(ephemeral_field_id_style(), |out| { - IoValueFormatter::new(out) - .value_formatter() - .format_symbol(name)?; - Ok(()) - })?; - write!(self.output, ": ")?; - }; - self.inspect_value(depth, ",", field.value(), no_comment())?; - Ok(()) + fn inspect_field(&mut self, depth: usize, field: FieldExpr) -> Result<()> { + use FieldExpr::*; + match field { + NameValue(name, value) => { + self.inspect_field_name(depth, name)?; + self.inspect_value(depth, ",", LazyValue::from(value), no_comment()) + } + NameMacro(name, invocation) => { + if let MacroExprKind::TemplateMacro(_tdl_invocation) = invocation.kind() { + // No-op; + Ok(()) + } else { + self.inspect_field_name(depth, name)?; + self.inspect_macro_invocation(depth, ",", invocation) + } + } + EExp(eexp) => self.inspect_eexp(depth, ",", eexp), + } } fn inspect_literal_struct<'x, D: Decoder>( &mut self, depth: usize, - delimiter: &str, + trailing_delimiter: &str, struct_: LazyStruct, encoded_value: impl EncodedBinaryValue<'x, D>, + kind: StructKind, ) -> Result<()> { self.inspect_literal_container_header(depth, encoded_value)?; self.write_with_style(text_ion_style(), "{")?; - self.inspect_struct_body(depth, struct_)?; - self.newline()?; - self.write_blank_offset_length_and_bytes(depth)?; - self.with_style(text_ion_style(), |out| { - write!(out, "}}{delimiter}")?; - Ok(()) - }) + self.inspect_struct_body(depth, struct_, kind)?; + self.inspect_literal_container_footer(depth, encoded_value, "}", trailing_delimiter) } - fn inspect_ephemeral_struct<'x>( + fn inspect_ephemeral_struct( &mut self, depth: usize, delimiter: &str, struct_: LazyStruct, + kind: StructKind, ) -> Result<()> { - self.write_blank_offset_length_and_bytes(depth)?; - self.with_style(ephemeral_value_style(), |out| { - write!(out, "{{")?; - Ok(()) - })?; - self.inspect_struct_body(depth, struct_)?; - self.newline()?; - self.write_blank_offset_length_and_bytes(depth)?; - self.with_style(ephemeral_value_style(), |out| { - write!(out, "}}{delimiter}")?; - Ok(()) + self.step_into_ephemeral(|this| { + this.write_blank_offset_length_and_bytes(depth)?; + this.write_with_style(ephemeral_value_style(), "{")?; + this.inspect_struct_body(depth, struct_, kind)?; + this.newline()?; + this.write_blank_offset_length_and_bytes(depth)?; + this.write_with_style(ephemeral_value_style(), format!("}}{delimiter}")) }) } - fn inspect_struct_body<'x>( + fn inspect_struct_body( &mut self, depth: usize, struct_: LazyStruct, + kind: StructKind, ) -> Result<()> { let mut has_printed_skip_message: bool = false; - for field_result in struct_.iter() { - let field = field_result?; + for field_expr_result in struct_.expanded().field_exprs() { + let field_expr = field_expr_result?; match self.select_action( depth + 1, &mut has_printed_skip_message, - &field.range(), + &field_expr.range(), "fields", "stepping out", )? { InspectorAction::Skip => continue, - InspectorAction::Inspect => self.inspect_field(depth + 1, field)?, + InspectorAction::Inspect => {} InspectorAction::LimitReached => break, - } - } - Ok(()) - } - - fn inspect_literal_symbol_table<'x, D: Decoder>( - &mut self, - struct_: LazyStruct, - raw_struct: LazyRawAnyStruct, - encoded_value: impl EncodedBinaryValue<'x, D>, - ) -> Result<()> { - // The processing for a symbol table is very similar to that of a regular struct, - // but with special handling defined for the `imports` and `symbols` fields when present. - // Because symbol tables are always at the top level, there is no need for indentation. - const TOP_LEVEL_DEPTH: usize = 0; - self.newline()?; - self.inspect_literal_container_header(TOP_LEVEL_DEPTH, encoded_value)?; - self.with_style(text_ion_style(), |out| { - write!(out, "{{")?; - Ok(()) - })?; - let mut has_printed_skip_message = false; - for (raw_field_result, field_result) in raw_struct.iter().zip(struct_.iter()) { - let field = field_result?; - let raw_field = raw_field_result?; + }; - match self.select_action( - TOP_LEVEL_DEPTH + 1, - &mut has_printed_skip_message, - &Some(raw_field), - "fields", - "stepping out", - )? { - InspectorAction::Skip => continue, - InspectorAction::Inspect if field.name()? == "symbols" => { - self.inspect_lst_symbols_field(struct_, field, raw_field)? + if kind == StructKind::SymbolTable { + if let FieldExpr::NameValue(name, value) = field_expr { + if name.read()? == "symbols" { + self.inspect_lst_symbols_field(struct_, name, value)?; + continue; + } } - // TODO: if field.name()? == "imports" => {} - InspectorAction::Inspect => self.inspect_field(TOP_LEVEL_DEPTH + 1, field)?, - InspectorAction::LimitReached => break, + // Other FieldExpr kinds are rendered normally; only the actual list of symbols gets + // special treatment. } + self.inspect_field(depth + 1, field_expr)?; } - // ===== Closing delimiter ===== - self.newline()?; - self.write_blank_offset_length_and_bytes(TOP_LEVEL_DEPTH)?; - self.with_style(text_ion_style(), |out| { - write!(out, "}}")?; - Ok(()) - }) + Ok(()) } fn inspect_lst_symbols_field( &mut self, symtab_struct: LazyStruct, - field: LazyField, - raw_field: LazyRawFieldExpr, + name: LazyExpandedFieldName, + value: LazyExpandedValue, ) -> Result<()> { const SYMBOL_LIST_DEPTH: usize = 1; - let (raw_name, raw_value) = raw_field.expect_name_value()?; - self.inspect_literal_field_name(SYMBOL_LIST_DEPTH, raw_name, field.name()?)?; - - let symbols_list = match field.value().read()? { - ValueRef::List(list) => list, - _ => { - return self.inspect_value(SYMBOL_LIST_DEPTH, ",", field.value(), |out, _value| { - out.write_all(b" // Invalid, ignored")?; - Ok(true) - }); - } - }; - - let raw_symbols_list = raw_value.read()?.expect_list()?; - let nested_raw_values = raw_symbols_list.iter(); - let nested_values = symbols_list.iter(); - + self.inspect_field_name(SYMBOL_LIST_DEPTH, name)?; self.newline()?; - match raw_value.kind() { - LazyRawValueKind::Binary_1_0(raw_value) => { - self.inspect_literal_container_header(SYMBOL_LIST_DEPTH, raw_value)?; - } - LazyRawValueKind::Binary_1_1(raw_value) => { - self.inspect_literal_container_header(SYMBOL_LIST_DEPTH, raw_value)?; - } - other_kind => unreachable!("binary encoding already confirmed; found {other_kind:?}"), - } - self.with_style(text_ion_style(), |out| { - write!(out, "[")?; - Ok(()) - })?; - // TODO: This does not account for shared symbol table imports. However, the CLI does not - // yet support specifying a catalog, so it's correct enough for the moment. - let symtab_value = symtab_struct.as_value(); - let mut next_symbol_id = symtab_value.symbol_table().len(); + // First, make sure that the `symbols` field value is a list. + // Anything else will be quietly ignored. + let ValueRef::List(symbols_list) = value.read_resolved()? else { + return self.inspect_value(SYMBOL_LIST_DEPTH, ",", value.into(), |out, _value| { + out.write_all(b"Invalid, ignored")?; + Ok(true) + }); + }; + + // If the LST struct's `imports` field value is the symbol `$ion_symbol_table`, this will + // be an append instead of a reset. let is_append = symtab_struct.get("imports")? == Some(ValueRef::Symbol(SymbolRef::with_text("$ion_symbol_table"))); - if !is_append { - next_symbol_id = 10; // First available SID after system symbols in Ion 1.0 - } - - let mut has_printed_skip_message = false; - for (raw_value_res, value_res) in nested_raw_values.zip(nested_values) { - let (raw_nested_value, nested_value) = (raw_value_res?, value_res?); - match self.select_action( - SYMBOL_LIST_DEPTH + 1, - &mut has_printed_skip_message, - &Some(raw_nested_value), - "values", - "stepping out", - )? { - InspectorAction::Skip => continue, - InspectorAction::Inspect => {} - InspectorAction::LimitReached => break, - } + let mut next_symbol_id = if is_append { + // Take a look at the stream's current symbol table to see how many symbols already exist. + let symtab_value = symtab_struct.as_value(); + symtab_value.symbol_table().len() + // TODO: ^^^ This impl does not account for shared symbol table imports. + // However, the CLI does not yet support specifying a catalog, + // so it's correct enough for the moment. + } else { + 10 // First available SID after system symbols in Ion 1.0 + }; - self.output.set_color(&comment_style())?; - self.inspect_value(SYMBOL_LIST_DEPTH + 1, ",", nested_value, |out, value| { - match value.read()? { - ValueRef::String(_s) => write!(out, " // -> ${next_symbol_id}"), - _other => write!(out, " // -> ${next_symbol_id} (no text)"), - }?; - next_symbol_id += 1; - Ok(true) - })?; - self.output.reset()?; - } + // This closure will be called after each of the list's values has been inspected. + // It will render a comment indicating which symbol address that value will be assigned. + let new_symbol_comment_fn = |out: &mut CommandOutput, expr: ValueExpr| { + match expr.expect_value_literal()?.ion_type() { + IonType::String => write!(out, "-> ID ${next_symbol_id}"), + _other => write!(out, "-> ${next_symbol_id} (no text)"), + }?; + next_symbol_id += 1; + Ok(true) + }; - self.newline()?; - self.write_blank_offset_length_and_bytes(SYMBOL_LIST_DEPTH)?; - self.with_style(text_ion_style(), |out| { - write!(out, "],")?; - Ok(()) - }) + // Inspect the list using our custom comment generator. + self.inspect_list(SYMBOL_LIST_DEPTH, ",", symbols_list, new_symbol_comment_fn) } fn inspect_literal_scalar<'x, D: Decoder>( @@ -1298,21 +1401,12 @@ impl<'a, 'b> IonInspector<'a, 'b> { self.write_offset_length_and_bytes(depth, range.start, range.len(), &mut formatter)?; let formatted_value = self.format_scalar_body(value)?; - self.with_style(text_ion_style(), |out| { - write!(out, "{formatted_value}{delimiter}")?; - Ok(()) - })?; - self.with_style(comment_style(), |out| { - let wrote_comment = comment_fn(out, value)?; - if let RawValueRef::Symbol(RawSymbolRef::SymbolId(symbol_id)) = encoded_value.read()? { - match wrote_comment { - true => write!(out, " (${symbol_id})"), - false => write!(out, " // ${symbol_id}"), - }?; - } - Ok(()) - })?; - + self.write_with_style(text_ion_style(), formatted_value)?; + self.write_with_style(text_ion_style(), delimiter)?; + let _wrote_comment = comment_fn(self.output, ValueExpr::ValueLiteral(value.expanded()))?; + if let RawValueRef::Symbol(RawSymbolRef::SymbolId(symbol_id)) = encoded_value.read()? { + self.write_comment(format!("<${symbol_id}>"))?; + } while !formatter.is_empty() { self.newline()?; self.write_offset_length_and_bytes(depth, "", "", &mut formatter)?; @@ -1330,20 +1424,18 @@ impl<'a, 'b> IonInspector<'a, 'b> { ) -> Result<()> { let formatted_value = self.format_scalar_body(value)?; let style = if let Some(variable) = value.expanded().variable() { - self.write_offset_length_and_bytes_comment(depth, "", "", variable.name())?; + let var_expansion = format!("(%{})", variable.name()); + self.write_offset_length_and_bytes_comment(depth, "", "", &var_expansion)?; ephemeral_value_style().set_underline(true).clone() } else { self.write_offset_length_and_bytes_comment(depth, "", "", "")?; ephemeral_value_style().clone() }; - self.with_style(style.clone(), |out| { - write!(out, "{formatted_value}")?; - Ok(()) - })?; + self.write_with_style(style.clone(), format!("{formatted_value}"))?; self.write_with_style(style.clone().set_underline(false).clone(), delimiter)?; - self.with_style(comment_style(), |out| { - comment_fn(out, value)?; + self.with_style(comment_style(), |this| { + comment_fn(this.output, ValueExpr::ValueLiteral(value.expanded()))?; Ok(()) })?; Ok(()) @@ -1408,9 +1500,9 @@ impl<'a, 'b> IonInspector<'a, 'b> { .set_intense(true) .set_bold(true) .set_fg(Some(Color::Rgb(100, 100, 100))); - self.with_style(color_spec, |out| { + self.with_style(color_spec, |this| { for _ in 0..depth { - out.write_all(INDENTATION_WITH_GUIDE.as_bytes())?; + this.output.write_all(INDENTATION_WITH_GUIDE.as_bytes())?; } Ok(()) }) @@ -1430,10 +1522,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { self.output, "{VERTICAL_LINE} {offset:12} {VERTICAL_LINE} {length:12} {VERTICAL_LINE} " )?; - self.with_style(ephemeral_bytes_style(), |out| { - write!(out, "{bytes:>23}")?; - Ok(()) - })?; + self.write_with_style(ephemeral_bytes_style(), format!("{bytes:>23}"))?; write!(self.output, " {VERTICAL_LINE} ")?; self.write_indentation(depth)?; Ok(()) @@ -1471,10 +1560,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { fn write_skipping_message(&mut self, depth: usize, name_of_skipped_item: &str) -> Result<()> { write!(self.output, "\n{VERTICAL_LINE} {:>12} {VERTICAL_LINE} {:>12} {VERTICAL_LINE} {:23} {VERTICAL_LINE} ", "...", "...", "...")?; self.write_indentation(depth)?; - self.with_style(comment_style(), |out| { - write!(out, "// ...skipping {name_of_skipped_item}...")?; - Ok(()) - }) + self.write_comment(format!("...skipping {name_of_skipped_item}...")) } /// Prints a row with an ellipsis (`...`) in the first three columns, and a text Ion comment in @@ -1484,10 +1570,7 @@ impl<'a, 'b> IonInspector<'a, 'b> { write!(self.output, "\n{VERTICAL_LINE} {:>12} {VERTICAL_LINE} {:>12} {VERTICAL_LINE} {:23} {VERTICAL_LINE} ", "...", "...", "...")?; self.write_indentation(depth)?; let limit_bytes = self.limit_bytes; - self.with_style(comment_style(), |out| { - write!(out, "// --limit-bytes {} reached, {action}.", limit_bytes)?; - Ok(()) - }) + self.write_comment(format!("// --limit-bytes {limit_bytes} reached, {action}.")) } } @@ -1558,7 +1641,7 @@ fn annotations_style() -> ColorSpec { } fn ephemeral_annotations_style() -> ColorSpec { - annotations_style().set_dimmed(true).clone() + comment_style() } /// Kinds of encoding primitives found in a binary Ion stream. diff --git a/src/bin/ion/commands/mod.rs b/src/bin/ion/commands/mod.rs index 1f9698c2..bc836141 100644 --- a/src/bin/ion/commands/mod.rs +++ b/src/bin/ion/commands/mod.rs @@ -213,7 +213,7 @@ pub struct CommandIo<'a> { args: &'a ArgMatches, } -impl<'a> CommandIo<'a> { +impl CommandIo<'_> { fn new(args: &ArgMatches) -> CommandIo { CommandIo { args } } diff --git a/src/bin/ion/commands/schema/validate.rs b/src/bin/ion/commands/schema/validate.rs index 799ccf6a..f6e64137 100644 --- a/src/bin/ion/commands/schema/validate.rs +++ b/src/bin/ion/commands/schema/validate.rs @@ -249,6 +249,6 @@ fn write_validation_result_ion( } /// Transposes a borrowed vec of owned elements into an owned vec of borrowed elements. -fn vec_of_refs(the_vec: &Vec) -> Vec<&Element> { +fn vec_of_refs(the_vec: &[Element]) -> Vec<&Element> { the_vec.iter().collect() } diff --git a/src/bin/ion/commands/symtab/filter.rs b/src/bin/ion/commands/symtab/filter.rs index 7e82cf69..c5e9a6bb 100644 --- a/src/bin/ion/commands/symtab/filter.rs +++ b/src/bin/ion/commands/symtab/filter.rs @@ -85,7 +85,7 @@ pub fn filter_out_user_data( // or // $ion_symbol_table::{}$ion_1_0$ion_symbol_table::{} if reader.detected_encoding().is_text() { - output.write_all(&[b'\n']).unwrap() + output.write_all(b"\n").unwrap() } } } diff --git a/src/bin/ion/hex_reader.rs b/src/bin/ion/hex_reader.rs index 1e98cdce..428042fe 100644 --- a/src/bin/ion/hex_reader.rs +++ b/src/bin/ion/hex_reader.rs @@ -50,14 +50,14 @@ impl From for HexReader { impl Read for HexReader { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - if buf.len() == 0 { + if buf.is_empty() { return Ok(0); } let mut bytes_read = 0usize; - while let Some(b) = self.inner.next() { - let c = char::from(b?); + for byte in &mut self.inner { + let c = char::from(byte?); use DigitState::*; match self.digit_state { @@ -67,9 +67,9 @@ impl Read for HexReader { // Now we know that this hex-encoded byte is going to be `0xHH` rather than `0H` Zero if c == 'x' => self.digit_state = ZeroX, // Reading the first digit of the hex-encoded byte - Empty | ZeroX if c.is_digit(16) => self.digit_state = HasUpperNibble(c), + Empty | ZeroX if c.is_ascii_hexdigit() => self.digit_state = HasUpperNibble(c), // Reading the second digit of the hex-encoded byte - Zero if c.is_digit(16) => { + Zero if c.is_ascii_hexdigit() => { // Unwrap is guaranteed not to panic because we've been putting only valid hex // digit characters in the `digit_buffer` String. let value = c.to_digit(16).unwrap(); @@ -78,7 +78,7 @@ impl Read for HexReader { bytes_read += 1; self.digit_state = Empty; } - HasUpperNibble(c0) if c.is_digit(16) => { + HasUpperNibble(c0) if c.is_ascii_hexdigit() => { // The first unwrap is guaranteed not to panic because we already know that both // chars are valid hex digits. // The second unwrap is guaranteed not to panic because the max it could be is 0x0F diff --git a/src/bin/ion/output.rs b/src/bin/ion/output.rs index 8f3ddc94..b225b769 100644 --- a/src/bin/ion/output.rs +++ b/src/bin/ion/output.rs @@ -9,7 +9,7 @@ pub enum CommandOutput<'a> { File(FileWriter), } -impl<'a> Write for CommandOutput<'a> { +impl Write for CommandOutput<'_> { fn write(&mut self, buf: &[u8]) -> std::io::Result { use CommandOutput::*; match self { @@ -27,7 +27,7 @@ impl<'a> Write for CommandOutput<'a> { } } -impl<'a> WriteColor for CommandOutput<'a> { +impl WriteColor for CommandOutput<'_> { fn supports_color(&self) -> bool { use CommandOutput::*; match self {