toml_edit-0.22.22/.cargo_vcs_info.json0000644000000001560000000000100131630ustar { "git": { "sha1": "091a0047931e997fe129f3c8fac2788af8091604" }, "path_in_vcs": "crates/toml_edit" }toml_edit-0.22.22/Cargo.lock0000644000000625410000000000100111440ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anstream" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon 1.0.2", "colorchoice", "is-terminal", "utf8parse", ] [[package]] name = "anstream" version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon 3.0.3", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" dependencies = [ "anstyle", "windows-sys 0.48.0", ] [[package]] name = "anstyle-wincon" version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bit-set" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bstr" version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "serde", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "num-traits", ] [[package]] name = "clap" version = "4.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" dependencies = [ "clap_builder", "clap_derive", "once_cell", ] [[package]] name = "clap_builder" version = "4.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" dependencies = [ "anstream 0.3.2", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_derive" version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "clap_lex" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "colorchoice" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "escape8259" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba4f4911e3666fcd7826997b4745c8224295a6f3072f1418c3067b97a67557ee" dependencies = [ "rustversion", ] [[package]] name = "fastrand" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "globset" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", "log", "regex-automata", "regex-syntax", ] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "ignore" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" dependencies = [ "globset", "lazy_static", "log", "memchr", "regex", "same-file", "thread_local", "walkdir", "winapi-util", ] [[package]] name = "include_dir" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" dependencies = [ "include_dir_macros", ] [[package]] name = "include_dir_macros" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ "proc-macro2", "quote", ] [[package]] name = "indexmap" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "is-terminal" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", "libc", "windows-sys 0.52.0", ] [[package]] name = "is_terminal_polyfill" version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b52b2de84ed0341893ce61ca1af04fa54eea0a764ecc38c6855cc5db84dc1927" dependencies = [ "is-terminal", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "kstring" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" dependencies = [ "static_assertions", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libm" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libtest-mimic" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc0bda45ed5b3a2904262c1bb91e526127aa70e7ef3758aba2ef93cf896b9b58" dependencies = [ "clap", "escape8259", "termcolor", "threadpool", ] [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "normalize-line-endings" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", "bitflags", "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", "regex-syntax", "rusty-fork", "tempfile", "unarray", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rand_xorshift" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ "rand_core", ] [[package]] name = "regex" version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rustix" version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "rustversion" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", "quick-error", "tempfile", "wait-timeout", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[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.204" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] [[package]] name = "similar" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" [[package]] name = "snapbox" version = "0.6.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "027c936207f85d10d015e21faf5c676c7e08c453ed371adf55c0874c443ca77a" dependencies = [ "anstream 0.6.14", "anstyle", "normalize-line-endings", "similar", "snapbox-macros", ] [[package]] name = "snapbox-macros" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" dependencies = [ "anstream 0.6.14", ] [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "2.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tempfile" version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", "rustix", "windows-sys 0.52.0", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "thread_local" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", ] [[package]] name = "threadpool" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" dependencies = [ "num_cpus", ] [[package]] name = "toml-test" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9e26681e9154ffb40044019b6bb374f6ed7fef1e367d3d314f0daf2b00faba9" dependencies = [ "chrono", "ryu", "serde", "serde_json", ] [[package]] name = "toml-test-data" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13bb6bf962107303ade738a8f729f4f92c29b2d84c0772cc376f7001602afa1a" dependencies = [ "include_dir", ] [[package]] name = "toml-test-harness" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad65271b9325d4727b1afb346e2eb4cade8e998797682da4e73b7b6d902f2b2" dependencies = [ "ignore", "libtest-mimic", "toml-test", "toml-test-data", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.22" dependencies = [ "indexmap", "kstring", "libtest-mimic", "proptest", "serde", "serde_json", "serde_spanned", "snapbox", "toml-test-data", "toml-test-harness", "toml_datetime", "winnow", ] [[package]] name = "unarray" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ "libc", ] [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi-util" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 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.5", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm 0.52.5", "windows_aarch64_msvc 0.52.5", "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", "windows_i686_msvc 0.52.5", "windows_x86_64_gnu 0.52.5", "windows_x86_64_gnullvm 0.52.5", "windows_x86_64_msvc 0.52.5", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] name = "windows_i686_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] toml_edit-0.22.22/Cargo.toml0000644000000127260000000000100111670ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.65" name = "toml_edit" version = "0.22.22" authors = [ "Andronik Ordian ", "Ed Page ", ] build = false include = [ "build.rs", "src/**/*", "Cargo.toml", "Cargo.lock", "LICENSE*", "README.md", "benches/**/*", "examples/**/*", "tests/**/*", ] autobins = false autoexamples = false autotests = false autobenches = false description = "Yet another format-preserving TOML parser." readme = "README.md" keywords = [ "encoding", "toml", ] categories = [ "encoding", "parser-implementations", "parsing", "config", ] license = "MIT OR Apache-2.0" repository = "https://github.com/toml-rs/toml" [package.metadata.docs.rs] features = ["serde"] rustdoc-args = [ "--cfg", "docsrs", ] [package.metadata.release] tag-name = "v{{version}}" [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" min = 1 replace = "{{version}}" search = "Unreleased" [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "CHANGELOG.md" replace = "...{{tag_name}}" search = '\.\.\.HEAD' [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" min = 1 replace = "{{date}}" search = "ReleaseDate" [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "CHANGELOG.md" replace = """ ## [Unreleased] - ReleaseDate """ search = "" [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "CHANGELOG.md" replace = """ [Unreleased]: https://github.com/toml-rs/toml/compare/{{tag_name}}...HEAD""" search = "" [lib] name = "toml_edit" path = "src/lib.rs" [[example]] name = "visit" path = "examples/visit.rs" test = true required-features = [ "parse", "display", ] [[test]] name = "decoder_compliance" path = "tests/decoder_compliance.rs" harness = false required-features = ["parse"] [[test]] name = "encoder_compliance" path = "tests/encoder_compliance.rs" harness = false required-features = [ "parse", "display", ] [[test]] name = "invalid" path = "tests/invalid.rs" harness = false required-features = [ "parse", "display", ] [[test]] name = "testsuite" path = "tests/testsuite/main.rs" required-features = [ "parse", "display", ] [dependencies.indexmap] version = "2.3.0" features = ["std"] [dependencies.kstring] version = "2.0.0" features = ["max_inline"] optional = true [dependencies.serde] version = "1.0.145" optional = true [dependencies.serde_spanned] version = "0.6.7" features = ["serde"] optional = true [dependencies.toml_datetime] version = "0.6.8" [dependencies.winnow] version = "0.6.18" optional = true [dev-dependencies.libtest-mimic] version = "0.7.2" [dev-dependencies.proptest] version = "1.5.0" [dev-dependencies.serde_json] version = "1.0.116" [dev-dependencies.snapbox] version = "0.6.0" [dev-dependencies.toml-test-data] version = "1.11.0" [dev-dependencies.toml-test-harness] version = "0.4.8" [features] default = [ "parse", "display", ] display = [] parse = ["dep:winnow"] perf = ["dep:kstring"] serde = [ "dep:serde", "toml_datetime/serde", "dep:serde_spanned", ] unbounded = [] [lints.clippy] bool_assert_comparison = "allow" branches_sharing_code = "allow" checked_conversions = "warn" collapsible_else_if = "allow" create_dir = "warn" dbg_macro = "warn" debug_assert_with_mut_call = "warn" doc_markdown = "warn" empty_enum = "warn" enum_glob_use = "warn" expl_impl_clone_on_copy = "warn" explicit_deref_methods = "warn" explicit_into_iter_loop = "warn" fallible_impl_from = "warn" filter_map_next = "warn" flat_map_option = "warn" float_cmp_const = "warn" fn_params_excessive_bools = "warn" from_iter_instead_of_collect = "warn" if_same_then_else = "allow" implicit_clone = "warn" imprecise_flops = "warn" inconsistent_struct_constructor = "warn" inefficient_to_string = "warn" infinite_loop = "warn" invalid_upcast_comparisons = "warn" large_digit_groups = "warn" large_stack_arrays = "warn" large_types_passed_by_value = "warn" let_and_return = "allow" linkedlist = "warn" lossy_float_literal = "warn" macro_use_imports = "warn" mem_forget = "warn" mutex_integer = "warn" needless_continue = "warn" needless_for_each = "warn" negative_feature_names = "warn" path_buf_push_overwrite = "warn" ptr_as_ptr = "warn" rc_mutex = "warn" redundant_feature_names = "warn" ref_option_ref = "warn" rest_pat_in_fully_bound_structs = "warn" same_functions_in_if_condition = "warn" self_named_module_files = "warn" semicolon_if_nothing_returned = "warn" str_to_string = "warn" string_add = "warn" string_add_assign = "warn" string_lit_as_bytes = "warn" string_to_string = "warn" todo = "warn" trait_duplication_in_bounds = "warn" verbose_file_reads = "warn" wildcard_imports = "warn" zero_sized_map_values = "warn" [lints.rust] unreachable_pub = "warn" unsafe_op_in_unsafe_fn = "warn" unused_lifetimes = "warn" unused_macro_rules = "warn" unused_qualifications = "warn" [lints.rust.rust_2018_idioms] level = "warn" priority = -1 toml_edit-0.22.22/Cargo.toml.orig000064400000000000000000000052351046102023000146450ustar 00000000000000[package] name = "toml_edit" version = "0.22.22" keywords = ["encoding", "toml"] categories = ["encoding", "parser-implementations", "parsing", "config"] description = "Yet another format-preserving TOML parser." authors = ["Andronik Ordian ", "Ed Page "] autotests = false repository.workspace = true license.workspace = true edition.workspace = true rust-version.workspace = true include.workspace = true [package.metadata.docs.rs] features = ["serde"] rustdoc-args = ["--cfg", "docsrs"] [package.metadata.release] tag-name = "v{{version}}" pre-release-replacements = [ {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/toml-rs/toml/compare/{{tag_name}}...HEAD", exactly=1}, ] [features] default = ["parse", "display"] parse = ["dep:winnow"] display = [] perf = ["dep:kstring"] serde = ["dep:serde", "toml_datetime/serde", "dep:serde_spanned"] # Provide a method disable_recursion_limit to parse arbitrarily deep structures # without any consideration for overflowing the stack. Additionally you will # need to be careful around other recursive operations on the parsed result # which may overflow the stack after deserialization has completed, including, # but not limited to, Display and Debug and Drop impls. unbounded = [] [dependencies] indexmap = { version = "2.3.0", features = ["std"] } winnow = { version = "0.6.18", optional = true } serde = { version = "1.0.145", optional = true } kstring = { version = "2.0.0", features = ["max_inline"], optional = true } toml_datetime = { version = "0.6.8", path = "../toml_datetime" } serde_spanned = { version = "0.6.7", path = "../serde_spanned", features = ["serde"], optional = true } [dev-dependencies] serde_json = "1.0.116" toml-test-harness = "0.4.8" toml-test-data = "1.11.0" libtest-mimic = "0.7.2" snapbox = "0.6.0" proptest = "1.5.0" [[test]] name = "testsuite" required-features = ["parse", "display"] [[test]] name = "decoder_compliance" required-features = ["parse"] harness = false [[test]] name = "encoder_compliance" required-features = ["parse", "display"] harness = false [[test]] name = "invalid" required-features = ["parse", "display"] harness = false [[example]] name = "visit" required-features = ["parse", "display"] test = true [lints] workspace = true toml_edit-0.22.22/LICENSE-APACHE000064400000000000000000000261361046102023000137050ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. toml_edit-0.22.22/LICENSE-MIT000064400000000000000000000020461046102023000134070ustar 00000000000000Copyright (c) Individual contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. toml_edit-0.22.22/README.md000064400000000000000000000037101046102023000132310ustar 00000000000000# toml_edit [![Build Status](https://github.com/toml-rs/toml/workflows/Continuous%20integration/badge.svg)](https://github.com/toml-rs/toml/actions) [![codecov](https://codecov.io/gh/toml-rs/toml/branch/master/graph/badge.svg)](https://codecov.io/gh/toml-rs/toml) [![crates.io](https://img.shields.io/crates/v/toml_edit.svg)](https://crates.io/crates/toml_edit) [![docs](https://docs.rs/toml_edit/badge.svg)](https://docs.rs/toml_edit) [![Join the chat at https://gitter.im/toml_edit/Lobby](https://badges.gitter.im/a.svg)](https://gitter.im/toml_edit/Lobby) This crate allows you to parse and modify toml documents, while preserving comments, spaces *and relative order* of items. `toml_edit` is primarily tailored for [cargo-edit](https://github.com/killercup/cargo-edit/) needs. ## Example ```rust use toml_edit::{Document, value}; fn main() { let toml = r#" "hello" = 'toml!' # comment ['a'.b] "#; let mut doc = toml.parse::().expect("invalid doc"); assert_eq!(doc.to_string(), toml); // let's add a new key/value pair inside a.b: c = {d = "hello"} doc["a"]["b"]["c"]["d"] = value("hello"); // autoformat inline table a.b.c: { d = "hello" } doc["a"]["b"]["c"].as_inline_table_mut().map(|t| t.fmt()); let expected = r#" "hello" = 'toml!' # comment ['a'.b] c = { d = "hello" } "#; assert_eq!(doc.to_string(), expected); } ``` ## Limitations Things it does not preserve: * Order of dotted keys, see [issue](https://github.com/toml-rs/toml/issues/163). ## License Licensed under either of - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://apache.org/licenses/LICENSE-2.0) - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. toml_edit-0.22.22/examples/visit.rs000064400000000000000000000175521046102023000153050ustar 00000000000000//! Example for how to use `VisitMut` to iterate over a table. use std::collections::BTreeSet; use toml_edit::visit::{visit_table_like_kv, Visit}; use toml_edit::visit_mut::{visit_table_like_kv_mut, visit_table_mut, VisitMut}; use toml_edit::{Array, DocumentMut, InlineTable, Item, KeyMut, Table, Value}; /// This models the visit state for dependency keys in a `Cargo.toml`. /// /// Dependencies can be specified as: /// /// ```toml /// [dependencies] /// dep1 = "0.2" /// /// [build-dependencies] /// dep2 = "0.3" /// /// [dev-dependencies] /// dep3 = "0.4" /// /// [target.'cfg(windows)'.dependencies] /// dep4 = "0.5" /// /// # and target build- and dev-dependencies /// ``` #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum VisitState { /// Represents the root of the table. Root, /// Represents "dependencies", "build-dependencies" or "dev-dependencies", or the target /// forms of these. Dependencies, /// A table within dependencies. SubDependencies, /// Represents "target". Target, /// "target.[TARGET]". TargetWithSpec, /// Represents some other state. Other, } impl VisitState { /// Figures out the next visit state, given the current state and the given key. fn descend(self, key: &str) -> Self { match (self, key) { ( VisitState::Root | VisitState::TargetWithSpec, "dependencies" | "build-dependencies" | "dev-dependencies", ) => VisitState::Dependencies, (VisitState::Root, "target") => VisitState::Target, (VisitState::Root | VisitState::TargetWithSpec, _) => VisitState::Other, (VisitState::Target, _) => VisitState::TargetWithSpec, (VisitState::Dependencies, _) => VisitState::SubDependencies, (VisitState::SubDependencies, _) => VisitState::SubDependencies, (VisitState::Other, _) => VisitState::Other, } } } /// Collect the names of every dependency key. #[derive(Debug)] struct DependencyNameVisitor<'doc> { state: VisitState, names: BTreeSet<&'doc str>, } impl<'doc> Visit<'doc> for DependencyNameVisitor<'doc> { fn visit_table_like_kv(&mut self, key: &'doc str, node: &'doc Item) { if self.state == VisitState::Dependencies { self.names.insert(key); } else { // Since we're only interested in collecting the top-level keys right under // [dependencies], don't recurse unconditionally. let old_state = self.state; // Figure out the next state given the key. self.state = self.state.descend(key); // Recurse further into the document tree. visit_table_like_kv(self, key, node); // Restore the old state after it's done. self.state = old_state; } } } /// Normalize all dependency tables into the format: /// /// ```toml /// [dependencies] /// dep = { version = "1.0", features = ["foo", "bar"], ... } /// ``` /// /// leaving other tables untouched. #[derive(Debug)] struct NormalizeDependencyTablesVisitor { state: VisitState, } impl VisitMut for NormalizeDependencyTablesVisitor { fn visit_table_mut(&mut self, node: &mut Table) { visit_table_mut(self, node); // The conversion from regular tables into inline ones might leave some explicit parent // tables hanging, so convert them to implicit. if matches!(self.state, VisitState::Target | VisitState::TargetWithSpec) { node.set_implicit(true); } } fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, node: &mut Item) { let old_state = self.state; // Figure out the next state given the key. self.state = self.state.descend(key.get()); match self.state { VisitState::Target | VisitState::TargetWithSpec | VisitState::Dependencies => { // Top-level dependency row, or above: turn inline tables into regular ones. if let Item::Value(Value::InlineTable(inline_table)) = node { let inline_table = std::mem::replace(inline_table, InlineTable::new()); let table = inline_table.into_table(); key.fmt(); *node = Item::Table(table); } } VisitState::SubDependencies => { // Individual dependency: turn regular tables into inline ones. if let Item::Table(table) = node { // Turn the table into an inline table. let table = std::mem::replace(table, Table::new()); let inline_table = table.into_inline_table(); key.fmt(); *node = Item::Value(Value::InlineTable(inline_table)); } } _ => {} } // Recurse further into the document tree. visit_table_like_kv_mut(self, key, node); // Restore the old state after it's done. self.state = old_state; } fn visit_array_mut(&mut self, node: &mut Array) { // Format any arrays within dependencies to be on the same line. if matches!( self.state, VisitState::Dependencies | VisitState::SubDependencies ) { node.fmt(); } } } /// This is the input provided to `visit_mut_example`. static INPUT: &str = r#" [package] name = "my-package" [package.metadata.foo] bar = 42 [dependencies] atty = "0.2" cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" } [dependencies.pretty_env_logger] version = "0.4" optional = true [target.'cfg(windows)'.dependencies] fwdansi = "1.1.0" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" features = [ "handleapi", "jobapi", ] [target.'cfg(unix)'] dev-dependencies = { miniz_oxide = "0.5" } [dev-dependencies.cargo-test-macro] path = "crates/cargo-test-macro" [build-dependencies.flate2] version = "0.4" "#; /// This is the output produced by `visit_mut_example`. #[cfg(test)] static VISIT_MUT_OUTPUT: &str = r#" [package] name = "my-package" [package.metadata.foo] bar = 42 [dependencies] atty = "0.2" cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" } pretty_env_logger = { version = "0.4", optional = true } [target.'cfg(windows)'.dependencies] fwdansi = "1.1.0" winapi = { version = "0.3", features = ["handleapi", "jobapi"] } [target.'cfg(unix)'.dev-dependencies] miniz_oxide = "0.5" [dev-dependencies] cargo-test-macro = { path = "crates/cargo-test-macro" } [build-dependencies] flate2 = { version = "0.4" } "#; fn visit_example(document: &DocumentMut) -> BTreeSet<&str> { let mut visitor = DependencyNameVisitor { state: VisitState::Root, names: BTreeSet::new(), }; visitor.visit_document(document); visitor.names } fn visit_mut_example(document: &mut DocumentMut) { let mut visitor = NormalizeDependencyTablesVisitor { state: VisitState::Root, }; visitor.visit_document_mut(document); } fn main() { let mut document: DocumentMut = INPUT.parse().expect("input is valid TOML"); println!("** visit example"); println!("{:?}", visit_example(&document)); println!("** visit_mut example"); visit_mut_example(&mut document); println!("{}", document); } #[cfg(test)] #[test] fn visit_correct() { let document: DocumentMut = INPUT.parse().expect("input is valid TOML"); let names = visit_example(&document); let expected = vec![ "atty", "cargo-platform", "pretty_env_logger", "fwdansi", "winapi", "miniz_oxide", "cargo-test-macro", "flate2", ] .into_iter() .collect(); assert_eq!(names, expected); } #[cfg(test)] #[test] fn visit_mut_correct() { let mut document: DocumentMut = INPUT.parse().expect("input is valid TOML"); visit_mut_example(&mut document); assert_eq!(format!("{}", document), VISIT_MUT_OUTPUT); } toml_edit-0.22.22/src/array.rs000064400000000000000000000322121046102023000142240ustar 00000000000000use std::iter::FromIterator; use std::mem; use crate::repr::Decor; use crate::value::{DEFAULT_LEADING_VALUE_DECOR, DEFAULT_VALUE_DECOR}; use crate::{Item, RawString, Value}; /// Type representing a TOML array, /// payload of the `Value::Array` variant's value #[derive(Debug, Default, Clone)] pub struct Array { // `trailing` represents whitespaces, newlines // and comments in an empty array or after the trailing comma trailing: RawString, trailing_comma: bool, // prefix before `[` and suffix after `]` decor: Decor, pub(crate) span: Option>, // always Vec pub(crate) values: Vec, } /// An owned iterator type over `Table`'s key/value pairs. pub type ArrayIntoIter = Box>; /// An iterator type over `Array`'s values. pub type ArrayIter<'a> = Box + 'a>; /// An iterator type over `Array`'s values. pub type ArrayIterMut<'a> = Box + 'a>; /// Constructors /// /// See also `FromIterator` impl Array { /// Create an empty `Array` /// /// # Examples /// /// ```rust /// let mut arr = toml_edit::Array::new(); /// ``` pub fn new() -> Self { Default::default() } pub(crate) fn with_vec(values: Vec) -> Self { Self { values, ..Default::default() } } } /// Formatting impl Array { /// Auto formats the array. pub fn fmt(&mut self) { decorate_array(self); } /// Set whether the array will use a trailing comma pub fn set_trailing_comma(&mut self, yes: bool) { self.trailing_comma = yes; } /// Whether the array will use a trailing comma pub fn trailing_comma(&self) -> bool { self.trailing_comma } /// Set whitespace after last element pub fn set_trailing(&mut self, trailing: impl Into) { self.trailing = trailing.into(); } /// Whitespace after last element pub fn trailing(&self) -> &RawString { &self.trailing } /// Returns the surrounding whitespace pub fn decor_mut(&mut self) -> &mut Decor { &mut self.decor } /// Returns the surrounding whitespace pub fn decor(&self) -> &Decor { &self.decor } /// The location within the original document /// /// This generally requires an [`ImDocument`][crate::ImDocument]. pub fn span(&self) -> Option> { self.span.clone() } pub(crate) fn despan(&mut self, input: &str) { self.span = None; self.decor.despan(input); self.trailing.despan(input); for value in &mut self.values { value.despan(input); } } } impl Array { /// Returns an iterator over all values. pub fn iter(&self) -> ArrayIter<'_> { Box::new(self.values.iter().filter_map(Item::as_value)) } /// Returns an iterator over all values. pub fn iter_mut(&mut self) -> ArrayIterMut<'_> { Box::new(self.values.iter_mut().filter_map(Item::as_value_mut)) } /// Returns the length of the underlying Vec. /// /// In some rare cases, placeholder elements will exist. For a more accurate count, call /// `a.iter().count()` /// /// # Examples /// /// ```rust /// let mut arr = toml_edit::Array::new(); /// arr.push(1); /// arr.push("foo"); /// assert_eq!(arr.len(), 2); /// ``` pub fn len(&self) -> usize { self.values.len() } /// Return true if `self.len() == 0`. /// /// # Examples /// /// ```rust /// let mut arr = toml_edit::Array::new(); /// assert!(arr.is_empty()); /// /// arr.push(1); /// arr.push("foo"); /// assert!(! arr.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clears the array, removing all values. Keeps the allocated memory for reuse. pub fn clear(&mut self) { self.values.clear(); } /// Returns a reference to the value at the given index, or `None` if the index is out of /// bounds. pub fn get(&self, index: usize) -> Option<&Value> { self.values.get(index).and_then(Item::as_value) } /// Returns a reference to the value at the given index, or `None` if the index is out of /// bounds. pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> { self.values.get_mut(index).and_then(Item::as_value_mut) } /// Appends a new value to the end of the array, applying default formatting to it. /// /// # Examples /// /// ```rust /// let mut arr = toml_edit::Array::new(); /// arr.push(1); /// arr.push("foo"); /// ``` pub fn push>(&mut self, v: V) { self.value_op(v.into(), true, |items, value| { items.push(Item::Value(value)); }); } /// Appends a new, already formatted value to the end of the array. /// /// # Examples /// /// ```rust /// # #[cfg(feature = "parse")] { /// let formatted_value = "'literal'".parse::().unwrap(); /// let mut arr = toml_edit::Array::new(); /// arr.push_formatted(formatted_value); /// # } /// ``` pub fn push_formatted(&mut self, v: Value) { self.values.push(Item::Value(v)); } /// Inserts an element at the given position within the array, applying default formatting to /// it and shifting all values after it to the right. /// /// # Panics /// /// Panics if `index > len`. /// /// # Examples /// /// ```rust /// let mut arr = toml_edit::Array::new(); /// arr.push(1); /// arr.push("foo"); /// /// arr.insert(0, "start"); /// ``` pub fn insert>(&mut self, index: usize, v: V) { self.value_op(v.into(), true, |items, value| { items.insert(index, Item::Value(value)); }); } /// Inserts an already formatted value at the given position within the array, shifting all /// values after it to the right. /// /// # Panics /// /// Panics if `index > len`. /// /// # Examples /// /// ```rust /// # #[cfg(feature = "parse")] { /// let mut arr = toml_edit::Array::new(); /// arr.push(1); /// arr.push("foo"); /// /// let formatted_value = "'start'".parse::().unwrap(); /// arr.insert_formatted(0, formatted_value); /// # } /// ``` pub fn insert_formatted(&mut self, index: usize, v: Value) { self.values.insert(index, Item::Value(v)); } /// Replaces the element at the given position within the array, preserving existing formatting. /// /// # Panics /// /// Panics if `index >= len`. /// /// # Examples /// /// ```rust /// let mut arr = toml_edit::Array::new(); /// arr.push(1); /// arr.push("foo"); /// /// arr.replace(0, "start"); /// ``` pub fn replace>(&mut self, index: usize, v: V) -> Value { // Read the existing value's decor and preserve it. let existing_decor = self .get(index) .unwrap_or_else(|| panic!("index {} out of bounds (len = {})", index, self.len())) .decor(); let mut value = v.into(); *value.decor_mut() = existing_decor.clone(); self.replace_formatted(index, value) } /// Replaces the element at the given position within the array with an already formatted value. /// /// # Panics /// /// Panics if `index >= len`. /// /// # Examples /// /// ```rust /// # #[cfg(feature = "parse")] { /// let mut arr = toml_edit::Array::new(); /// arr.push(1); /// arr.push("foo"); /// /// let formatted_value = "'start'".parse::().unwrap(); /// arr.replace_formatted(0, formatted_value); /// # } /// ``` pub fn replace_formatted(&mut self, index: usize, v: Value) -> Value { match mem::replace(&mut self.values[index], Item::Value(v)) { Item::Value(old_value) => old_value, x => panic!("non-value item {:?} in an array", x), } } /// Removes the value at the given index. /// /// # Examples /// /// ```rust /// let mut arr = toml_edit::Array::new(); /// arr.push(1); /// arr.push("foo"); /// /// arr.remove(0); /// assert_eq!(arr.len(), 1); /// ``` pub fn remove(&mut self, index: usize) -> Value { let removed = self.values.remove(index); match removed { Item::Value(v) => v, x => panic!("non-value item {:?} in an array", x), } } /// Retains only the values specified by the `keep` predicate. /// /// In other words, remove all values for which `keep(&value)` returns `false`. /// /// This method operates in place, visiting each element exactly once in the /// original order, and preserves the order of the retained elements. pub fn retain(&mut self, mut keep: F) where F: FnMut(&Value) -> bool, { self.values .retain(|item| item.as_value().map(&mut keep).unwrap_or(false)); } /// Sorts the slice with a comparator function. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case. /// /// The comparator function must define a total ordering for the elements in the slice. If /// the ordering is not total, the order of the elements is unspecified. An order is a /// total order if it is (for all `a`, `b` and `c`): /// /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. /// /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`. #[inline] pub fn sort_by(&mut self, mut compare: F) where F: FnMut(&Value, &Value) -> std::cmp::Ordering, { self.values.sort_by(move |lhs, rhs| { let lhs = lhs.as_value(); let rhs = rhs.as_value(); match (lhs, rhs) { (None, None) => std::cmp::Ordering::Equal, (Some(_), None) => std::cmp::Ordering::Greater, (None, Some(_)) => std::cmp::Ordering::Less, (Some(lhs), Some(rhs)) => compare(lhs, rhs), } }); } /// Sorts the array with a key extraction function. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) /// worst-case, where the key function is *O*(*m*). #[inline] pub fn sort_by_key(&mut self, mut f: F) where F: FnMut(&Value) -> K, K: Ord, { #[allow(clippy::manual_map)] // needed for lifetimes self.values.sort_by_key(move |item| { if let Some(value) = item.as_value() { Some(f(value)) } else { None } }); } fn value_op( &mut self, v: Value, decorate: bool, op: impl FnOnce(&mut Vec, Value) -> T, ) -> T { let mut value = v; if !self.is_empty() && decorate { value.decorate(" ", ""); } else if decorate { value.decorate("", ""); } op(&mut self.values, value) } } #[cfg(feature = "display")] impl std::fmt::Display for Array { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { crate::encode::encode_array(self, f, None, ("", "")) } } impl> Extend for Array { fn extend>(&mut self, iter: T) { for value in iter { self.push_formatted(value.into()); } } } impl> FromIterator for Array { fn from_iter(iter: I) -> Self where I: IntoIterator, { let v = iter.into_iter().map(|a| Item::Value(a.into())); Array { values: v.collect(), ..Default::default() } } } impl IntoIterator for Array { type Item = Value; type IntoIter = ArrayIntoIter; fn into_iter(self) -> Self::IntoIter { Box::new( self.values .into_iter() .filter(|v| v.is_value()) .map(|v| v.into_value().unwrap()), ) } } impl<'s> IntoIterator for &'s Array { type Item = &'s Value; type IntoIter = ArrayIter<'s>; fn into_iter(self) -> Self::IntoIter { self.iter() } } fn decorate_array(array: &mut Array) { for (i, value) in array .values .iter_mut() .filter_map(Item::as_value_mut) .enumerate() { // [value1, value2, value3] if i == 0 { value.decorate(DEFAULT_LEADING_VALUE_DECOR.0, DEFAULT_LEADING_VALUE_DECOR.1); } else { value.decorate(DEFAULT_VALUE_DECOR.0, DEFAULT_VALUE_DECOR.1); } } // Since everything is now on the same line, remove trailing commas and whitespace. array.set_trailing_comma(false); array.set_trailing(""); } toml_edit-0.22.22/src/array_of_tables.rs000064400000000000000000000112071046102023000162430ustar 00000000000000use std::iter::FromIterator; use crate::{Array, Item, Table}; /// Type representing a TOML array of tables #[derive(Clone, Debug, Default)] pub struct ArrayOfTables { // Always Vec, just `Item` to make `Index` work pub(crate) span: Option>, pub(crate) values: Vec, } /// Constructors /// /// See also `FromIterator` impl ArrayOfTables { /// Creates an empty array of tables. pub fn new() -> Self { Default::default() } } /// Formatting impl ArrayOfTables { /// Convert to an inline array pub fn into_array(mut self) -> Array { for value in self.values.iter_mut() { value.make_value(); } let mut a = Array::with_vec(self.values); a.fmt(); a } /// The location within the original document /// /// This generally requires an [`ImDocument`][crate::ImDocument]. pub fn span(&self) -> Option> { self.span.clone() } pub(crate) fn despan(&mut self, input: &str) { self.span = None; for value in &mut self.values { value.despan(input); } } } impl ArrayOfTables { /// Returns an iterator over tables. pub fn iter(&self) -> ArrayOfTablesIter<'_> { Box::new(self.values.iter().filter_map(Item::as_table)) } /// Returns an iterator over tables. pub fn iter_mut(&mut self) -> ArrayOfTablesIterMut<'_> { Box::new(self.values.iter_mut().filter_map(Item::as_table_mut)) } /// Returns the length of the underlying Vec. /// To get the actual number of items use `a.iter().count()`. pub fn len(&self) -> usize { self.values.len() } /// Returns true if `self.len() == 0`. pub fn is_empty(&self) -> bool { self.len() == 0 } /// Removes all the tables. pub fn clear(&mut self) { self.values.clear(); } /// Returns an optional reference to the table. pub fn get(&self, index: usize) -> Option<&Table> { self.values.get(index).and_then(Item::as_table) } /// Returns an optional mutable reference to the table. pub fn get_mut(&mut self, index: usize) -> Option<&mut Table> { self.values.get_mut(index).and_then(Item::as_table_mut) } /// Appends a table to the array. pub fn push(&mut self, table: Table) { self.values.push(Item::Table(table)); } /// Removes a table with the given index. pub fn remove(&mut self, index: usize) { self.values.remove(index); } /// Retains only the elements specified by the `keep` predicate. /// /// In other words, remove all tables for which `keep(&table)` returns `false`. /// /// This method operates in place, visiting each element exactly once in the /// original order, and preserves the order of the retained elements. pub fn retain(&mut self, mut keep: F) where F: FnMut(&Table) -> bool, { self.values .retain(|item| item.as_table().map(&mut keep).unwrap_or(false)); } } /// An iterator type over `ArrayOfTables`'s values. pub type ArrayOfTablesIter<'a> = Box + 'a>; /// An iterator type over `ArrayOfTables`'s values. pub type ArrayOfTablesIterMut<'a> = Box + 'a>; /// An iterator type over `ArrayOfTables`'s values. pub type ArrayOfTablesIntoIter = Box>; impl Extend for ArrayOfTables { fn extend>(&mut self, iter: T) { for value in iter { self.push(value); } } } impl FromIterator
for ArrayOfTables { fn from_iter(iter: I) -> Self where I: IntoIterator, { let v = iter.into_iter().map(Item::Table); ArrayOfTables { values: v.collect(), span: None, } } } impl IntoIterator for ArrayOfTables { type Item = Table; type IntoIter = ArrayOfTablesIntoIter; fn into_iter(self) -> Self::IntoIter { Box::new( self.values .into_iter() .filter(|v| v.is_table()) .map(|v| v.into_table().unwrap()), ) } } impl<'s> IntoIterator for &'s ArrayOfTables { type Item = &'s Table; type IntoIter = ArrayOfTablesIter<'s>; fn into_iter(self) -> Self::IntoIter { self.iter() } } #[cfg(feature = "display")] impl std::fmt::Display for ArrayOfTables { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // HACK: Without the header, we don't really have a proper way of printing this self.clone().into_array().fmt(f) } } toml_edit-0.22.22/src/de/array.rs000064400000000000000000000050171046102023000146170ustar 00000000000000use crate::de::Error; pub(crate) struct ArrayDeserializer { input: Vec, span: Option>, } impl ArrayDeserializer { pub(crate) fn new(input: Vec, span: Option>) -> Self { Self { input, span } } } // Note: this is wrapped by `ValueDeserializer` and any trait methods // implemented here need to be wrapped there impl<'de> serde::Deserializer<'de> for ArrayDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_seq(ArraySeqAccess::new(self.input)) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { if serde_spanned::__unstable::is_spanned(name, fields) { if let Some(span) = self.span.clone() { return visitor.visit_map(super::SpannedDeserializer::new(self, span)); } } self.deserialize_any(visitor) } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map option unit newtype_struct ignored_any unit_struct tuple_struct tuple enum identifier } } impl<'de> serde::de::IntoDeserializer<'de, Error> for ArrayDeserializer { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } impl crate::Array { pub(crate) fn into_deserializer(self) -> ArrayDeserializer { ArrayDeserializer::new(self.values, self.span) } } impl crate::ArrayOfTables { pub(crate) fn into_deserializer(self) -> ArrayDeserializer { ArrayDeserializer::new(self.values, self.span) } } pub(crate) struct ArraySeqAccess { iter: std::vec::IntoIter, } impl ArraySeqAccess { pub(crate) fn new(input: Vec) -> Self { Self { iter: input.into_iter(), } } } impl<'de> serde::de::SeqAccess<'de> for ArraySeqAccess { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> where T: serde::de::DeserializeSeed<'de>, { match self.iter.next() { Some(v) => seed .deserialize(crate::de::ValueDeserializer::new(v)) .map(Some), None => Ok(None), } } } toml_edit-0.22.22/src/de/datetime.rs000064400000000000000000000021371046102023000152750ustar 00000000000000use serde::de::value::BorrowedStrDeserializer; use serde::de::IntoDeserializer; use crate::de::Error; pub(crate) struct DatetimeDeserializer { date: Option, } impl DatetimeDeserializer { pub(crate) fn new(date: crate::Datetime) -> Self { Self { date: Some(date) } } } impl<'de> serde::de::MapAccess<'de> for DatetimeDeserializer { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result, Error> where K: serde::de::DeserializeSeed<'de>, { if self.date.is_some() { seed.deserialize(BorrowedStrDeserializer::new( toml_datetime::__unstable::FIELD, )) .map(Some) } else { Ok(None) } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { if let Some(date) = self.date.take() { seed.deserialize(date.to_string().into_deserializer()) } else { panic!("next_value_seed called before next_key_seed") } } } toml_edit-0.22.22/src/de/key.rs000064400000000000000000000071211046102023000142670ustar 00000000000000use serde::de::IntoDeserializer; use super::Error; pub(crate) struct KeyDeserializer { span: Option>, key: crate::Key, } impl KeyDeserializer { pub(crate) fn new(key: crate::Key, span: Option>) -> Self { KeyDeserializer { span, key } } } impl<'de> IntoDeserializer<'de, Error> for KeyDeserializer { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } impl<'de> serde::de::Deserializer<'de> for KeyDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { self.key.into_deserializer().deserialize_any(visitor) } fn deserialize_enum( self, name: &str, variants: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { let _ = name; let _ = variants; visitor.visit_enum(self) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { if serde_spanned::__unstable::is_spanned(name, fields) { if let Some(span) = self.span.clone() { return visitor.visit_map(super::SpannedDeserializer::new(self.key.get(), span)); } } self.deserialize_any(visitor) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map option unit ignored_any unit_struct tuple_struct tuple identifier } } impl<'de> serde::de::EnumAccess<'de> for KeyDeserializer { type Error = Error; type Variant = UnitOnly; fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> where T: serde::de::DeserializeSeed<'de>, { seed.deserialize(self).map(unit_only) } } pub(crate) struct UnitOnly { marker: std::marker::PhantomData, } fn unit_only(t: T) -> (T, UnitOnly) { ( t, UnitOnly { marker: std::marker::PhantomData, }, ) } impl<'de, E> serde::de::VariantAccess<'de> for UnitOnly where E: serde::de::Error, { type Error = E; fn unit_variant(self) -> Result<(), Self::Error> { Ok(()) } fn newtype_variant_seed(self, _seed: T) -> Result where T: serde::de::DeserializeSeed<'de>, { Err(serde::de::Error::invalid_type( serde::de::Unexpected::UnitVariant, &"newtype variant", )) } fn tuple_variant(self, _len: usize, _visitor: V) -> Result where V: serde::de::Visitor<'de>, { Err(serde::de::Error::invalid_type( serde::de::Unexpected::UnitVariant, &"tuple variant", )) } fn struct_variant( self, _fields: &'static [&'static str], _visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { Err(serde::de::Error::invalid_type( serde::de::Unexpected::UnitVariant, &"struct variant", )) } } toml_edit-0.22.22/src/de/mod.rs000064400000000000000000000201731046102023000142600ustar 00000000000000//! Deserializing TOML into Rust structures. //! //! This module contains all the Serde support for deserializing TOML documents into Rust structures. use serde::de::DeserializeOwned; mod array; mod datetime; mod key; mod spanned; mod table; mod table_enum; mod value; use array::ArrayDeserializer; use datetime::DatetimeDeserializer; use key::KeyDeserializer; use spanned::SpannedDeserializer; use table_enum::TableEnumDeserializer; pub use value::ValueDeserializer; /// Errors that can occur when deserializing a type. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Error { inner: crate::TomlError, } impl Error { pub(crate) fn custom(msg: T, span: Option>) -> Self where T: std::fmt::Display, { Error { inner: crate::TomlError::custom(msg.to_string(), span), } } /// Add key while unwinding pub fn add_key(&mut self, key: String) { self.inner.add_key(key); } /// What went wrong pub fn message(&self) -> &str { self.inner.message() } /// The start/end index into the original document where the error occurred pub fn span(&self) -> Option> { self.inner.span() } pub(crate) fn set_span(&mut self, span: Option>) { self.inner.set_span(span); } } impl serde::de::Error for Error { fn custom(msg: T) -> Self where T: std::fmt::Display, { Error::custom(msg, None) } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.inner.fmt(f) } } impl From for Error { fn from(e: crate::TomlError) -> Error { Self { inner: e } } } impl From for crate::TomlError { fn from(e: Error) -> crate::TomlError { e.inner } } impl std::error::Error for Error {} /// Convert a TOML [documents][crate::DocumentMut] into `T`. #[cfg(feature = "parse")] pub fn from_str(s: &'_ str) -> Result where T: DeserializeOwned, { let de = Deserializer::parse(s)?; T::deserialize(de) } /// Convert a TOML [documents][crate::DocumentMut] into `T`. #[cfg(feature = "parse")] pub fn from_slice(s: &'_ [u8]) -> Result where T: DeserializeOwned, { let s = std::str::from_utf8(s).map_err(|e| Error::custom(e, None))?; from_str(s) } /// Convert a [`DocumentMut`][crate::DocumentMut] into `T`. pub fn from_document(d: impl Into) -> Result where T: DeserializeOwned, { let deserializer = d.into(); T::deserialize(deserializer) } /// Deserialization for TOML [documents][crate::DocumentMut]. pub struct Deserializer { root: crate::Item, raw: Option, } impl Deserializer { /// Deserialization implementation for TOML. #[deprecated(since = "0.22.6", note = "Replaced with `Deserializer::from`")] pub fn new(input: crate::DocumentMut) -> Self { Self::from(input) } } #[cfg(feature = "parse")] impl> Deserializer { /// Parse a TOML document pub fn parse(raw: S) -> Result { crate::ImDocument::parse(raw) .map(Self::from) .map_err(Into::into) } } impl From for Deserializer { fn from(doc: crate::DocumentMut) -> Self { let crate::DocumentMut { root, .. } = doc; Self { root, raw: None } } } impl From> for Deserializer { fn from(doc: crate::ImDocument) -> Self { let crate::ImDocument { root, raw, .. } = doc; let raw = Some(raw); Self { root, raw } } } #[cfg(feature = "parse")] impl std::str::FromStr for Deserializer { type Err = Error; /// Parses a document from a &str fn from_str(s: &str) -> Result { let doc: crate::ImDocument<_> = s.parse().map_err(Error::from)?; Ok(Deserializer::from(doc)) } } // Note: this is wrapped by `toml::de::Deserializer` and any trait methods // implemented here need to be wrapped there impl<'de, S: Into> serde::Deserializer<'de> for Deserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { let raw = self.raw; self.root .into_deserializer() .deserialize_any(visitor) .map_err(|mut e: Self::Error| { e.inner.set_raw(raw.map(|r| r.into())); e }) } // `None` is interpreted as a missing field so be sure to implement `Some` // as a present field. fn deserialize_option(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { let raw = self.raw; self.root .into_deserializer() .deserialize_option(visitor) .map_err(|mut e: Self::Error| { e.inner.set_raw(raw.map(|r| r.into())); e }) } fn deserialize_newtype_struct( self, name: &'static str, visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { let raw = self.raw; self.root .into_deserializer() .deserialize_newtype_struct(name, visitor) .map_err(|mut e: Self::Error| { e.inner.set_raw(raw.map(|r| r.into())); e }) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { let raw = self.raw; self.root .into_deserializer() .deserialize_struct(name, fields, visitor) .map_err(|mut e: Self::Error| { e.inner.set_raw(raw.map(|r| r.into())); e }) } // Called when the type to deserialize is an enum, as opposed to a field in the type. fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { let raw = self.raw; self.root .into_deserializer() .deserialize_enum(name, variants, visitor) .map_err(|mut e: Self::Error| { e.inner.set_raw(raw.map(|r| r.into())); e }) } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map unit ignored_any unit_struct tuple_struct tuple identifier } } impl<'de> serde::de::IntoDeserializer<'de, Error> for Deserializer { type Deserializer = Deserializer; fn into_deserializer(self) -> Self::Deserializer { self } } impl<'de> serde::de::IntoDeserializer<'de, Error> for crate::DocumentMut { type Deserializer = Deserializer; fn into_deserializer(self) -> Self::Deserializer { Deserializer::from(self) } } impl<'de> serde::de::IntoDeserializer<'de, Error> for crate::ImDocument { type Deserializer = Deserializer; fn into_deserializer(self) -> Self::Deserializer { Deserializer::from(self) } } pub(crate) fn validate_struct_keys( table: &crate::table::KeyValuePairs, fields: &'static [&'static str], ) -> Result<(), Error> { let extra_fields = table .keys() .filter_map(|key| { if !fields.contains(&key.get()) { Some(key.clone()) } else { None } }) .collect::>(); if extra_fields.is_empty() { Ok(()) } else { Err(Error::custom( format!( "unexpected keys in table: {}, available keys: {}", extra_fields .iter() .map(|k| k.get()) .collect::>() .join(", "), fields.join(", "), ), extra_fields[0].span(), )) } } toml_edit-0.22.22/src/de/spanned.rs000064400000000000000000000041421046102023000151270ustar 00000000000000use serde::de::value::BorrowedStrDeserializer; use serde::de::IntoDeserializer as _; use super::Error; pub(crate) struct SpannedDeserializer<'de, T: serde::de::IntoDeserializer<'de, Error>> { phantom_data: std::marker::PhantomData<&'de ()>, start: Option, end: Option, value: Option, } impl<'de, T> SpannedDeserializer<'de, T> where T: serde::de::IntoDeserializer<'de, Error>, { pub(crate) fn new(value: T, span: std::ops::Range) -> Self { Self { phantom_data: Default::default(), start: Some(span.start), end: Some(span.end), value: Some(value), } } } impl<'de, T> serde::de::MapAccess<'de> for SpannedDeserializer<'de, T> where T: serde::de::IntoDeserializer<'de, Error>, { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result, Error> where K: serde::de::DeserializeSeed<'de>, { if self.start.is_some() { seed.deserialize(BorrowedStrDeserializer::new( serde_spanned::__unstable::START_FIELD, )) .map(Some) } else if self.end.is_some() { seed.deserialize(BorrowedStrDeserializer::new( serde_spanned::__unstable::END_FIELD, )) .map(Some) } else if self.value.is_some() { seed.deserialize(BorrowedStrDeserializer::new( serde_spanned::__unstable::VALUE_FIELD, )) .map(Some) } else { Ok(None) } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { if let Some(start) = self.start.take() { seed.deserialize(start.into_deserializer()) } else if let Some(end) = self.end.take() { seed.deserialize(end.into_deserializer()) } else if let Some(value) = self.value.take() { seed.deserialize(value.into_deserializer()) } else { panic!("next_value_seed called before next_key_seed") } } } toml_edit-0.22.22/src/de/table.rs000064400000000000000000000137001046102023000145660ustar 00000000000000use serde::de::IntoDeserializer; use crate::de::Error; pub(crate) struct TableDeserializer { span: Option>, items: crate::table::KeyValuePairs, } // Note: this is wrapped by `Deserializer` and `ValueDeserializer` and any trait methods // implemented here need to be wrapped there impl<'de> serde::Deserializer<'de> for TableDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_map(TableMapAccess::new(self)) } // `None` is interpreted as a missing field so be sure to implement `Some` // as a present field. fn deserialize_option(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_some(self) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { if serde_spanned::__unstable::is_spanned(name, fields) { if let Some(span) = self.span.clone() { return visitor.visit_map(super::SpannedDeserializer::new(self, span)); } } self.deserialize_any(visitor) } // Called when the type to deserialize is an enum, as opposed to a field in the type. fn deserialize_enum( self, _name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { if self.items.is_empty() { Err(Error::custom( "wanted exactly 1 element, found 0 elements", self.span, )) } else if self.items.len() != 1 { Err(Error::custom( "wanted exactly 1 element, more than 1 element", self.span, )) } else { visitor.visit_enum(TableMapAccess::new(self)) } } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map unit ignored_any unit_struct tuple_struct tuple identifier } } impl<'de> IntoDeserializer<'de, Error> for TableDeserializer { type Deserializer = TableDeserializer; fn into_deserializer(self) -> Self::Deserializer { self } } impl crate::Table { pub(crate) fn into_deserializer(self) -> TableDeserializer { TableDeserializer { span: self.span(), items: self.items, } } } impl crate::InlineTable { pub(crate) fn into_deserializer(self) -> TableDeserializer { TableDeserializer { span: self.span(), items: self.items, } } } pub(crate) struct TableMapAccess { iter: indexmap::map::IntoIter, span: Option>, value: Option<(crate::Key, crate::Item)>, } impl TableMapAccess { pub(crate) fn new(input: TableDeserializer) -> Self { Self { iter: input.items.into_iter(), span: input.span, value: None, } } } impl<'de> serde::de::MapAccess<'de> for TableMapAccess { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> where K: serde::de::DeserializeSeed<'de>, { match self.iter.next() { Some((k, v)) => { let key_span = k.span(); let ret = seed .deserialize(super::KeyDeserializer::new(k.clone(), key_span.clone())) .map(Some) .map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(key_span); } e }); self.value = Some((k, v)); ret } None => Ok(None), } } fn next_value_seed(&mut self, seed: V) -> Result where V: serde::de::DeserializeSeed<'de>, { match self.value.take() { Some((k, v)) => { let span = v.span().or_else(|| k.span()); seed.deserialize(crate::de::ValueDeserializer::new(v)) .map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(span); } e.add_key(k.get().to_owned()); e }) } None => { panic!("no more values in next_value_seed, internal error in ValueDeserializer") } } } } impl<'de> serde::de::EnumAccess<'de> for TableMapAccess { type Error = Error; type Variant = super::TableEnumDeserializer; fn variant_seed(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> where V: serde::de::DeserializeSeed<'de>, { let (key, value) = match self.iter.next() { Some(pair) => pair, None => { return Err(Error::custom( "expected table with exactly 1 entry, found empty table", self.span, )); } }; let val = seed .deserialize(key.into_deserializer()) .map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(key.span()); } e })?; let variant = super::TableEnumDeserializer::new(value); Ok((val, variant)) } } toml_edit-0.22.22/src/de/table_enum.rs000064400000000000000000000144061046102023000156160ustar 00000000000000use crate::de::Error; /// Deserializes table values into enum variants. pub(crate) struct TableEnumDeserializer { value: crate::Item, } impl TableEnumDeserializer { pub(crate) fn new(value: crate::Item) -> Self { TableEnumDeserializer { value } } } impl<'de> serde::de::VariantAccess<'de> for TableEnumDeserializer { type Error = Error; fn unit_variant(self) -> Result<(), Self::Error> { match self.value { crate::Item::ArrayOfTables(values) => { if values.is_empty() { Ok(()) } else { Err(Error::custom("expected empty array", values.span())) } } crate::Item::Value(crate::Value::Array(values)) => { if values.is_empty() { Ok(()) } else { Err(Error::custom("expected empty table", values.span())) } } crate::Item::Table(values) => { if values.is_empty() { Ok(()) } else { Err(Error::custom("expected empty table", values.span())) } } crate::Item::Value(crate::Value::InlineTable(values)) => { if values.is_empty() { Ok(()) } else { Err(Error::custom("expected empty table", values.span())) } } e => Err(Error::custom( format!("expected table, found {}", e.type_name()), e.span(), )), } } fn newtype_variant_seed(self, seed: T) -> Result where T: serde::de::DeserializeSeed<'de>, { seed.deserialize(super::ValueDeserializer::new(self.value)) } fn tuple_variant(self, len: usize, visitor: V) -> Result where V: serde::de::Visitor<'de>, { match self.value { crate::Item::ArrayOfTables(values) => { let values_span = values.span(); let tuple_values = values.values.into_iter().collect::>(); if tuple_values.len() == len { serde::de::Deserializer::deserialize_seq( super::ArrayDeserializer::new(tuple_values, values_span), visitor, ) } else { Err(Error::custom( format!("expected tuple with length {}", len), values_span, )) } } crate::Item::Value(crate::Value::Array(values)) => { let values_span = values.span(); let tuple_values = values.values.into_iter().collect::>(); if tuple_values.len() == len { serde::de::Deserializer::deserialize_seq( super::ArrayDeserializer::new(tuple_values, values_span), visitor, ) } else { Err(Error::custom( format!("expected tuple with length {}", len), values_span, )) } } crate::Item::Table(values) => { let values_span = values.span(); let tuple_values: Result, _> = values .items .into_iter() .enumerate() .map(|(index, (key, value))| match key.get().parse::() { Ok(key_index) if key_index == index => Ok(value), Ok(_) | Err(_) => Err(Error::custom( format!("expected table key `{}`, but was `{}`", index, key.get()), key.span(), )), }) .collect(); let tuple_values = tuple_values?; if tuple_values.len() == len { serde::de::Deserializer::deserialize_seq( super::ArrayDeserializer::new(tuple_values, values_span), visitor, ) } else { Err(Error::custom( format!("expected tuple with length {}", len), values_span, )) } } crate::Item::Value(crate::Value::InlineTable(values)) => { let values_span = values.span(); let tuple_values: Result, _> = values .items .into_iter() .enumerate() .map(|(index, (key, value))| match key.get().parse::() { Ok(key_index) if key_index == index => Ok(value), Ok(_) | Err(_) => Err(Error::custom( format!("expected table key `{}`, but was `{}`", index, key.get()), key.span(), )), }) .collect(); let tuple_values = tuple_values?; if tuple_values.len() == len { serde::de::Deserializer::deserialize_seq( super::ArrayDeserializer::new(tuple_values, values_span), visitor, ) } else { Err(Error::custom( format!("expected tuple with length {}", len), values_span, )) } } e => Err(Error::custom( format!("expected table, found {}", e.type_name()), e.span(), )), } } fn struct_variant( self, fields: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { serde::de::Deserializer::deserialize_struct( super::ValueDeserializer::new(self.value).with_struct_key_validation(), "", // TODO: this should be the variant name fields, visitor, ) } } toml_edit-0.22.22/src/de/value.rs000064400000000000000000000177621046102023000146270ustar 00000000000000use serde::de::IntoDeserializer as _; use crate::de::DatetimeDeserializer; use crate::de::Error; /// Deserialization implementation for TOML [values][crate::Value]. /// /// Can be created either directly from TOML strings, using [`std::str::FromStr`], /// or from parsed [values][crate::Value] using [`serde::de::IntoDeserializer::into_deserializer`]. /// /// # Example /// /// ``` /// # #[cfg(feature = "parse")] { /// # #[cfg(feature = "display")] { /// use serde::Deserialize; /// /// #[derive(Deserialize)] /// struct Config { /// title: String, /// owner: Owner, /// } /// /// #[derive(Deserialize)] /// struct Owner { /// name: String, /// } /// /// let value = r#"{ title = 'TOML Example', owner = { name = 'Lisa' } }"#; /// let deserializer = value.parse::().unwrap(); /// let config = Config::deserialize(deserializer).unwrap(); /// assert_eq!(config.title, "TOML Example"); /// assert_eq!(config.owner.name, "Lisa"); /// # } /// # } /// ``` pub struct ValueDeserializer { input: crate::Item, validate_struct_keys: bool, } impl ValueDeserializer { pub(crate) fn new(input: crate::Item) -> Self { Self { input, validate_struct_keys: false, } } pub(crate) fn with_struct_key_validation(mut self) -> Self { self.validate_struct_keys = true; self } } // Note: this is wrapped by `toml::de::ValueDeserializer` and any trait methods // implemented here need to be wrapped there impl<'de> serde::Deserializer<'de> for ValueDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { let span = self.input.span(); match self.input { crate::Item::None => visitor.visit_none(), crate::Item::Value(crate::Value::String(v)) => visitor.visit_string(v.into_value()), crate::Item::Value(crate::Value::Integer(v)) => visitor.visit_i64(v.into_value()), crate::Item::Value(crate::Value::Float(v)) => visitor.visit_f64(v.into_value()), crate::Item::Value(crate::Value::Boolean(v)) => visitor.visit_bool(v.into_value()), crate::Item::Value(crate::Value::Datetime(v)) => { visitor.visit_map(DatetimeDeserializer::new(v.into_value())) } crate::Item::Value(crate::Value::Array(v)) => { v.into_deserializer().deserialize_any(visitor) } crate::Item::Value(crate::Value::InlineTable(v)) => { v.into_deserializer().deserialize_any(visitor) } crate::Item::Table(v) => v.into_deserializer().deserialize_any(visitor), crate::Item::ArrayOfTables(v) => v.into_deserializer().deserialize_any(visitor), } .map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(span); } e }) } // `None` is interpreted as a missing field so be sure to implement `Some` // as a present field. fn deserialize_option(self, visitor: V) -> Result where V: serde::de::Visitor<'de>, { let span = self.input.span(); visitor.visit_some(self).map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(span); } e }) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { let span = self.input.span(); visitor .visit_newtype_struct(self) .map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(span); } e }) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { if serde_spanned::__unstable::is_spanned(name, fields) { if let Some(span) = self.input.span() { return visitor.visit_map(super::SpannedDeserializer::new(self, span)); } } if name == toml_datetime::__unstable::NAME && fields == [toml_datetime::__unstable::FIELD] { let span = self.input.span(); if let crate::Item::Value(crate::Value::Datetime(d)) = self.input { return visitor .visit_map(DatetimeDeserializer::new(d.into_value())) .map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(span); } e }); } } if self.validate_struct_keys { let span = self.input.span(); match &self.input { crate::Item::Table(values) => super::validate_struct_keys(&values.items, fields), crate::Item::Value(crate::Value::InlineTable(values)) => { super::validate_struct_keys(&values.items, fields) } _ => Ok(()), } .map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(span); } e })?; } self.deserialize_any(visitor) } // Called when the type to deserialize is an enum, as opposed to a field in the type. fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: serde::de::Visitor<'de>, { let span = self.input.span(); match self.input { crate::Item::Value(crate::Value::String(v)) => { visitor.visit_enum(v.into_value().into_deserializer()) } crate::Item::Value(crate::Value::InlineTable(v)) => { if v.is_empty() { Err(Error::custom( "wanted exactly 1 element, found 0 elements", v.span(), )) } else if v.len() != 1 { Err(Error::custom( "wanted exactly 1 element, more than 1 element", v.span(), )) } else { v.into_deserializer() .deserialize_enum(name, variants, visitor) } } crate::Item::Table(v) => v .into_deserializer() .deserialize_enum(name, variants, visitor), e => Err(Error::custom("wanted string or table", e.span())), } .map_err(|mut e: Self::Error| { if e.span().is_none() { e.set_span(span); } e }) } serde::forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bytes byte_buf map unit ignored_any unit_struct tuple_struct tuple identifier } } impl<'de> serde::de::IntoDeserializer<'de, Error> for ValueDeserializer { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } impl<'de> serde::de::IntoDeserializer<'de, Error> for crate::Value { type Deserializer = ValueDeserializer; fn into_deserializer(self) -> Self::Deserializer { ValueDeserializer::new(crate::Item::Value(self)) } } impl crate::Item { pub(crate) fn into_deserializer(self) -> ValueDeserializer { ValueDeserializer::new(self) } } #[cfg(feature = "parse")] impl std::str::FromStr for ValueDeserializer { type Err = Error; /// Parses a value from a &str fn from_str(s: &str) -> Result { let v = crate::parser::parse_value(s).map_err(Error::from)?; Ok(v.into_deserializer()) } } toml_edit-0.22.22/src/document.rs000064400000000000000000000113631046102023000147300ustar 00000000000000use std::str::FromStr; use crate::table::Iter; use crate::{Item, RawString, Table}; /// Type representing a parsed TOML document #[derive(Debug, Clone)] pub struct ImDocument { pub(crate) root: Item, // Trailing comments and whitespaces pub(crate) trailing: RawString, pub(crate) raw: S, } impl ImDocument<&'static str> { /// Creates an empty document pub fn new() -> Self { Default::default() } } #[cfg(feature = "parse")] impl> ImDocument { /// Parse a TOML document pub fn parse(raw: S) -> Result { crate::parser::parse_document(raw) } } impl> ImDocument { /// # Panics /// /// If run on on a [`DocumentMut`] not generated by the parser pub(crate) fn despan(&mut self) { self.root.despan(self.raw.as_ref()); self.trailing.despan(self.raw.as_ref()); } } impl ImDocument { /// Returns a reference to the root item. pub fn as_item(&self) -> &Item { &self.root } /// Returns a reference to the root table. pub fn as_table(&self) -> &Table { self.root.as_table().expect("root should always be a table") } /// Returns an iterator over the root table. pub fn iter(&self) -> Iter<'_> { self.as_table().iter() } /// Whitespace after last element pub fn trailing(&self) -> &RawString { &self.trailing } } impl> ImDocument { /// Access the raw, unparsed document pub fn raw(&self) -> &str { self.raw.as_ref() } } impl> ImDocument { /// Allow editing of the [`DocumentMut`] pub fn into_mut(mut self) -> DocumentMut { self.despan(); DocumentMut { root: self.root, trailing: self.trailing, } } } impl Default for ImDocument<&'static str> { fn default() -> Self { Self { root: Item::Table(Table::with_pos(Some(0))), trailing: Default::default(), raw: "", } } } #[cfg(feature = "parse")] impl FromStr for ImDocument { type Err = crate::TomlError; /// Parses a document from a &str fn from_str(s: &str) -> Result { Self::parse(s.to_owned()) } } impl std::ops::Deref for ImDocument { type Target = Table; fn deref(&self) -> &Self::Target { self.as_table() } } /// Type representing a TOML document #[derive(Debug, Clone)] pub struct DocumentMut { pub(crate) root: Item, // Trailing comments and whitespaces pub(crate) trailing: RawString, } impl DocumentMut { /// Creates an empty document pub fn new() -> Self { Default::default() } /// Returns a reference to the root item. pub fn as_item(&self) -> &Item { &self.root } /// Returns a mutable reference to the root item. pub fn as_item_mut(&mut self) -> &mut Item { &mut self.root } /// Returns a reference to the root table. pub fn as_table(&self) -> &Table { self.root.as_table().expect("root should always be a table") } /// Returns a mutable reference to the root table. pub fn as_table_mut(&mut self) -> &mut Table { self.root .as_table_mut() .expect("root should always be a table") } /// Returns an iterator over the root table. pub fn iter(&self) -> Iter<'_> { self.as_table().iter() } /// Set whitespace after last element pub fn set_trailing(&mut self, trailing: impl Into) { self.trailing = trailing.into(); } /// Whitespace after last element pub fn trailing(&self) -> &RawString { &self.trailing } } impl Default for DocumentMut { fn default() -> Self { Self { root: Item::Table(Table::with_pos(Some(0))), trailing: Default::default(), } } } #[cfg(feature = "parse")] impl FromStr for DocumentMut { type Err = crate::TomlError; /// Parses a document from a &str fn from_str(s: &str) -> Result { let im = ImDocument::from_str(s)?; Ok(im.into_mut()) } } impl std::ops::Deref for DocumentMut { type Target = Table; fn deref(&self) -> &Self::Target { self.as_table() } } impl std::ops::DerefMut for DocumentMut { fn deref_mut(&mut self) -> &mut Self::Target { self.as_table_mut() } } impl From
for DocumentMut { fn from(root: Table) -> Self { Self { root: Item::Table(root), ..Default::default() } } } #[test] #[cfg(feature = "parse")] #[cfg(feature = "display")] fn default_roundtrip() { DocumentMut::default() .to_string() .parse::() .unwrap(); } toml_edit-0.22.22/src/encode.rs000064400000000000000000000422201046102023000143430ustar 00000000000000use std::borrow::Cow; use std::fmt::{Display, Formatter, Result, Write}; use toml_datetime::Datetime; use crate::inline_table::DEFAULT_INLINE_KEY_DECOR; use crate::key::Key; use crate::repr::{Formatted, Repr, ValueRepr}; use crate::table::{ DEFAULT_KEY_DECOR, DEFAULT_KEY_PATH_DECOR, DEFAULT_ROOT_DECOR, DEFAULT_TABLE_DECOR, }; use crate::value::{ DEFAULT_LEADING_VALUE_DECOR, DEFAULT_TRAILING_VALUE_DECOR, DEFAULT_VALUE_DECOR, }; use crate::DocumentMut; use crate::{Array, InlineTable, Item, Table, Value}; pub(crate) fn encode_key(this: &Key, buf: &mut dyn Write, input: Option<&str>) -> Result { if let Some(input) = input { let repr = this .as_repr() .map(Cow::Borrowed) .unwrap_or_else(|| Cow::Owned(this.default_repr())); repr.encode(buf, input)?; } else { let repr = this.display_repr(); write!(buf, "{}", repr)?; }; Ok(()) } fn encode_key_path( this: &[Key], buf: &mut dyn Write, input: Option<&str>, default_decor: (&str, &str), ) -> Result { let leaf_decor = this.last().expect("always at least one key").leaf_decor(); for (i, key) in this.iter().enumerate() { let dotted_decor = key.dotted_decor(); let first = i == 0; let last = i + 1 == this.len(); if first { leaf_decor.prefix_encode(buf, input, default_decor.0)?; } else { write!(buf, ".")?; dotted_decor.prefix_encode(buf, input, DEFAULT_KEY_PATH_DECOR.0)?; } encode_key(key, buf, input)?; if last { leaf_decor.suffix_encode(buf, input, default_decor.1)?; } else { dotted_decor.suffix_encode(buf, input, DEFAULT_KEY_PATH_DECOR.1)?; } } Ok(()) } pub(crate) fn encode_key_path_ref( this: &[&Key], buf: &mut dyn Write, input: Option<&str>, default_decor: (&str, &str), ) -> Result { let leaf_decor = this.last().expect("always at least one key").leaf_decor(); for (i, key) in this.iter().enumerate() { let dotted_decor = key.dotted_decor(); let first = i == 0; let last = i + 1 == this.len(); if first { leaf_decor.prefix_encode(buf, input, default_decor.0)?; } else { write!(buf, ".")?; dotted_decor.prefix_encode(buf, input, DEFAULT_KEY_PATH_DECOR.0)?; } encode_key(key, buf, input)?; if last { leaf_decor.suffix_encode(buf, input, default_decor.1)?; } else { dotted_decor.suffix_encode(buf, input, DEFAULT_KEY_PATH_DECOR.1)?; } } Ok(()) } pub(crate) fn encode_formatted( this: &Formatted, buf: &mut dyn Write, input: Option<&str>, default_decor: (&str, &str), ) -> Result { let decor = this.decor(); decor.prefix_encode(buf, input, default_decor.0)?; if let Some(input) = input { let repr = this .as_repr() .map(Cow::Borrowed) .unwrap_or_else(|| Cow::Owned(this.default_repr())); repr.encode(buf, input)?; } else { let repr = this.display_repr(); write!(buf, "{}", repr)?; }; decor.suffix_encode(buf, input, default_decor.1)?; Ok(()) } pub(crate) fn encode_array( this: &Array, buf: &mut dyn Write, input: Option<&str>, default_decor: (&str, &str), ) -> Result { let decor = this.decor(); decor.prefix_encode(buf, input, default_decor.0)?; write!(buf, "[")?; for (i, elem) in this.iter().enumerate() { let inner_decor; if i == 0 { inner_decor = DEFAULT_LEADING_VALUE_DECOR; } else { inner_decor = DEFAULT_VALUE_DECOR; write!(buf, ",")?; } encode_value(elem, buf, input, inner_decor)?; } if this.trailing_comma() && !this.is_empty() { write!(buf, ",")?; } this.trailing().encode_with_default(buf, input, "")?; write!(buf, "]")?; decor.suffix_encode(buf, input, default_decor.1)?; Ok(()) } pub(crate) fn encode_table( this: &InlineTable, buf: &mut dyn Write, input: Option<&str>, default_decor: (&str, &str), ) -> Result { let decor = this.decor(); decor.prefix_encode(buf, input, default_decor.0)?; write!(buf, "{{")?; this.preamble().encode_with_default(buf, input, "")?; let children = this.get_values(); let len = children.len(); for (i, (key_path, value)) in children.into_iter().enumerate() { if i != 0 { write!(buf, ",")?; } let inner_decor = if i == len - 1 { DEFAULT_TRAILING_VALUE_DECOR } else { DEFAULT_VALUE_DECOR }; encode_key_path_ref(&key_path, buf, input, DEFAULT_INLINE_KEY_DECOR)?; write!(buf, "=")?; encode_value(value, buf, input, inner_decor)?; } write!(buf, "}}")?; decor.suffix_encode(buf, input, default_decor.1)?; Ok(()) } pub(crate) fn encode_value( this: &Value, buf: &mut dyn Write, input: Option<&str>, default_decor: (&str, &str), ) -> Result { match this { Value::String(repr) => encode_formatted(repr, buf, input, default_decor), Value::Integer(repr) => encode_formatted(repr, buf, input, default_decor), Value::Float(repr) => encode_formatted(repr, buf, input, default_decor), Value::Boolean(repr) => encode_formatted(repr, buf, input, default_decor), Value::Datetime(repr) => encode_formatted(repr, buf, input, default_decor), Value::Array(array) => encode_array(array, buf, input, default_decor), Value::InlineTable(table) => encode_table(table, buf, input, default_decor), } } impl Display for DocumentMut { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let decor = self.decor(); decor.prefix_encode(f, None, DEFAULT_ROOT_DECOR.0)?; let mut path = Vec::new(); let mut last_position = 0; let mut tables = Vec::new(); visit_nested_tables(self.as_table(), &mut path, false, &mut |t, p, is_array| { if let Some(pos) = t.position() { last_position = pos; } tables.push((last_position, t, p.clone(), is_array)); Ok(()) }) .unwrap(); tables.sort_by_key(|&(id, _, _, _)| id); let mut first_table = true; for (_, table, path, is_array) in tables { visit_table(f, None, table, &path, is_array, &mut first_table)?; } decor.suffix_encode(f, None, DEFAULT_ROOT_DECOR.1)?; self.trailing().encode_with_default(f, None, "") } } fn visit_nested_tables<'t, F>( table: &'t Table, path: &mut Vec, is_array_of_tables: bool, callback: &mut F, ) -> Result where F: FnMut(&'t Table, &Vec, bool) -> Result, { if !table.is_dotted() { callback(table, path, is_array_of_tables)?; } for (key, value) in table.items.iter() { match value { Item::Table(ref t) => { let key = key.clone(); path.push(key); visit_nested_tables(t, path, false, callback)?; path.pop(); } Item::ArrayOfTables(ref a) => { for t in a.iter() { let key = key.clone(); path.push(key); visit_nested_tables(t, path, true, callback)?; path.pop(); } } _ => {} } } Ok(()) } fn visit_table( buf: &mut dyn Write, input: Option<&str>, table: &Table, path: &[Key], is_array_of_tables: bool, first_table: &mut bool, ) -> Result { let children = table.get_values(); // We are intentionally hiding implicit tables without any tables nested under them (ie // `table.is_empty()` which is in contrast to `table.get_values().is_empty()`). We are // trusting the user that an empty implicit table is not semantically meaningful // // This allows a user to delete all tables under this implicit table and the implicit table // will disappear. // // However, this means that users need to take care in deciding what tables get marked as // implicit. let is_visible_std_table = !(table.implicit && children.is_empty()); if path.is_empty() { // don't print header for the root node if !children.is_empty() { *first_table = false; } } else if is_array_of_tables { let default_decor = if *first_table { *first_table = false; ("", DEFAULT_TABLE_DECOR.1) } else { DEFAULT_TABLE_DECOR }; table.decor.prefix_encode(buf, input, default_decor.0)?; write!(buf, "[[")?; encode_key_path(path, buf, input, DEFAULT_KEY_PATH_DECOR)?; write!(buf, "]]")?; table.decor.suffix_encode(buf, input, default_decor.1)?; writeln!(buf)?; } else if is_visible_std_table { let default_decor = if *first_table { *first_table = false; ("", DEFAULT_TABLE_DECOR.1) } else { DEFAULT_TABLE_DECOR }; table.decor.prefix_encode(buf, input, default_decor.0)?; write!(buf, "[")?; encode_key_path(path, buf, input, DEFAULT_KEY_PATH_DECOR)?; write!(buf, "]")?; table.decor.suffix_encode(buf, input, default_decor.1)?; writeln!(buf)?; } // print table body for (key_path, value) in children { encode_key_path_ref(&key_path, buf, input, DEFAULT_KEY_DECOR)?; write!(buf, "=")?; encode_value(value, buf, input, DEFAULT_VALUE_DECOR)?; writeln!(buf)?; } Ok(()) } impl ValueRepr for String { fn to_repr(&self) -> Repr { to_string_repr(self, None, None) } } pub(crate) fn to_string_repr( value: &str, style: Option, literal: Option, ) -> Repr { let (style, literal) = infer_style(value, style, literal); let mut output = String::with_capacity(value.len() * 2); if literal { output.push_str(style.literal_start()); output.push_str(value); output.push_str(style.literal_end()); } else { output.push_str(style.standard_start()); for ch in value.chars() { match ch { '\u{8}' => output.push_str("\\b"), '\u{9}' => output.push_str("\\t"), '\u{a}' => match style { StringStyle::NewlineTriple => output.push('\n'), StringStyle::OnelineSingle => output.push_str("\\n"), StringStyle::OnelineTriple => unreachable!(), }, '\u{c}' => output.push_str("\\f"), '\u{d}' => output.push_str("\\r"), '\u{22}' => output.push_str("\\\""), '\u{5c}' => output.push_str("\\\\"), c if c <= '\u{1f}' || c == '\u{7f}' => { write!(output, "\\u{:04X}", ch as u32).unwrap(); } ch => output.push(ch), } } output.push_str(style.standard_end()); } Repr::new_unchecked(output) } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum StringStyle { NewlineTriple, OnelineTriple, OnelineSingle, } impl StringStyle { fn literal_start(self) -> &'static str { match self { Self::NewlineTriple => "'''\n", Self::OnelineTriple => "'''", Self::OnelineSingle => "'", } } fn literal_end(self) -> &'static str { match self { Self::NewlineTriple => "'''", Self::OnelineTriple => "'''", Self::OnelineSingle => "'", } } fn standard_start(self) -> &'static str { match self { Self::NewlineTriple => "\"\"\"\n", // note: OnelineTriple can happen if do_pretty wants to do // '''it's one line''' // but literal == false Self::OnelineTriple | Self::OnelineSingle => "\"", } } fn standard_end(self) -> &'static str { match self { Self::NewlineTriple => "\"\"\"", // note: OnelineTriple can happen if do_pretty wants to do // '''it's one line''' // but literal == false Self::OnelineTriple | Self::OnelineSingle => "\"", } } } fn infer_style( value: &str, style: Option, literal: Option, ) -> (StringStyle, bool) { match (style, literal) { (Some(style), Some(literal)) => (style, literal), (None, Some(literal)) => (infer_all_style(value).0, literal), (Some(style), None) => { let literal = infer_literal(value); (style, literal) } (None, None) => infer_all_style(value), } } fn infer_literal(value: &str) -> bool { #[cfg(feature = "parse")] { use winnow::stream::ContainsToken as _; (value.contains('"') | value.contains('\\')) && value .chars() .all(|c| crate::parser::strings::LITERAL_CHAR.contains_token(c)) } #[cfg(not(feature = "parse"))] { false } } fn infer_all_style(value: &str) -> (StringStyle, bool) { // We need to determine: // - if we are a "multi-line" pretty (if there are \n) // - if ['''] appears if multi or ['] if single // - if there are any invalid control characters // // Doing it any other way would require multiple passes // to determine if a pretty string works or not. let mut ty = StringStyle::OnelineSingle; // found consecutive single quotes let mut max_found_singles = 0; let mut found_singles = 0; let mut prefer_literal = false; let mut can_be_pretty = true; for ch in value.chars() { if can_be_pretty { if ch == '\'' { found_singles += 1; if found_singles >= 3 { can_be_pretty = false; } } else { if found_singles > max_found_singles { max_found_singles = found_singles; } found_singles = 0; } match ch { '\t' => {} '"' => { prefer_literal = true; } '\\' => { prefer_literal = true; } '\n' => ty = StringStyle::NewlineTriple, // Escape codes are needed if any ascii control // characters are present, including \b \f \r. c if c <= '\u{1f}' || c == '\u{7f}' => can_be_pretty = false, _ => {} } } else { // the string cannot be represented as pretty, // still check if it should be multiline if ch == '\n' { ty = StringStyle::NewlineTriple; } } } if found_singles > 0 && value.ends_with('\'') { // We cannot escape the ending quote so we must use """ can_be_pretty = false; } if !prefer_literal { can_be_pretty = false; } if !can_be_pretty { debug_assert!(ty != StringStyle::OnelineTriple); return (ty, false); } if found_singles > max_found_singles { max_found_singles = found_singles; } debug_assert!(max_found_singles < 3); if ty == StringStyle::OnelineSingle && max_found_singles >= 1 { // no newlines, but must use ''' because it has ' in it ty = StringStyle::OnelineTriple; } (ty, true) } impl ValueRepr for i64 { fn to_repr(&self) -> Repr { Repr::new_unchecked(self.to_string()) } } impl ValueRepr for f64 { fn to_repr(&self) -> Repr { to_f64_repr(*self) } } fn to_f64_repr(f: f64) -> Repr { let repr = match (f.is_sign_negative(), f.is_nan(), f == 0.0) { (true, true, _) => "-nan".to_owned(), (false, true, _) => "nan".to_owned(), (true, false, true) => "-0.0".to_owned(), (false, false, true) => "0.0".to_owned(), (_, false, false) => { if f % 1.0 == 0.0 { format!("{}.0", f) } else { format!("{}", f) } } }; Repr::new_unchecked(repr) } impl ValueRepr for bool { fn to_repr(&self) -> Repr { Repr::new_unchecked(self.to_string()) } } impl ValueRepr for Datetime { fn to_repr(&self) -> Repr { Repr::new_unchecked(self.to_string()) } } #[cfg(test)] mod test { use super::*; use proptest::prelude::*; proptest! { #[test] #[cfg(feature = "parse")] fn parseable_string(string in "\\PC*") { let string = Value::from(string); let encoded = string.to_string(); let _: Value = encoded.parse().unwrap_or_else(|err| { panic!("error: {err} string: ``` {string} ``` ") }); } } proptest! { #[test] #[cfg(feature = "parse")] fn parseable_key(string in "\\PC*") { let string = Key::new(string); let encoded = string.to_string(); let _: Key = encoded.parse().unwrap_or_else(|err| { panic!("error: {err} string: ``` {string} ``` ") }); } } } toml_edit-0.22.22/src/error.rs000064400000000000000000000153521046102023000142450ustar 00000000000000use std::error::Error as StdError; use std::fmt::{Display, Formatter, Result}; /// Type representing a TOML parse error #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct TomlError { message: String, raw: Option, keys: Vec, span: Option>, } impl TomlError { #[cfg(feature = "parse")] pub(crate) fn new( error: winnow::error::ParseError< crate::parser::prelude::Input<'_>, winnow::error::ContextError, >, mut raw: crate::parser::prelude::Input<'_>, ) -> Self { use winnow::stream::Stream; let message = error.inner().to_string(); let raw = raw.finish(); let raw = String::from_utf8(raw.to_owned()).expect("original document was utf8"); let offset = error.offset(); let offset = (0..=offset) .rev() .find(|index| raw.is_char_boundary(*index)) .unwrap_or(0); let mut indices = raw[offset..].char_indices(); indices.next(); let len = if let Some((index, _)) = indices.next() { index } else { raw.len() - offset }; let span = offset..(offset + len); Self { message, raw: Some(raw), keys: Vec::new(), span: Some(span), } } #[cfg(any(feature = "serde", feature = "parse"))] pub(crate) fn custom(message: String, span: Option>) -> Self { Self { message, raw: None, keys: Vec::new(), span, } } #[cfg(feature = "serde")] pub(crate) fn add_key(&mut self, key: String) { self.keys.insert(0, key); } /// What went wrong pub fn message(&self) -> &str { &self.message } /// The start/end index into the original document where the error occurred pub fn span(&self) -> Option> { self.span.clone() } #[cfg(feature = "serde")] pub(crate) fn set_span(&mut self, span: Option>) { self.span = span; } #[cfg(feature = "serde")] pub(crate) fn set_raw(&mut self, raw: Option) { self.raw = raw; } } /// Displays a TOML parse error /// /// # Example /// /// TOML parse error at line 1, column 10 /// | /// 1 | 00:32:00.a999999 /// | ^ /// Unexpected `a` /// Expected `digit` /// While parsing a Time /// While parsing a Date-Time impl Display for TomlError { fn fmt(&self, f: &mut Formatter<'_>) -> Result { let mut context = false; if let (Some(raw), Some(span)) = (&self.raw, self.span()) { context = true; let (line, column) = translate_position(raw.as_bytes(), span.start); let line_num = line + 1; let col_num = column + 1; let gutter = line_num.to_string().len(); let content = raw.split('\n').nth(line).expect("valid line number"); let highlight_len = span.end - span.start; // Allow highlight to go one past the line let highlight_len = highlight_len.min(content.len().saturating_sub(column)); writeln!( f, "TOML parse error at line {}, column {}", line_num, col_num )?; // | for _ in 0..=gutter { write!(f, " ")?; } writeln!(f, "|")?; // 1 | 00:32:00.a999999 write!(f, "{} | ", line_num)?; writeln!(f, "{}", content)?; // | ^ for _ in 0..=gutter { write!(f, " ")?; } write!(f, "|")?; for _ in 0..=column { write!(f, " ")?; } // The span will be empty at eof, so we need to make sure we always print at least // one `^` write!(f, "^")?; for _ in 1..highlight_len { write!(f, "^")?; } writeln!(f)?; } writeln!(f, "{}", self.message)?; if !context && !self.keys.is_empty() { writeln!(f, "in `{}`", self.keys.join("."))?; } Ok(()) } } impl StdError for TomlError { fn description(&self) -> &'static str { "TOML parse error" } } fn translate_position(input: &[u8], index: usize) -> (usize, usize) { if input.is_empty() { return (0, index); } let safe_index = index.min(input.len() - 1); let column_offset = index - safe_index; let index = safe_index; let nl = input[0..index] .iter() .rev() .enumerate() .find(|(_, b)| **b == b'\n') .map(|(nl, _)| index - nl - 1); let line_start = match nl { Some(nl) => nl + 1, None => 0, }; let line = input[0..line_start].iter().filter(|b| **b == b'\n').count(); let column = std::str::from_utf8(&input[line_start..=index]) .map(|s| s.chars().count() - 1) .unwrap_or_else(|_| index - line_start); let column = column + column_offset; (line, column) } #[cfg(test)] mod test_translate_position { use super::*; #[test] fn empty() { let input = b""; let index = 0; let position = translate_position(&input[..], index); assert_eq!(position, (0, 0)); } #[test] fn start() { let input = b"Hello"; let index = 0; let position = translate_position(&input[..], index); assert_eq!(position, (0, 0)); } #[test] fn end() { let input = b"Hello"; let index = input.len() - 1; let position = translate_position(&input[..], index); assert_eq!(position, (0, input.len() - 1)); } #[test] fn after() { let input = b"Hello"; let index = input.len(); let position = translate_position(&input[..], index); assert_eq!(position, (0, input.len())); } #[test] fn first_line() { let input = b"Hello\nWorld\n"; let index = 2; let position = translate_position(&input[..], index); assert_eq!(position, (0, 2)); } #[test] fn end_of_line() { let input = b"Hello\nWorld\n"; let index = 5; let position = translate_position(&input[..], index); assert_eq!(position, (0, 5)); } #[test] fn start_of_second_line() { let input = b"Hello\nWorld\n"; let index = 6; let position = translate_position(&input[..], index); assert_eq!(position, (1, 0)); } #[test] fn second_line() { let input = b"Hello\nWorld\n"; let index = 8; let position = translate_position(&input[..], index); assert_eq!(position, (1, 2)); } } toml_edit-0.22.22/src/index.rs000064400000000000000000000073201046102023000142170ustar 00000000000000use std::ops; use crate::key::Key; use crate::DocumentMut; use crate::{value, InlineTable, Item, Table, Value}; // copied from // https://github.com/serde-rs/json/blob/master/src/value/index.rs pub trait Index: crate::private::Sealed { #[doc(hidden)] fn index<'v>(&self, val: &'v Item) -> Option<&'v Item>; #[doc(hidden)] fn index_mut<'v>(&self, val: &'v mut Item) -> Option<&'v mut Item>; } impl Index for usize { fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { match *v { Item::ArrayOfTables(ref aot) => aot.values.get(*self), Item::Value(ref a) if a.is_array() => a.as_array().and_then(|a| a.values.get(*self)), _ => None, } } fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { match *v { Item::ArrayOfTables(ref mut vec) => vec.values.get_mut(*self), Item::Value(ref mut a) => a.as_array_mut().and_then(|a| a.values.get_mut(*self)), _ => None, } } } impl Index for str { fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { match *v { Item::Table(ref t) => t.get(self), Item::Value(ref v) => v .as_inline_table() .and_then(|t| t.items.get(self)) .and_then(|value| if !value.is_none() { Some(value) } else { None }), _ => None, } } fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { if let Item::None = *v { let mut t = InlineTable::default(); t.items.insert(Key::new(self), Item::None); *v = value(Value::InlineTable(t)); } match *v { Item::Table(ref mut t) => Some(t.entry(self).or_insert(Item::None)), Item::Value(ref mut v) => v .as_inline_table_mut() .map(|t| t.items.entry(Key::new(self)).or_insert_with(|| Item::None)), _ => None, } } } impl Index for String { fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { self[..].index(v) } fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { self[..].index_mut(v) } } impl<'a, T: ?Sized> Index for &'a T where T: Index, { fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { (**self).index(v) } fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { (**self).index_mut(v) } } impl ops::Index for Item where I: Index, { type Output = Item; fn index(&self, index: I) -> &Item { index.index(self).expect("index not found") } } impl ops::IndexMut for Item where I: Index, { fn index_mut(&mut self, index: I) -> &mut Item { index.index_mut(self).expect("index not found") } } impl<'s> ops::Index<&'s str> for Table { type Output = Item; fn index(&self, key: &'s str) -> &Item { self.get(key).expect("index not found") } } impl<'s> ops::IndexMut<&'s str> for Table { fn index_mut(&mut self, key: &'s str) -> &mut Item { self.entry(key).or_insert(Item::None) } } impl<'s> ops::Index<&'s str> for InlineTable { type Output = Value; fn index(&self, key: &'s str) -> &Value { self.get(key).expect("index not found") } } impl<'s> ops::IndexMut<&'s str> for InlineTable { fn index_mut(&mut self, key: &'s str) -> &mut Value { self.get_mut(key).expect("index not found") } } impl<'s> ops::Index<&'s str> for DocumentMut { type Output = Item; fn index(&self, key: &'s str) -> &Item { self.root.index(key) } } impl<'s> ops::IndexMut<&'s str> for DocumentMut { fn index_mut(&mut self, key: &'s str) -> &mut Item { self.root.index_mut(key) } } toml_edit-0.22.22/src/inline_table.rs000064400000000000000000000572271046102023000155500ustar 00000000000000use std::iter::FromIterator; use crate::key::Key; use crate::repr::Decor; use crate::table::{Iter, IterMut, KeyValuePairs, TableLike}; use crate::{InternalString, Item, KeyMut, RawString, Table, Value}; /// Type representing a TOML inline table, /// payload of the `Value::InlineTable` variant #[derive(Debug, Default, Clone)] pub struct InlineTable { // `preamble` represents whitespaces in an empty table preamble: RawString, // Whether to hide an empty table pub(crate) implicit: bool, // prefix before `{` and suffix after `}` decor: Decor, pub(crate) span: Option>, // whether this is a proxy for dotted keys dotted: bool, pub(crate) items: KeyValuePairs, } /// Constructors /// /// See also `FromIterator` impl InlineTable { /// Creates an empty table. pub fn new() -> Self { Default::default() } pub(crate) fn with_pairs(items: KeyValuePairs) -> Self { Self { items, ..Default::default() } } /// Convert to a table pub fn into_table(self) -> Table { let mut t = Table::with_pairs(self.items); t.fmt(); t } } /// Formatting impl InlineTable { /// Get key/values for values that are visually children of this table /// /// For example, this will return dotted keys pub fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { let mut values = Vec::new(); let root = Vec::new(); self.append_values(&root, &mut values); values } pub(crate) fn append_values<'s>( &'s self, parent: &[&'s Key], values: &mut Vec<(Vec<&'s Key>, &'s Value)>, ) { for (key, value) in self.items.iter() { let mut path = parent.to_vec(); path.push(key); match value { Item::Value(Value::InlineTable(table)) if table.is_dotted() => { table.append_values(&path, values); } Item::Value(value) => { values.push((path, value)); } _ => {} } } } /// Auto formats the table. pub fn fmt(&mut self) { decorate_inline_table(self); } /// Sorts the key/value pairs by key. pub fn sort_values(&mut self) { // Assuming standard tables have their position set and this won't negatively impact them self.items.sort_keys(); for value in self.items.values_mut() { match value { Item::Value(Value::InlineTable(table)) if table.is_dotted() => { table.sort_values(); } _ => {} } } } /// Sort Key/Value Pairs of the table using the using the comparison function `compare`. /// /// The comparison function receives two key and value pairs to compare (you can sort by keys or /// values or their combination as needed). pub fn sort_values_by(&mut self, mut compare: F) where F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering, { self.sort_values_by_internal(&mut compare); } fn sort_values_by_internal(&mut self, compare: &mut F) where F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering, { let modified_cmp = |key1: &Key, val1: &Item, key2: &Key, val2: &Item| -> std::cmp::Ordering { match (val1.as_value(), val2.as_value()) { (Some(v1), Some(v2)) => compare(key1, v1, key2, v2), (Some(_), None) => std::cmp::Ordering::Greater, (None, Some(_)) => std::cmp::Ordering::Less, (None, None) => std::cmp::Ordering::Equal, } }; self.items.sort_by(modified_cmp); for value in self.items.values_mut() { match value { Item::Value(Value::InlineTable(table)) if table.is_dotted() => { table.sort_values_by_internal(compare); } _ => {} } } } /// If a table has no key/value pairs and implicit, it will not be displayed. /// /// # Examples /// /// ```notrust /// [target."x86_64/windows.json".dependencies] /// ``` /// /// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit. /// /// ``` /// # #[cfg(feature = "parse")] { /// # #[cfg(feature = "display")] { /// use toml_edit::DocumentMut; /// let mut doc = "[a]\n[a.b]\n".parse::().expect("invalid toml"); /// /// doc["a"].as_table_mut().unwrap().set_implicit(true); /// assert_eq!(doc.to_string(), "[a.b]\n"); /// # } /// # } /// ``` pub(crate) fn set_implicit(&mut self, implicit: bool) { self.implicit = implicit; } /// If a table has no key/value pairs and implicit, it will not be displayed. pub(crate) fn is_implicit(&self) -> bool { self.implicit } /// Change this table's dotted status pub fn set_dotted(&mut self, yes: bool) { self.dotted = yes; } /// Check if this is a wrapper for dotted keys, rather than a standard table pub fn is_dotted(&self) -> bool { self.dotted } /// Returns the surrounding whitespace pub fn decor_mut(&mut self) -> &mut Decor { &mut self.decor } /// Returns the surrounding whitespace pub fn decor(&self) -> &Decor { &self.decor } /// Returns an accessor to a key's formatting pub fn key(&self, key: &str) -> Option<&'_ Key> { self.items.get_full(key).map(|(_, key, _)| key) } /// Returns an accessor to a key's formatting pub fn key_mut(&mut self, key: &str) -> Option> { use indexmap::map::MutableKeys; self.items .get_full_mut2(key) .map(|(_, key, _)| key.as_mut()) } /// Returns the decor associated with a given key of the table. #[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")] pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { #![allow(deprecated)] use indexmap::map::MutableKeys; self.items .get_full_mut2(key) .map(|(_, key, _)| key.leaf_decor_mut()) } /// Returns the decor associated with a given key of the table. #[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")] pub fn key_decor(&self, key: &str) -> Option<&Decor> { #![allow(deprecated)] self.items.get_full(key).map(|(_, key, _)| key.leaf_decor()) } /// Set whitespace after before element pub fn set_preamble(&mut self, preamble: impl Into) { self.preamble = preamble.into(); } /// Whitespace after before element pub fn preamble(&self) -> &RawString { &self.preamble } /// The location within the original document /// /// This generally requires an [`ImDocument`][crate::ImDocument]. pub fn span(&self) -> Option> { self.span.clone() } pub(crate) fn despan(&mut self, input: &str) { use indexmap::map::MutableKeys; self.span = None; self.decor.despan(input); self.preamble.despan(input); for (key, value) in self.items.iter_mut2() { key.despan(input); value.despan(input); } } } impl InlineTable { /// Returns an iterator over key/value pairs. pub fn iter(&self) -> InlineTableIter<'_> { Box::new( self.items .iter() .filter(|(_, value)| !value.is_none()) .map(|(key, value)| (key.get(), value.as_value().unwrap())), ) } /// Returns an iterator over key/value pairs. pub fn iter_mut(&mut self) -> InlineTableIterMut<'_> { use indexmap::map::MutableKeys; Box::new( self.items .iter_mut2() .filter(|(_, value)| value.is_value()) .map(|(key, value)| (key.as_mut(), value.as_value_mut().unwrap())), ) } /// Returns the number of key/value pairs. pub fn len(&self) -> usize { self.iter().count() } /// Returns true if the table is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse. pub fn clear(&mut self) { self.items.clear(); } /// Gets the given key's corresponding entry in the Table for in-place manipulation. pub fn entry(&'_ mut self, key: impl Into) -> InlineEntry<'_> { match self.items.entry(key.into().into()) { indexmap::map::Entry::Occupied(mut entry) => { // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code. let scratch = std::mem::take(entry.get_mut()); let scratch = Item::Value( scratch .into_value() // HACK: `Item::None` is a corner case of a corner case, let's just pick a // "safe" value .unwrap_or_else(|_| Value::InlineTable(Default::default())), ); *entry.get_mut() = scratch; InlineEntry::Occupied(InlineOccupiedEntry { entry }) } indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry { entry }), } } /// Gets the given key's corresponding entry in the Table for in-place manipulation. pub fn entry_format<'a>(&'a mut self, key: &Key) -> InlineEntry<'a> { // Accept a `&Key` to be consistent with `entry` match self.items.entry(key.clone()) { indexmap::map::Entry::Occupied(mut entry) => { // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code. let scratch = std::mem::take(entry.get_mut()); let scratch = Item::Value( scratch .into_value() // HACK: `Item::None` is a corner case of a corner case, let's just pick a // "safe" value .unwrap_or_else(|_| Value::InlineTable(Default::default())), ); *entry.get_mut() = scratch; InlineEntry::Occupied(InlineOccupiedEntry { entry }) } indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry { entry }), } } /// Return an optional reference to the value at the given the key. pub fn get(&self, key: &str) -> Option<&Value> { self.items.get(key).and_then(|value| value.as_value()) } /// Return an optional mutable reference to the value at the given the key. pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> { self.items .get_mut(key) .and_then(|value| value.as_value_mut()) } /// Return references to the key-value pair stored for key, if it is present, else None. pub fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { self.items.get_full(key).and_then(|(_, key, value)| { if !value.is_none() { Some((key, value)) } else { None } }) } /// Return mutable references to the key-value pair stored for key, if it is present, else None. pub fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { use indexmap::map::MutableKeys; self.items.get_full_mut2(key).and_then(|(_, key, value)| { if !value.is_none() { Some((key.as_mut(), value)) } else { None } }) } /// Returns true if the table contains given key. pub fn contains_key(&self, key: &str) -> bool { if let Some(value) = self.items.get(key) { value.is_value() } else { false } } /// Inserts a key/value pair if the table does not contain the key. /// Returns a mutable reference to the corresponding value. pub fn get_or_insert>( &mut self, key: impl Into, value: V, ) -> &mut Value { let key = key.into(); self.items .entry(Key::new(key)) .or_insert(Item::Value(value.into())) .as_value_mut() .expect("non-value type in inline table") } /// Inserts a key-value pair into the map. pub fn insert(&mut self, key: impl Into, value: Value) -> Option { use indexmap::map::MutableEntryKey; let key = Key::new(key); let value = Item::Value(value); match self.items.entry(key.clone()) { indexmap::map::Entry::Occupied(mut entry) => { entry.key_mut().fmt(); let old = std::mem::replace(entry.get_mut(), value); old.into_value().ok() } indexmap::map::Entry::Vacant(entry) => { entry.insert(value); None } } } /// Inserts a key-value pair into the map. pub fn insert_formatted(&mut self, key: &Key, value: Value) -> Option { use indexmap::map::MutableEntryKey; let value = Item::Value(value); match self.items.entry(key.clone()) { indexmap::map::Entry::Occupied(mut entry) => { *entry.key_mut() = key.clone(); let old = std::mem::replace(entry.get_mut(), value); old.into_value().ok() } indexmap::map::Entry::Vacant(entry) => { entry.insert(value); None } } } /// Removes an item given the key. pub fn remove(&mut self, key: &str) -> Option { self.items .shift_remove(key) .and_then(|value| value.into_value().ok()) } /// Removes a key from the map, returning the stored key and value if the key was previously in the map. pub fn remove_entry(&mut self, key: &str) -> Option<(Key, Value)> { self.items .shift_remove_entry(key) .and_then(|(key, value)| Some((key, value.into_value().ok()?))) } /// Retains only the elements specified by the `keep` predicate. /// /// In other words, remove all pairs `(key, value)` for which /// `keep(&key, &mut value)` returns `false`. /// /// The elements are visited in iteration order. pub fn retain(&mut self, mut keep: F) where F: FnMut(&str, &mut Value) -> bool, { self.items.retain(|key, item| { item.as_value_mut() .map(|value| keep(key, value)) .unwrap_or(false) }); } } #[cfg(feature = "display")] impl std::fmt::Display for InlineTable { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { crate::encode::encode_table(self, f, None, ("", "")) } } impl, V: Into> Extend<(K, V)> for InlineTable { fn extend>(&mut self, iter: T) { for (key, value) in iter { let key = key.into(); let value = Item::Value(value.into()); self.items.insert(key, value); } } } impl, V: Into> FromIterator<(K, V)> for InlineTable { fn from_iter(iter: I) -> Self where I: IntoIterator, { let mut table = InlineTable::new(); table.extend(iter); table } } impl IntoIterator for InlineTable { type Item = (InternalString, Value); type IntoIter = InlineTableIntoIter; fn into_iter(self) -> Self::IntoIter { Box::new( self.items .into_iter() .filter(|(_, value)| value.is_value()) .map(|(key, value)| (key.into(), value.into_value().unwrap())), ) } } impl<'s> IntoIterator for &'s InlineTable { type Item = (&'s str, &'s Value); type IntoIter = InlineTableIter<'s>; fn into_iter(self) -> Self::IntoIter { self.iter() } } fn decorate_inline_table(table: &mut InlineTable) { use indexmap::map::MutableKeys; for (mut key, value) in table .items .iter_mut2() .filter(|(_, value)| value.is_value()) .map(|(key, value)| (key.as_mut(), value.as_value_mut().unwrap())) { key.leaf_decor_mut().clear(); key.dotted_decor_mut().clear(); value.decor_mut().clear(); } } /// An owned iterator type over key/value pairs of an inline table. pub type InlineTableIntoIter = Box>; /// An iterator type over key/value pairs of an inline table. pub type InlineTableIter<'a> = Box + 'a>; /// A mutable iterator type over key/value pairs of an inline table. pub type InlineTableIterMut<'a> = Box, &'a mut Value)> + 'a>; impl TableLike for InlineTable { fn iter(&self) -> Iter<'_> { Box::new(self.items.iter().map(|(key, value)| (key.get(), value))) } fn iter_mut(&mut self) -> IterMut<'_> { use indexmap::map::MutableKeys; Box::new( self.items .iter_mut2() .map(|(key, value)| (key.as_mut(), value)), ) } fn clear(&mut self) { self.clear(); } fn entry<'a>(&'a mut self, key: &str) -> crate::Entry<'a> { // Accept a `&str` rather than an owned type to keep `InternalString`, well, internal match self.items.entry(key.into()) { indexmap::map::Entry::Occupied(entry) => { crate::Entry::Occupied(crate::OccupiedEntry { entry }) } indexmap::map::Entry::Vacant(entry) => { crate::Entry::Vacant(crate::VacantEntry { entry }) } } } fn entry_format<'a>(&'a mut self, key: &Key) -> crate::Entry<'a> { // Accept a `&Key` to be consistent with `entry` match self.items.entry(key.get().into()) { indexmap::map::Entry::Occupied(entry) => { crate::Entry::Occupied(crate::OccupiedEntry { entry }) } indexmap::map::Entry::Vacant(entry) => { crate::Entry::Vacant(crate::VacantEntry { entry }) } } } fn get<'s>(&'s self, key: &str) -> Option<&'s Item> { self.items.get(key) } fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> { self.items.get_mut(key) } fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { self.get_key_value(key) } fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { self.get_key_value_mut(key) } fn contains_key(&self, key: &str) -> bool { self.contains_key(key) } fn insert(&mut self, key: &str, value: Item) -> Option { self.insert(key, value.into_value().unwrap()) .map(Item::Value) } fn remove(&mut self, key: &str) -> Option { self.remove(key).map(Item::Value) } fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { self.get_values() } fn fmt(&mut self) { self.fmt(); } fn sort_values(&mut self) { self.sort_values(); } fn set_dotted(&mut self, yes: bool) { self.set_dotted(yes); } fn is_dotted(&self) -> bool { self.is_dotted() } fn key(&self, key: &str) -> Option<&'_ Key> { self.key(key) } fn key_mut(&mut self, key: &str) -> Option> { self.key_mut(key) } fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { #![allow(deprecated)] self.key_decor_mut(key) } fn key_decor(&self, key: &str) -> Option<&Decor> { #![allow(deprecated)] self.key_decor(key) } } // `{ key1 = value1, ... }` pub(crate) const DEFAULT_INLINE_KEY_DECOR: (&str, &str) = (" ", " "); /// A view into a single location in a map, which may be vacant or occupied. pub enum InlineEntry<'a> { /// An occupied Entry. Occupied(InlineOccupiedEntry<'a>), /// A vacant Entry. Vacant(InlineVacantEntry<'a>), } impl<'a> InlineEntry<'a> { /// Returns the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("hello", map.entry("hello").key()); /// ``` pub fn key(&self) -> &str { match self { InlineEntry::Occupied(e) => e.key(), InlineEntry::Vacant(e) => e.key(), } } /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. pub fn or_insert(self, default: Value) -> &'a mut Value { match self { InlineEntry::Occupied(entry) => entry.into_mut(), InlineEntry::Vacant(entry) => entry.insert(default), } } /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. pub fn or_insert_with Value>(self, default: F) -> &'a mut Value { match self { InlineEntry::Occupied(entry) => entry.into_mut(), InlineEntry::Vacant(entry) => entry.insert(default()), } } } /// A view into a single occupied location in a `IndexMap`. pub struct InlineOccupiedEntry<'a> { entry: indexmap::map::OccupiedEntry<'a, Key, Item>, } impl<'a> InlineOccupiedEntry<'a> { /// Gets a reference to the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("foo", map.entry("foo").key()); /// ``` pub fn key(&self) -> &str { self.entry.key().get() } /// Gets a mutable reference to the entry key pub fn key_mut(&mut self) -> KeyMut<'_> { use indexmap::map::MutableEntryKey; self.entry.key_mut().as_mut() } /// Gets a reference to the value in the entry. pub fn get(&self) -> &Value { self.entry.get().as_value().unwrap() } /// Gets a mutable reference to the value in the entry. pub fn get_mut(&mut self) -> &mut Value { self.entry.get_mut().as_value_mut().unwrap() } /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry /// with a lifetime bound to the map itself pub fn into_mut(self) -> &'a mut Value { self.entry.into_mut().as_value_mut().unwrap() } /// Sets the value of the entry, and returns the entry's old value pub fn insert(&mut self, value: Value) -> Value { let value = Item::Value(value); self.entry.insert(value).into_value().unwrap() } /// Takes the value out of the entry, and returns it pub fn remove(self) -> Value { self.entry.shift_remove().into_value().unwrap() } } /// A view into a single empty location in a `IndexMap`. pub struct InlineVacantEntry<'a> { entry: indexmap::map::VacantEntry<'a, Key, Item>, } impl<'a> InlineVacantEntry<'a> { /// Gets a reference to the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("foo", map.entry("foo").key()); /// ``` pub fn key(&self) -> &str { self.entry.key().get() } /// Sets the value of the entry with the `VacantEntry`'s key, /// and returns a mutable reference to it pub fn insert(self, value: Value) -> &'a mut Value { let entry = self.entry; let value = Item::Value(value); entry.insert(value).as_value_mut().unwrap() } } toml_edit-0.22.22/src/internal_string.rs000064400000000000000000000101311046102023000163040ustar 00000000000000use std::borrow::Borrow; use std::str::FromStr; /// Opaque string storage internal to `toml_edit` #[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct InternalString(Inner); #[cfg(feature = "perf")] type Inner = kstring::KString; #[cfg(not(feature = "perf"))] type Inner = String; impl InternalString { /// Create an empty string pub fn new() -> Self { InternalString(Inner::new()) } /// Access the underlying string #[inline] pub fn as_str(&self) -> &str { self.0.as_str() } } impl std::fmt::Debug for InternalString { #[inline] fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { self.0.fmt(formatter) } } impl std::ops::Deref for InternalString { type Target = str; #[inline] fn deref(&self) -> &str { self.as_str() } } impl Borrow for InternalString { #[inline] fn borrow(&self) -> &str { self.as_str() } } impl AsRef for InternalString { #[inline] fn as_ref(&self) -> &str { self.as_str() } } impl From<&str> for InternalString { #[inline] fn from(s: &str) -> Self { #[cfg(feature = "perf")] let inner = kstring::KString::from_ref(s); #[cfg(not(feature = "perf"))] let inner = String::from(s); InternalString(inner) } } impl From for InternalString { #[inline] fn from(s: String) -> Self { #[allow(clippy::useless_conversion)] // handle any string type InternalString(s.into()) } } impl From<&String> for InternalString { #[inline] fn from(s: &String) -> Self { InternalString(s.into()) } } impl From<&InternalString> for InternalString { #[inline] fn from(s: &InternalString) -> Self { s.clone() } } impl From> for InternalString { #[inline] fn from(s: Box) -> Self { InternalString(s.into()) } } impl FromStr for InternalString { type Err = core::convert::Infallible; #[inline] fn from_str(s: &str) -> Result { Ok(Self::from(s)) } } impl std::fmt::Display for InternalString { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_str().fmt(f) } } #[cfg(feature = "serde")] impl serde::Serialize for InternalString { #[inline] fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_str(self.as_str()) } } #[cfg(feature = "serde")] impl<'de> serde::Deserialize<'de> for InternalString { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { deserializer.deserialize_string(StringVisitor) } } #[cfg(feature = "serde")] struct StringVisitor; #[cfg(feature = "serde")] impl<'de> serde::de::Visitor<'de> for StringVisitor { type Value = InternalString; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("a string") } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { Ok(InternalString::from(v)) } fn visit_string(self, v: String) -> Result where E: serde::de::Error, { Ok(InternalString::from(v)) } fn visit_bytes(self, v: &[u8]) -> Result where E: serde::de::Error, { match std::str::from_utf8(v) { Ok(s) => Ok(InternalString::from(s)), Err(_) => Err(serde::de::Error::invalid_value( serde::de::Unexpected::Bytes(v), &self, )), } } fn visit_byte_buf(self, v: Vec) -> Result where E: serde::de::Error, { match String::from_utf8(v) { Ok(s) => Ok(InternalString::from(s)), Err(e) => Err(serde::de::Error::invalid_value( serde::de::Unexpected::Bytes(&e.into_bytes()), &self, )), } } } toml_edit-0.22.22/src/item.rs000064400000000000000000000277271046102023000140630ustar 00000000000000use std::str::FromStr; use toml_datetime::Datetime; use crate::array_of_tables::ArrayOfTables; use crate::table::TableLike; use crate::{Array, InlineTable, Table, Value}; /// Type representing either a value, a table, an array of tables, or none. #[derive(Debug, Default)] pub enum Item { /// Type representing none. #[default] None, /// Type representing value. Value(Value), /// Type representing table. Table(Table), /// Type representing array of tables. ArrayOfTables(ArrayOfTables), } impl Item { /// Sets `self` to the given item if `self` is none and /// returns a mutable reference to `self`. pub fn or_insert(&mut self, item: Item) -> &mut Item { if self.is_none() { *self = item; } self } } // TODO: This should be generated by macro or derive /// Downcasting impl Item { /// Text description of value type pub fn type_name(&self) -> &'static str { match self { Item::None => "none", Item::Value(v) => v.type_name(), Item::Table(..) => "table", Item::ArrayOfTables(..) => "array of tables", } } /// Index into a TOML array or map. A string index can be used to access a /// value in a map, and a usize index can be used to access an element of an /// array. /// /// Returns `None` if: /// - The type of `self` does not match the type of the /// index, for example if the index is a string and `self` is an array or a /// number. /// - The given key does not exist in the map /// or the given index is not within the bounds of the array. pub fn get(&self, index: I) -> Option<&Item> { index.index(self) } /// Mutably index into a TOML array or map. A string index can be used to /// access a value in a map, and a usize index can be used to access an /// element of an array. /// /// Returns `None` if: /// - The type of `self` does not match the type of the /// index, for example if the index is a string and `self` is an array or a /// number. /// - The given key does not exist in the map /// or the given index is not within the bounds of the array. pub fn get_mut(&mut self, index: I) -> Option<&mut Item> { index.index_mut(self) } /// Casts `self` to value. pub fn as_value(&self) -> Option<&Value> { match *self { Item::Value(ref v) => Some(v), _ => None, } } /// Casts `self` to table. pub fn as_table(&self) -> Option<&Table> { match *self { Item::Table(ref t) => Some(t), _ => None, } } /// Casts `self` to array of tables. pub fn as_array_of_tables(&self) -> Option<&ArrayOfTables> { match *self { Item::ArrayOfTables(ref a) => Some(a), _ => None, } } /// Casts `self` to mutable value. pub fn as_value_mut(&mut self) -> Option<&mut Value> { match *self { Item::Value(ref mut v) => Some(v), _ => None, } } /// Casts `self` to mutable table. pub fn as_table_mut(&mut self) -> Option<&mut Table> { match *self { Item::Table(ref mut t) => Some(t), _ => None, } } /// Casts `self` to mutable array of tables. pub fn as_array_of_tables_mut(&mut self) -> Option<&mut ArrayOfTables> { match *self { Item::ArrayOfTables(ref mut a) => Some(a), _ => None, } } /// Casts `self` to value. pub fn into_value(self) -> Result { match self { Item::None => Err(self), Item::Value(v) => Ok(v), Item::Table(v) => { let v = v.into_inline_table(); Ok(Value::InlineTable(v)) } Item::ArrayOfTables(v) => { let v = v.into_array(); Ok(Value::Array(v)) } } } /// In-place convert to a value pub fn make_value(&mut self) { let other = std::mem::take(self); let other = other.into_value().map(Item::Value).unwrap_or(Item::None); *self = other; } /// Casts `self` to table. pub fn into_table(self) -> Result { match self { Item::Table(t) => Ok(t), Item::Value(Value::InlineTable(t)) => Ok(t.into_table()), _ => Err(self), } } /// Casts `self` to array of tables. pub fn into_array_of_tables(self) -> Result { match self { Item::ArrayOfTables(a) => Ok(a), Item::Value(Value::Array(a)) => { if a.is_empty() { Err(Item::Value(Value::Array(a))) } else if a.iter().all(|v| v.is_inline_table()) { let mut aot = ArrayOfTables::new(); aot.values = a.values; for value in aot.values.iter_mut() { value.make_item(); } Ok(aot) } else { Err(Item::Value(Value::Array(a))) } } _ => Err(self), } } // Starting private because the name is unclear pub(crate) fn make_item(&mut self) { let other = std::mem::take(self); let other = match other.into_table().map(Item::Table) { Ok(i) => i, Err(i) => i, }; let other = match other.into_array_of_tables().map(Item::ArrayOfTables) { Ok(i) => i, Err(i) => i, }; *self = other; } /// Returns true if `self` is a value. pub fn is_value(&self) -> bool { self.as_value().is_some() } /// Returns true if `self` is a table. pub fn is_table(&self) -> bool { self.as_table().is_some() } /// Returns true if `self` is an array of tables. pub fn is_array_of_tables(&self) -> bool { self.as_array_of_tables().is_some() } /// Returns true if `self` is `None`. pub fn is_none(&self) -> bool { matches!(*self, Item::None) } // Duplicate Value downcasting API /// Casts `self` to integer. pub fn as_integer(&self) -> Option { self.as_value().and_then(Value::as_integer) } /// Returns true if `self` is an integer. pub fn is_integer(&self) -> bool { self.as_integer().is_some() } /// Casts `self` to float. pub fn as_float(&self) -> Option { self.as_value().and_then(Value::as_float) } /// Returns true if `self` is a float. pub fn is_float(&self) -> bool { self.as_float().is_some() } /// Casts `self` to boolean. pub fn as_bool(&self) -> Option { self.as_value().and_then(Value::as_bool) } /// Returns true if `self` is a boolean. pub fn is_bool(&self) -> bool { self.as_bool().is_some() } /// Casts `self` to str. pub fn as_str(&self) -> Option<&str> { self.as_value().and_then(Value::as_str) } /// Returns true if `self` is a string. pub fn is_str(&self) -> bool { self.as_str().is_some() } /// Casts `self` to date-time. pub fn as_datetime(&self) -> Option<&Datetime> { self.as_value().and_then(Value::as_datetime) } /// Returns true if `self` is a date-time. pub fn is_datetime(&self) -> bool { self.as_datetime().is_some() } /// Casts `self` to array. pub fn as_array(&self) -> Option<&Array> { self.as_value().and_then(Value::as_array) } /// Casts `self` to mutable array. pub fn as_array_mut(&mut self) -> Option<&mut Array> { self.as_value_mut().and_then(Value::as_array_mut) } /// Returns true if `self` is an array. pub fn is_array(&self) -> bool { self.as_array().is_some() } /// Casts `self` to inline table. pub fn as_inline_table(&self) -> Option<&InlineTable> { self.as_value().and_then(Value::as_inline_table) } /// Casts `self` to mutable inline table. pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> { self.as_value_mut().and_then(Value::as_inline_table_mut) } /// Returns true if `self` is an inline table. pub fn is_inline_table(&self) -> bool { self.as_inline_table().is_some() } /// Casts `self` to either a table or an inline table. pub fn as_table_like(&self) -> Option<&dyn TableLike> { self.as_table() .map(|t| t as &dyn TableLike) .or_else(|| self.as_inline_table().map(|t| t as &dyn TableLike)) } /// Casts `self` to either a table or an inline table. pub fn as_table_like_mut(&mut self) -> Option<&mut dyn TableLike> { match self { Item::Table(t) => Some(t as &mut dyn TableLike), Item::Value(Value::InlineTable(t)) => Some(t as &mut dyn TableLike), _ => None, } } /// Returns true if `self` is either a table, or an inline table. pub fn is_table_like(&self) -> bool { self.as_table_like().is_some() } /// The location within the original document /// /// This generally requires an [`ImDocument`][crate::ImDocument]. pub fn span(&self) -> Option> { match self { Item::None => None, Item::Value(v) => v.span(), Item::Table(v) => v.span(), Item::ArrayOfTables(v) => v.span(), } } pub(crate) fn despan(&mut self, input: &str) { match self { Item::None => {} Item::Value(v) => v.despan(input), Item::Table(v) => v.despan(input), Item::ArrayOfTables(v) => v.despan(input), } } } impl Clone for Item { #[inline(never)] fn clone(&self) -> Self { match self { Item::None => Item::None, Item::Value(v) => Item::Value(v.clone()), Item::Table(v) => Item::Table(v.clone()), Item::ArrayOfTables(v) => Item::ArrayOfTables(v.clone()), } } } #[cfg(feature = "parse")] impl FromStr for Item { type Err = crate::TomlError; /// Parses a value from a &str fn from_str(s: &str) -> Result { let value = s.parse::()?; Ok(Item::Value(value)) } } impl<'b> From<&'b Item> for Item { fn from(s: &'b Item) -> Self { s.clone() } } impl> From for Item { fn from(s: V) -> Self { Item::Value(s.into()) } } #[cfg(feature = "display")] impl std::fmt::Display for Item { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self { Item::None => Ok(()), Item::Value(v) => v.fmt(f), Item::Table(v) => v.fmt(f), Item::ArrayOfTables(v) => v.fmt(f), } } } /// Returns a formatted value. /// /// Since formatting is part of a `Value`, the right hand side of the /// assignment needs to be decorated with a space before the value. /// The `value` function does just that. /// /// # Examples /// ```rust /// # #[cfg(feature = "display")] { /// # #[cfg(feature = "parse")] { /// # use toml_edit::*; /// let mut table = Table::default(); /// let mut array = Array::default(); /// array.push("hello"); /// array.push("\\, world"); // \ is only allowed in a literal string /// table["key1"] = value("value1"); /// table["key2"] = value(42); /// table["key3"] = value(array); /// assert_eq!(table.to_string(), /// r#"key1 = "value1" /// key2 = 42 /// key3 = ["hello", '\, world'] /// "#); /// # } /// # } /// ``` pub fn value>(v: V) -> Item { Item::Value(v.into()) } /// Returns an empty table. pub fn table() -> Item { Item::Table(Table::new()) } /// Returns an empty array of tables. pub fn array() -> Item { Item::ArrayOfTables(ArrayOfTables::new()) } #[test] #[cfg(feature = "parse")] #[cfg(feature = "display")] fn string_roundtrip() { value("hello").to_string().parse::().unwrap(); } toml_edit-0.22.22/src/key.rs000064400000000000000000000255421046102023000137060ustar 00000000000000use std::borrow::Cow; use std::str::FromStr; use crate::repr::{Decor, Repr}; use crate::InternalString; /// Key as part of a Key/Value Pair or a table header. /// /// # Examples /// /// ```notrust /// [dependencies."nom"] /// version = "5.0" /// 'literal key' = "nonsense" /// "basic string key" = 42 /// ``` /// /// There are 3 types of keys: /// /// 1. Bare keys (`version` and `dependencies`) /// /// 2. Basic quoted keys (`"basic string key"` and `"nom"`) /// /// 3. Literal quoted keys (`'literal key'`) /// /// For details see [toml spec](https://github.com/toml-lang/toml/#keyvalue-pair). /// /// To parse a key use `FromStr` trait implementation: `"string".parse::()`. #[derive(Debug)] pub struct Key { key: InternalString, pub(crate) repr: Option, pub(crate) leaf_decor: Decor, pub(crate) dotted_decor: Decor, } impl Key { /// Create a new table key pub fn new(key: impl Into) -> Self { Self { key: key.into(), repr: None, leaf_decor: Default::default(), dotted_decor: Default::default(), } } /// Parse a TOML key expression /// /// Unlike `"".parse()`, this supports dotted keys. #[cfg(feature = "parse")] pub fn parse(repr: &str) -> Result, crate::TomlError> { Self::try_parse_path(repr) } pub(crate) fn with_repr_unchecked(mut self, repr: Repr) -> Self { self.repr = Some(repr); self } /// While creating the `Key`, add `Decor` to it #[deprecated(since = "0.21.1", note = "Replaced with `with_leaf_decor`")] pub fn with_decor(self, decor: Decor) -> Self { self.with_leaf_decor(decor) } /// While creating the `Key`, add `Decor` to it for the line entry pub fn with_leaf_decor(mut self, decor: Decor) -> Self { self.leaf_decor = decor; self } /// While creating the `Key`, add `Decor` to it for between dots pub fn with_dotted_decor(mut self, decor: Decor) -> Self { self.dotted_decor = decor; self } /// Access a mutable proxy for the `Key`. pub fn as_mut(&mut self) -> KeyMut<'_> { KeyMut { key: self } } /// Returns the parsed key value. pub fn get(&self) -> &str { &self.key } /// Returns key raw representation, if available. pub fn as_repr(&self) -> Option<&Repr> { self.repr.as_ref() } /// Returns the default raw representation. #[cfg(feature = "display")] pub fn default_repr(&self) -> Repr { to_key_repr(&self.key) } /// Returns a raw representation. #[cfg(feature = "display")] pub fn display_repr(&self) -> Cow<'_, str> { self.as_repr() .and_then(|r| r.as_raw().as_str()) .map(Cow::Borrowed) .unwrap_or_else(|| { Cow::Owned(self.default_repr().as_raw().as_str().unwrap().to_owned()) }) } /// Returns the surrounding whitespace #[deprecated( since = "0.21.1", note = "Replaced with `dotted_decor_mut`, `leaf_decor_mut" )] pub fn decor_mut(&mut self) -> &mut Decor { self.leaf_decor_mut() } /// Returns the surrounding whitespace for the line entry pub fn leaf_decor_mut(&mut self) -> &mut Decor { &mut self.leaf_decor } /// Returns the surrounding whitespace for between dots pub fn dotted_decor_mut(&mut self) -> &mut Decor { &mut self.dotted_decor } /// Returns the surrounding whitespace #[deprecated(since = "0.21.1", note = "Replaced with `dotted_decor`, `leaf_decor")] pub fn decor(&self) -> &Decor { self.leaf_decor() } /// Returns the surrounding whitespace for the line entry pub fn leaf_decor(&self) -> &Decor { &self.leaf_decor } /// Returns the surrounding whitespace for between dots pub fn dotted_decor(&self) -> &Decor { &self.dotted_decor } /// The location within the original document /// /// This generally requires an [`ImDocument`][crate::ImDocument]. pub fn span(&self) -> Option> { self.repr.as_ref().and_then(|r| r.span()) } pub(crate) fn despan(&mut self, input: &str) { self.leaf_decor.despan(input); self.dotted_decor.despan(input); if let Some(repr) = &mut self.repr { repr.despan(input); } } /// Auto formats the key. pub fn fmt(&mut self) { self.repr = None; self.leaf_decor.clear(); self.dotted_decor.clear(); } #[cfg(feature = "parse")] fn try_parse_simple(s: &str) -> Result { let mut key = crate::parser::parse_key(s)?; key.despan(s); Ok(key) } #[cfg(feature = "parse")] fn try_parse_path(s: &str) -> Result, crate::TomlError> { let mut keys = crate::parser::parse_key_path(s)?; for key in &mut keys { key.despan(s); } Ok(keys) } } impl Clone for Key { #[inline(never)] fn clone(&self) -> Self { Self { key: self.key.clone(), repr: self.repr.clone(), leaf_decor: self.leaf_decor.clone(), dotted_decor: self.dotted_decor.clone(), } } } impl std::ops::Deref for Key { type Target = str; fn deref(&self) -> &Self::Target { self.get() } } impl std::borrow::Borrow for Key { #[inline] fn borrow(&self) -> &str { self.get() } } impl std::hash::Hash for Key { fn hash(&self, state: &mut H) { self.get().hash(state); } } impl Ord for Key { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.get().cmp(other.get()) } } impl PartialOrd for Key { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Eq for Key {} impl PartialEq for Key { #[inline] fn eq(&self, other: &Key) -> bool { PartialEq::eq(self.get(), other.get()) } } impl PartialEq for Key { #[inline] fn eq(&self, other: &str) -> bool { PartialEq::eq(self.get(), other) } } impl<'s> PartialEq<&'s str> for Key { #[inline] fn eq(&self, other: &&str) -> bool { PartialEq::eq(self.get(), *other) } } impl PartialEq for Key { #[inline] fn eq(&self, other: &String) -> bool { PartialEq::eq(self.get(), other.as_str()) } } #[cfg(feature = "display")] impl std::fmt::Display for Key { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { crate::encode::encode_key(self, f, None) } } #[cfg(feature = "parse")] impl FromStr for Key { type Err = crate::TomlError; /// Tries to parse a key from a &str, /// if fails, tries as basic quoted key (surrounds with "") /// and then literal quoted key (surrounds with '') fn from_str(s: &str) -> Result { Key::try_parse_simple(s) } } #[cfg(feature = "display")] fn to_key_repr(key: &str) -> Repr { #[cfg(feature = "parse")] { if key .as_bytes() .iter() .copied() .all(crate::parser::key::is_unquoted_char) && !key.is_empty() { Repr::new_unchecked(key) } else { crate::encode::to_string_repr( key, Some(crate::encode::StringStyle::OnelineSingle), None, ) } } #[cfg(not(feature = "parse"))] { crate::encode::to_string_repr(key, Some(crate::encode::StringStyle::OnelineSingle), None) } } impl<'b> From<&'b str> for Key { fn from(s: &'b str) -> Self { Key::new(s) } } impl<'b> From<&'b String> for Key { fn from(s: &'b String) -> Self { Key::new(s) } } impl From for Key { fn from(s: String) -> Self { Key::new(s) } } impl From for Key { fn from(s: InternalString) -> Self { Key::new(s) } } #[doc(hidden)] impl From for InternalString { fn from(key: Key) -> InternalString { key.key } } /// A mutable reference to a `Key`'s formatting #[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct KeyMut<'k> { key: &'k mut Key, } impl<'k> KeyMut<'k> { /// Returns the parsed key value. pub fn get(&self) -> &str { self.key.get() } /// Returns the raw representation, if available. pub fn as_repr(&self) -> Option<&Repr> { self.key.as_repr() } /// Returns the default raw representation. #[cfg(feature = "display")] pub fn default_repr(&self) -> Repr { self.key.default_repr() } /// Returns a raw representation. #[cfg(feature = "display")] pub fn display_repr(&self) -> Cow<'_, str> { self.key.display_repr() } /// Returns the surrounding whitespace #[deprecated( since = "0.21.1", note = "Replaced with `dotted_decor_mut`, `leaf_decor_mut" )] pub fn decor_mut(&mut self) -> &mut Decor { #![allow(deprecated)] self.key.decor_mut() } /// Returns the surrounding whitespace for the line entry pub fn leaf_decor_mut(&mut self) -> &mut Decor { self.key.leaf_decor_mut() } /// Returns the surrounding whitespace for between dots pub fn dotted_decor_mut(&mut self) -> &mut Decor { self.key.dotted_decor_mut() } /// Returns the surrounding whitespace #[deprecated(since = "0.21.1", note = "Replaced with `dotted_decor`, `leaf_decor")] pub fn decor(&self) -> &Decor { #![allow(deprecated)] self.key.decor() } /// Returns the surrounding whitespace for the line entry pub fn leaf_decor(&self) -> &Decor { self.key.leaf_decor() } /// Returns the surrounding whitespace for between dots pub fn dotted_decor(&self) -> &Decor { self.key.dotted_decor() } /// Auto formats the key. pub fn fmt(&mut self) { self.key.fmt(); } } impl<'k> std::ops::Deref for KeyMut<'k> { type Target = str; fn deref(&self) -> &Self::Target { self.get() } } impl<'s> PartialEq for KeyMut<'s> { #[inline] fn eq(&self, other: &str) -> bool { PartialEq::eq(self.get(), other) } } impl<'s> PartialEq<&'s str> for KeyMut<'s> { #[inline] fn eq(&self, other: &&str) -> bool { PartialEq::eq(self.get(), *other) } } impl<'s> PartialEq for KeyMut<'s> { #[inline] fn eq(&self, other: &String) -> bool { PartialEq::eq(self.get(), other.as_str()) } } #[cfg(feature = "display")] impl<'k> std::fmt::Display for KeyMut<'k> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.key, f) } } #[test] #[cfg(feature = "parse")] #[cfg(feature = "display")] fn string_roundtrip() { Key::new("hello").to_string().parse::().unwrap(); } toml_edit-0.22.22/src/lib.rs000064400000000000000000000075241046102023000136640ustar 00000000000000//! # `toml_edit` //! //! This crate allows you to parse and modify toml //! documents, while preserving comments, spaces *and //! relative order* or items. //! //! If you also need the ease of a more traditional API, see the [`toml`] crate. //! //! # Example //! //! ```rust //! # #[cfg(feature = "parse")] { //! # #[cfg(feature = "display")] { //! use toml_edit::{DocumentMut, value}; //! //! let toml = r#" //! "hello" = 'toml!' # comment //! ['a'.b] //! "#; //! let mut doc = toml.parse::().expect("invalid doc"); //! assert_eq!(doc.to_string(), toml); //! // let's add a new key/value pair inside a.b: c = {d = "hello"} //! doc["a"]["b"]["c"]["d"] = value("hello"); //! // autoformat inline table a.b.c: { d = "hello" } //! doc["a"]["b"]["c"].as_inline_table_mut().map(|t| t.fmt()); //! let expected = r#" //! "hello" = 'toml!' # comment //! ['a'.b] //! c = { d = "hello" } //! "#; //! assert_eq!(doc.to_string(), expected); //! # } //! # } //! ``` //! //! ## Controlling formatting //! //! By default, values are created with default formatting //! ```rust //! # #[cfg(feature = "display")] { //! # #[cfg(feature = "parse")] { //! let mut doc = toml_edit::DocumentMut::new(); //! doc["foo"] = toml_edit::value("bar"); //! let expected = r#"foo = "bar" //! "#; //! assert_eq!(doc.to_string(), expected); //! # } //! # } //! ``` //! //! You can choose a custom TOML representation by parsing the value. //! ```rust //! # #[cfg(feature = "display")] { //! # #[cfg(feature = "parse")] { //! let mut doc = toml_edit::DocumentMut::new(); //! doc["foo"] = "'bar'".parse::().unwrap(); //! let expected = r#"foo = 'bar' //! "#; //! assert_eq!(doc.to_string(), expected); //! # } //! # } //! ``` //! //! ## Limitations //! //! Things it does not preserve: //! //! * Order of dotted keys, see [issue](https://github.com/toml-rs/toml/issues/163). //! //! [`toml`]: https://docs.rs/toml/latest/toml/ // https://github.com/Marwes/combine/issues/172 #![recursion_limit = "256"] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs)] #![warn(clippy::print_stderr)] #![warn(clippy::print_stdout)] mod array; mod array_of_tables; mod document; #[cfg(feature = "display")] mod encode; mod error; mod index; mod inline_table; mod internal_string; mod item; mod key; #[cfg(feature = "parse")] mod parser; mod raw_string; mod repr; mod table; mod value; #[cfg(feature = "serde")] pub mod de; #[cfg(feature = "serde")] pub mod ser; pub mod visit; pub mod visit_mut; pub use crate::array::{Array, ArrayIntoIter, ArrayIter, ArrayIterMut}; pub use crate::array_of_tables::{ ArrayOfTables, ArrayOfTablesIntoIter, ArrayOfTablesIter, ArrayOfTablesIterMut, }; /// Deprecated, replaced with [`DocumentMut`] #[deprecated(since = "0.22.6", note = "Replaced with `DocumentMut`")] pub type Document = DocumentMut; pub use crate::document::DocumentMut; pub use crate::document::ImDocument; pub use crate::error::TomlError; pub use crate::inline_table::{ InlineEntry, InlineOccupiedEntry, InlineTable, InlineTableIntoIter, InlineTableIter, InlineTableIterMut, InlineVacantEntry, }; pub use crate::internal_string::InternalString; pub use crate::item::{array, table, value, Item}; pub use crate::key::{Key, KeyMut}; pub use crate::raw_string::RawString; pub use crate::repr::{Decor, Formatted, Repr}; pub use crate::table::{ Entry, IntoIter, Iter, IterMut, OccupiedEntry, Table, TableLike, VacantEntry, }; pub use crate::value::Value; pub use toml_datetime::*; // Prevent users from some traits. pub(crate) mod private { pub trait Sealed {} impl Sealed for usize {} impl Sealed for str {} impl Sealed for String {} impl Sealed for i64 {} impl Sealed for f64 {} impl Sealed for bool {} impl Sealed for crate::Datetime {} impl<'a, T: ?Sized> Sealed for &'a T where T: Sealed {} impl Sealed for crate::Table {} impl Sealed for crate::InlineTable {} } toml_edit-0.22.22/src/parser/array.rs000064400000000000000000000074121046102023000155240ustar 00000000000000use winnow::combinator::cut_err; use winnow::combinator::delimited; use winnow::combinator::opt; use winnow::combinator::peek; use winnow::combinator::separated; use winnow::combinator::trace; use crate::parser::trivia::ws_comment_newline; use crate::parser::value::value; use crate::{Array, Item, RawString}; use crate::parser::prelude::*; // ;; Array // array = array-open array-values array-close pub(crate) fn array<'i>(input: &mut Input<'i>) -> PResult { trace("array", move |input: &mut Input<'i>| { delimited( ARRAY_OPEN, cut_err(array_values), cut_err(ARRAY_CLOSE) .context(StrContext::Label("array")) .context(StrContext::Expected(StrContextValue::CharLiteral(']'))), ) .parse_next(input) }) .parse_next(input) } // note: we're omitting ws and newlines here, because // they should be part of the formatted values // array-open = %x5B ws-newline ; [ pub(crate) const ARRAY_OPEN: u8 = b'['; // array-close = ws-newline %x5D ; ] const ARRAY_CLOSE: u8 = b']'; // array-sep = ws %x2C ws ; , Comma const ARRAY_SEP: u8 = b','; // array-values = ws-comment-newline val ws-comment-newline array-sep array-values // array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ] pub(crate) fn array_values(input: &mut Input<'_>) -> PResult { if peek(opt(ARRAY_CLOSE)).parse_next(input)?.is_some() { // Optimize for empty arrays, avoiding `value` from being expected to fail return Ok(Array::new()); } let array = separated(0.., array_value, ARRAY_SEP).parse_next(input)?; let mut array = Array::with_vec(array); if !array.is_empty() { let comma = opt(ARRAY_SEP).parse_next(input)?.is_some(); array.set_trailing_comma(comma); } let trailing = ws_comment_newline.span().parse_next(input)?; array.set_trailing(RawString::with_span(trailing)); Ok(array) } pub(crate) fn array_value(input: &mut Input<'_>) -> PResult { let prefix = ws_comment_newline.span().parse_next(input)?; let value = value.parse_next(input)?; let suffix = ws_comment_newline.span().parse_next(input)?; let value = value.decorated(RawString::with_span(prefix), RawString::with_span(suffix)); let value = Item::Value(value); Ok(value) } #[cfg(test)] #[cfg(feature = "parse")] #[cfg(feature = "display")] mod test { use super::*; #[test] fn arrays() { let inputs = [ r#"[]"#, r#"[ ]"#, r#"[ 1, 2, 3 ]"#, r#"[ 1, 2, # this is ok ]"#, r#"[# comment # comment2 ]"#, r#"[# comment # comment2 1 #sd , # comment3 ]"#, r#"[1]"#, r#"[1,]"#, r#"[ "all", 'strings', """are the same""", '''type''']"#, r#"[ 100, -2,]"#, r#"[1, 2, 3]"#, r#"[1.1, 2.1, 3.1]"#, r#"["a", "b", "c"]"#, r#"[ [ 1, 2 ], [3, 4, 5] ]"#, r#"[ [ 1, 2 ], ["a", "b", "c"] ]"#, r#"[ { x = 1, a = "2" }, {a = "a",b = "b", c = "c"} ]"#, ]; for input in inputs { dbg!(input); let mut parsed = array.parse(new_input(input)); if let Ok(parsed) = &mut parsed { parsed.despan(input); } assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned())); } } #[test] fn invalid_arrays() { let invalid_inputs = [r#"["#, r#"[,]"#, r#"[,2]"#, r#"[1e165,,]"#]; for input in invalid_inputs { dbg!(input); let mut parsed = array.parse(new_input(input)); if let Ok(parsed) = &mut parsed { parsed.despan(input); } assert!(parsed.is_err()); } } } toml_edit-0.22.22/src/parser/datetime.rs000064400000000000000000000343331046102023000162040ustar 00000000000000use std::ops::RangeInclusive; use crate::parser::error::CustomError; use crate::parser::prelude::*; use crate::parser::trivia::from_utf8_unchecked; use toml_datetime::{Date, Datetime, Offset, Time}; use winnow::combinator::alt; use winnow::combinator::cut_err; use winnow::combinator::opt; use winnow::combinator::preceded; use winnow::combinator::trace; use winnow::stream::Stream as _; use winnow::token::one_of; use winnow::token::take_while; // ;; Date and Time (as defined in RFC 3339) // date-time = offset-date-time / local-date-time / local-date / local-time // offset-date-time = full-date time-delim full-time // local-date-time = full-date time-delim partial-time // local-date = full-date // local-time = partial-time // full-time = partial-time time-offset pub(crate) fn date_time(input: &mut Input<'_>) -> PResult { trace( "date-time", alt(( (full_date, opt((time_delim, partial_time, opt(time_offset)))) .map(|(date, opt)| { match opt { // Offset Date-Time Some((_, time, offset)) => Datetime { date: Some(date), time: Some(time), offset, }, // Local Date None => Datetime { date: Some(date), time: None, offset: None, }, } }) .context(StrContext::Label("date-time")), partial_time .map(|t| t.into()) .context(StrContext::Label("time")), )), ) .parse_next(input) } // full-date = date-fullyear "-" date-month "-" date-mday pub(crate) fn full_date(input: &mut Input<'_>) -> PResult { trace("full-date", full_date_).parse_next(input) } fn full_date_(input: &mut Input<'_>) -> PResult { let year = date_fullyear.parse_next(input)?; let _ = b'-'.parse_next(input)?; let month = cut_err(date_month).parse_next(input)?; let _ = cut_err(b'-').parse_next(input)?; let day_start = input.checkpoint(); let day = cut_err(date_mday).parse_next(input)?; let is_leap_year = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); let max_days_in_month = match month { 2 if is_leap_year => 29, 2 => 28, 4 | 6 | 9 | 11 => 30, _ => 31, }; if max_days_in_month < day { input.reset(&day_start); return Err(winnow::error::ErrMode::from_external_error( input, winnow::error::ErrorKind::Verify, CustomError::OutOfRange, ) .cut()); } Ok(Date { year, month, day }) } // partial-time = time-hour ":" time-minute ":" time-second [time-secfrac] pub(crate) fn partial_time(input: &mut Input<'_>) -> PResult