toml_edit-0.24.0+spec-1.1.0/.cargo_vcs_info.json0000644000000001560000000000100144620ustar { "git": { "sha1": "2e094015675c23c868512590c84df0b6ce68e4ad" }, "path_in_vcs": "crates/toml_edit" }toml_edit-0.24.0+spec-1.1.0/Cargo.lock0000644000000645100000000000100124410ustar # 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.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", "windows-sys 0.60.2", ] [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bstr" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "serde", ] [[package]] name = "cfg-if" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "chrono" version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "num-traits", ] [[package]] name = "colorchoice" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "crossbeam-deque" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" dependencies = [ "serde", "typeid", ] [[package]] name = "errno" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys 0.61.0", ] [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "getrandom" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", "r-efi", "wasi", ] [[package]] name = "globset" version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" dependencies = [ "aho-corasick", "bstr", "log", "regex-automata", "regex-syntax", ] [[package]] name = "hashbrown" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "ignore" version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ "crossbeam-deque", "globset", "log", "memchr", "regex-automata", "same-file", "walkdir", "winapi-util", ] [[package]] name = "include_dir" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" dependencies = [ "include_dir_macros", ] [[package]] name = "include_dir_macros" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" dependencies = [ "proc-macro2", "quote", ] [[package]] name = "indexmap" version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "json-write" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4085027557b9a870495ab8b7b411e14576055491d7220c88b11b7e2ba198b297" [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lexarg" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84373d01a60bb462a2e7caa28796669692d38ba075028a656bd626ac211062d4" dependencies = [ "lexarg-error", "lexarg-parser", ] [[package]] name = "lexarg-error" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "178daf11ee95fa4bf31ff1af878dda4c637dc08a37aabdd63ae3683481fd13a9" dependencies = [ "lexarg-parser", ] [[package]] name = "lexarg-parser" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67367be9ace12a2d51c03741b5280ff3029a833c49a4ec1193223a1a8cfbc863" [[package]] name = "libc" version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libtest-json" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f58e30343a6bfe0fb896b0bb92cf482c34ed047c637aac4b561d0b251b638c" dependencies = [ "json-write", ] [[package]] name = "libtest-lexarg" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "914e11e515e22a1b2a0aac76c0615e6417d470789c2f0433a0598a5b6aae491f" dependencies = [ "lexarg", "lexarg-error", ] [[package]] name = "libtest2-harness" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ca907aef7f70aceecb01e88588062946dd0af0727d80a68d9a1e928dacf07c9" dependencies = [ "anstream", "anstyle", "lexarg-error", "lexarg-parser", "libtest-json", "libtest-lexarg", ] [[package]] name = "libtest2-mimic" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a91f49bdcba4db89919ae87029787d2102f051e5dcf635df29e3bfdf55b2a4ac" dependencies = [ "libtest-json", "libtest2-harness", ] [[package]] name = "linux-raw-sys" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[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", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "ppv-lite86" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro2" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" 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.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom", ] [[package]] name = "rand_xorshift" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ "rand_core", ] [[package]] name = "regex-automata" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rustix" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.61.0", ] [[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.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[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.225" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde-untagged" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" dependencies = [ "erased-serde", "serde", "serde_core", "typeid", ] [[package]] name = "serde_core" version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", "serde_core", ] [[package]] name = "serde_spanned" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" dependencies = [ "serde_core", ] [[package]] name = "similar" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "snapbox" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96dcfc4581e3355d70ac2ee14cfdf81dce3d85c85f1ed9e2c1d3013f53b3436b" dependencies = [ "anstream", "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", ] [[package]] name = "syn" version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tempfile" version = "3.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" dependencies = [ "fastrand", "getrandom", "once_cell", "rustix", "windows-sys 0.61.0", ] [[package]] name = "toml-test" version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2849d808127660fc2182eb19c6fa69fd8d34a3968df247aa968da712c5a10064" dependencies = [ "chrono", "ryu", "serde", "serde_json", ] [[package]] name = "toml-test-data" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b59b1c6fa1ba45f952bfe2c40b1fc6dab837507837ed69b04fb5d56cf3bed7d4" dependencies = [ "include_dir", ] [[package]] name = "toml-test-harness" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b0c89104957a5be58bd9d3b853691e11421b74effc1234430714a8dd48b8d5" dependencies = [ "ignore", "libtest2-mimic", "snapbox", "toml-test", "toml-test-data", ] [[package]] name = "toml_datetime" version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" version = "0.24.0+spec-1.1.0" dependencies = [ "anstream", "anstyle", "indexmap", "proptest", "serde", "serde-untagged", "serde_core", "serde_json", "serde_spanned", "snapbox", "toml-test-data", "toml-test-harness", "toml_datetime", "toml_parser", "toml_writer", "walkdir", "winnow", ] [[package]] name = "toml_parser" version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ "anstream", "anstyle", "winnow", ] [[package]] name = "toml_writer" version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "typeid" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[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.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wait-timeout" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" 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.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ "wit-bindgen", ] [[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys 0.48.0", ] [[package]] name = "windows-link" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[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.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets 0.53.3", ] [[package]] name = "windows-sys" version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" dependencies = [ "windows-link 0.2.0", ] [[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.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", "windows_i686_gnullvm", "windows_i686_msvc 0.53.0", "windows_x86_64_gnu 0.53.0", "windows_x86_64_gnullvm 0.53.0", "windows_x86_64_msvc 0.53.0", ] [[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.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[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.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[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.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] name = "windows_i686_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[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.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[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.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[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.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[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.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "zerocopy" version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", "syn", ] toml_edit-0.24.0+spec-1.1.0/Cargo.toml0000644000000126650000000000100124700ustar # 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.76" name = "toml_edit" version = "0.24.0+spec-1.1.0" build = false include = [ "build.rs", "src/**/*", "Cargo.toml", "Cargo.lock", "LICENSE*", "README.md", "examples/**/*", ] autolib = false 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] all-features = true rustdoc-args = ["--generate-link-to-definition"] [package.metadata.release] tag-name = "v{{version}}" [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" search = "Unreleased" replace = "{{version}}" min = 1 [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" search = '\.\.\.HEAD' replace = "...{{tag_name}}" exactly = 1 [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" search = "ReleaseDate" replace = "{{date}}" min = 1 [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" search = "" replace = """ ## [Unreleased] - ReleaseDate """ exactly = 1 [[package.metadata.release.pre-release-replacements]] file = "CHANGELOG.md" search = "" replace = """ [Unreleased]: https://github.com/toml-rs/toml/compare/{{tag_name}}...HEAD""" exactly = 1 [features] debug = [ "toml_parser?/debug", "dep:anstream", "dep:anstyle", "display", ] default = [ "parse", "display", ] display = ["dep:toml_writer"] parse = [ "dep:toml_parser", "dep:winnow", ] serde = [ "dep:serde_core", "toml_datetime/serde", "dep:serde_spanned", ] unbounded = [] [lib] name = "toml_edit" path = "src/lib.rs" [[example]] name = "visit" path = "examples/visit.rs" test = true required-features = [ "parse", "display", ] [dependencies.anstream] version = "0.6.20" optional = true [dependencies.anstyle] version = "1.0.11" optional = true [dependencies.indexmap] version = "2.11.4" features = ["std"] [dependencies.serde_core] version = "1.0.225" optional = true [dependencies.serde_spanned] version = "1.0.4" features = ["serde"] optional = true [dependencies.toml_datetime] version = "0.7.5" [dependencies.toml_parser] version = "1.0.6" optional = true [dependencies.toml_writer] version = "1.0.6" optional = true [dependencies.winnow] version = "0.7.13" optional = true [dev-dependencies.proptest] version = "1.7.0" [dev-dependencies.serde] version = "1.0.225" features = ["derive"] [dev-dependencies.serde-untagged] version = "0.1.9" [dev-dependencies.serde_json] version = "1.0.145" [dev-dependencies.snapbox] version = "0.6.21" [dev-dependencies.toml-test-data] version = "2.3.3" [dev-dependencies.toml-test-harness] version = "1.3.3" features = ["snapshot"] [dev-dependencies.walkdir] version = "2.5.0" [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" get_first = "allow" 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_bool = "allow" needless_continue = "allow" 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" result_large_err = "allow" 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" uninlined_format_args = "warn" use_self = "warn" verbose_file_reads = "warn" wildcard_imports = "warn" zero_sized_map_values = "warn" [lints.rust] unnameable_types = "allow" 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.24.0+spec-1.1.0/Cargo.toml.orig000064400000000000000000000063221046102023000161420ustar 00000000000000[package] name = "toml_edit" version = "0.24.0+spec-1.1.0" description = "Yet another format-preserving TOML parser." categories = ["encoding", "parser-implementations", "parsing", "config"] keywords = ["encoding", "toml"] autotests = false repository.workspace = true license.workspace = true edition.workspace = true rust-version.workspace = true include.workspace = true [package.metadata.docs.rs] all-features = true rustdoc-args = ["--generate-link-to-definition"] [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:toml_parser", "dep:winnow"] display = ["dep:toml_writer"] serde = ["dep:serde_core", "toml_datetime/serde", "dep:serde_spanned"] debug = ["toml_parser?/debug", "dep:anstream", "dep:anstyle", "display"] # 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.11.4", features = ["std"] } winnow = { version = "0.7.13", optional = true } serde_core = { version = "1.0.225", optional = true } toml_datetime = { version = "0.7.5", path = "../toml_datetime" } serde_spanned = { version = "1.0.4", path = "../serde_spanned", features = ["serde"], optional = true } toml_writer = { version = "1.0.6", path = "../toml_writer", optional = true } toml_parser = { version = "1.0.6", path = "../toml_parser", optional = true } anstream = { version = "0.6.20", optional = true } anstyle = { version = "1.0.11", optional = true } [dev-dependencies] serde = { version = "1.0.225", features = ["derive"] } serde_json = "1.0.145" toml-test-harness = { version = "1.3.3", features = ["snapshot"] } toml-test-data = "2.3.3" snapbox = "0.6.21" proptest = "1.7.0" walkdir = "2.5.0" serde_spanned = { path = "../serde_spanned" } toml_types = { path = "../toml", package = "toml", default-features = false, features = ["serde", "preserve_order"] } serde-untagged = "0.1.9" [[test]] name = "testsuite" required-features = ["parse", "display"] [[test]] name = "compliance" required-features = ["parse", "display"] [[test]] name = "decoder_compliance" required-features = ["parse", "display"] harness = false [[test]] name = "encoder_compliance" required-features = ["parse", "display"] harness = false [[test]] name = "serde" required-features = ["parse", "display", "serde"] [[example]] name = "visit" required-features = ["parse", "display"] test = true [lints] workspace = true toml_edit-0.24.0+spec-1.1.0/LICENSE-APACHE000064400000000000000000000261361046102023000152040ustar 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.24.0+spec-1.1.0/LICENSE-MIT000064400000000000000000000020461046102023000147060ustar 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.24.0+spec-1.1.0/README.md000064400000000000000000000033071046102023000145320ustar 00000000000000# toml_edit [![Documentation](https://img.shields.io/badge/docs-master-blue.svg)](https://docs.rs/toml_edit) ![License](https://img.shields.io/crates/l/toml_edit.svg) [![Crates Status](https://img.shields.io/crates/v/toml_edit.svg)](https://crates.io/crates/toml_edit) 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::{DocumentMut, 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 ) * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. ### 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.24.0+spec-1.1.0/examples/visit.rs000064400000000000000000000174061046102023000166020ustar 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) { ( Self::Root | Self::TargetWithSpec, "dependencies" | "build-dependencies" | "dev-dependencies", ) => Self::Dependencies, (Self::Root, "target") => Self::Target, (Self::Root | Self::TargetWithSpec, _) => Self::Other, (Self::Target, _) => Self::TargetWithSpec, (Self::Dependencies, _) => Self::SubDependencies, (Self::SubDependencies, _) => Self::SubDependencies, (Self::Other, _) => Self::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.24.0+spec-1.1.0/src/array.rs000064400000000000000000000311751046102023000155320ustar 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}; /// A TOML [`Value`] that contains a sequence of [`Value`]s #[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 [`Array`]'s [`Value`]s pub type ArrayIntoIter = Box>; /// An iterator type over [`Array`]'s [`Value`]s pub type ArrayIter<'a> = Box + 'a>; /// An iterator type over [`Array`]'s [`Value`]s 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 a [`Document`][crate::Document]. 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.values.push(Item::Value(v.into())); } /// 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.values.insert(index, Item::Value(v.into())); } /// 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 {x:?} in an array"), } } /// 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 {x:?} in an array"), } } /// 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 } }); } } #[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())); Self { 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.24.0+spec-1.1.0/src/array_of_tables.rs000064400000000000000000000114261046102023000175450ustar 00000000000000use std::iter::FromIterator; use crate::{Array, Item, Table}; /// A top-level sequence of [`Table`]s, each under their own header #[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 a [`Document`][crate::Document]. 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) -> Table { self.values .remove(index) .into_table() .expect("cannot have any other item in an array-of-tables") } /// 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 [`Table`]s pub type ArrayOfTablesIter<'a> = Box + 'a>; /// An iterator type over [`ArrayOfTables`]'s [`Table`]s pub type ArrayOfTablesIterMut<'a> = Box + 'a>; /// An iterator type over [`ArrayOfTables`]'s [`Table`]s 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); Self { 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.24.0+spec-1.1.0/src/de/array.rs000064400000000000000000000044331046102023000161170ustar 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 } } } impl<'de> serde_core::Deserializer<'de> for ArrayDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde_core::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_core::de::Visitor<'de>, { if serde_spanned::de::is_spanned(name) { if let Some(span) = self.span.clone() { return visitor.visit_map( serde_spanned::de::SpannedDeserializer::::new(self, span), ); } else { return Err(Error::custom("value is missing a span", None)); } } self.deserialize_any(visitor) } serde_core::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 serde_core::de::IntoDeserializer<'_, Error> for ArrayDeserializer { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } 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_core::de::SeqAccess<'de> for ArraySeqAccess { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> where T: serde_core::de::DeserializeSeed<'de>, { match self.iter.next() { Some(v) => seed .deserialize(crate::de::ValueDeserializer::new(v)) .map(Some), None => Ok(None), } } } toml_edit-0.24.0+spec-1.1.0/src/de/error.rs000064400000000000000000000033111046102023000161240ustar 00000000000000/// Errors that can occur when deserializing a type. #[derive(Clone, PartialEq, Eq, Hash)] pub struct Error { inner: crate::TomlError, } impl Error { pub(crate) fn custom(msg: T, span: Option>) -> Self where T: std::fmt::Display, { Self { 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); } /// Provide the encoded TOML the error applies to pub fn set_input(&mut self, input: Option<&str>) { self.inner.set_input(input); } } impl serde_core::de::Error for Error { fn custom(msg: T) -> Self where T: std::fmt::Display, { Self::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 std::fmt::Debug 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) -> Self { Self { inner: e } } } impl From for crate::TomlError { fn from(e: Error) -> Self { e.inner } } impl std::error::Error for Error {} toml_edit-0.24.0+spec-1.1.0/src/de/key.rs000064400000000000000000000173111046102023000155700ustar 00000000000000use serde_core::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 { Self { span, key } } } impl IntoDeserializer<'_, Error> for KeyDeserializer { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } impl<'de> serde_core::de::Deserializer<'de> for KeyDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { self.key.into_deserializer().deserialize_any(visitor) } fn deserialize_bool(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: bool = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_bool(visitor) } fn deserialize_i8(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: i8 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_i8(visitor) } fn deserialize_i16(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: i16 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_i16(visitor) } fn deserialize_i32(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: i32 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_i32(visitor) } fn deserialize_i64(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: i64 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_i64(visitor) } fn deserialize_i128(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: i128 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_i128(visitor) } fn deserialize_u8(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: u8 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_u8(visitor) } fn deserialize_u16(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: u16 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_u16(visitor) } fn deserialize_u32(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: u32 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_u32(visitor) } fn deserialize_u64(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: u64 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_u64(visitor) } fn deserialize_u128(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: u128 = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_u128(visitor) } fn deserialize_char(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let key: char = self .key .parse() .map_err(::custom)?; key.into_deserializer().deserialize_char(visitor) } fn deserialize_enum( self, name: &str, variants: &'static [&'static str], visitor: V, ) -> Result where V: serde_core::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_core::de::Visitor<'de>, { if serde_spanned::de::is_spanned(name) { if let Some(span) = self.span.clone() { return visitor.visit_map( serde_spanned::de::SpannedDeserializer::<&str, Error>::new( self.key.get(), span, ), ); } else { return Err(Error::custom("value is missing a span", None)); } } self.deserialize_any(visitor) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: serde_core::de::Visitor<'de>, { visitor.visit_newtype_struct(self) } serde_core::forward_to_deserialize_any! { f32 f64 str string seq bytes byte_buf map option unit ignored_any unit_struct tuple_struct tuple identifier } } impl<'de> serde_core::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_core::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_core::de::VariantAccess<'de> for UnitOnly where E: serde_core::de::Error, { type Error = E; fn unit_variant(self) -> Result<(), Self::Error> { Ok(()) } fn newtype_variant_seed(self, _seed: T) -> Result where T: serde_core::de::DeserializeSeed<'de>, { Err(serde_core::de::Error::invalid_type( serde_core::de::Unexpected::UnitVariant, &"newtype variant", )) } fn tuple_variant(self, _len: usize, _visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { Err(serde_core::de::Error::invalid_type( serde_core::de::Unexpected::UnitVariant, &"tuple variant", )) } fn struct_variant( self, _fields: &'static [&'static str], _visitor: V, ) -> Result where V: serde_core::de::Visitor<'de>, { Err(serde_core::de::Error::invalid_type( serde_core::de::Unexpected::UnitVariant, &"struct variant", )) } } toml_edit-0.24.0+spec-1.1.0/src/de/mod.rs000064400000000000000000000150111046102023000155520ustar 00000000000000//! Deserializing TOML into Rust structures. //! //! This module contains all the Serde support for deserializing TOML documents into Rust structures. use serde_core::de::DeserializeOwned; mod array; mod error; mod key; mod table; mod table_enum; mod value; use array::ArrayDeserializer; use key::KeyDeserializer; use table::TableDeserializer; use table_enum::TableEnumDeserializer; use toml_datetime::de::DatetimeDeserializer; pub use error::Error; pub use value::ValueDeserializer; /// Deserializes a string into a type. /// /// This function will attempt to interpret `s` as a TOML document and /// deserialize `T` from the document. /// /// To deserializes TOML values, instead of documents, see [`ValueDeserializer`]. /// /// # Examples /// /// ``` /// use serde::Deserialize; /// /// #[derive(Deserialize)] /// struct Config { /// title: String, /// owner: Owner, /// } /// /// #[derive(Deserialize)] /// struct Owner { /// name: String, /// } /// /// let config: Config = toml_edit::de::from_str(r#" /// title = 'TOML Example' /// /// [owner] /// name = 'Lisa' /// "#).unwrap(); /// /// assert_eq!(config.title, "TOML Example"); /// assert_eq!(config.owner.name, "Lisa"); /// ``` #[cfg(feature = "parse")] pub fn from_str(s: &'_ str) -> Result where T: DeserializeOwned, { let de = Deserializer::parse(s)?; T::deserialize(de) } /// Deserializes bytes into a type. /// /// This function will attempt to interpret `s` as a TOML document and /// deserialize `T` from the document. /// /// To deserializes TOML values, instead of documents, see [`ValueDeserializer`]. #[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, } #[cfg(feature = "parse")] impl> Deserializer { /// Parse a TOML document pub fn parse(raw: S) -> Result { crate::Document::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::Document) -> Self { let crate::Document { 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::Document<_> = s.parse().map_err(Error::from)?; Ok(Self::from(doc)) } } impl<'de, S: AsRef> serde_core::Deserializer<'de> for Deserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde_core::de::Visitor<'de>, { let raw = self.raw; ValueDeserializer::new(self.root) .deserialize_any(visitor) .map_err(|mut e: Self::Error| { let raw = raw.as_ref().map(|r| r.as_ref()); e.set_input(raw); 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_core::de::Visitor<'de>, { let raw = self.raw; ValueDeserializer::new(self.root) .deserialize_option(visitor) .map_err(|mut e: Self::Error| { let raw = raw.as_ref().map(|r| r.as_ref()); e.set_input(raw); e }) } fn deserialize_newtype_struct( self, name: &'static str, visitor: V, ) -> Result where V: serde_core::de::Visitor<'de>, { let raw = self.raw; ValueDeserializer::new(self.root) .deserialize_newtype_struct(name, visitor) .map_err(|mut e: Self::Error| { let raw = raw.as_ref().map(|r| r.as_ref()); e.set_input(raw); e }) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: serde_core::de::Visitor<'de>, { let raw = self.raw; ValueDeserializer::new(self.root) .deserialize_struct(name, fields, visitor) .map_err(|mut e: Self::Error| { let raw = raw.as_ref().map(|r| r.as_ref()); e.set_input(raw); 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_core::de::Visitor<'de>, { let raw = self.raw; ValueDeserializer::new(self.root) .deserialize_enum(name, variants, visitor) .map_err(|mut e: Self::Error| { let raw = raw.as_ref().map(|r| r.as_ref()); e.set_input(raw); e }) } serde_core::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 serde_core::de::IntoDeserializer<'_, Error> for Deserializer { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } impl serde_core::de::IntoDeserializer<'_, Error> for crate::DocumentMut { type Deserializer = Deserializer; fn into_deserializer(self) -> Self::Deserializer { Deserializer::from(self) } } impl serde_core::de::IntoDeserializer<'_, Error> for crate::Document { type Deserializer = Deserializer; fn into_deserializer(self) -> Self::Deserializer { Deserializer::from(self) } } toml_edit-0.24.0+spec-1.1.0/src/de/table.rs000064400000000000000000000134621046102023000160720ustar 00000000000000use serde_core::de::IntoDeserializer; use crate::de::Error; pub(crate) struct TableDeserializer { span: Option>, items: crate::table::KeyValuePairs, } impl TableDeserializer { pub(crate) fn new( items: crate::table::KeyValuePairs, span: Option>, ) -> Self { Self { span, items } } } impl<'de> serde_core::Deserializer<'de> for TableDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde_core::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_core::de::Visitor<'de>, { visitor.visit_some(self) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: serde_core::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_core::de::Visitor<'de>, { if serde_spanned::de::is_spanned(name) { if let Some(span) = self.span.clone() { return visitor.visit_map( serde_spanned::de::SpannedDeserializer::::new(self, span), ); } else { return Err(Error::custom("value is missing a span", None)); } } 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_core::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_core::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 IntoDeserializer<'_, Error> for TableDeserializer { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } 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_core::de::MapAccess<'de> for TableMapAccess { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> where K: serde_core::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_core::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_core::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_core::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.24.0+spec-1.1.0/src/de/table_enum.rs000064400000000000000000000144321046102023000171140ustar 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 { Self { value } } } impl<'de> serde_core::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_core::de::DeserializeSeed<'de>, { seed.deserialize(super::ValueDeserializer::new(self.value)) } fn tuple_variant(self, len: usize, visitor: V) -> Result where V: serde_core::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_core::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_core::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_core::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_core::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_core::de::Visitor<'de>, { serde_core::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.24.0+spec-1.1.0/src/de/value.rs000064400000000000000000000217241046102023000161170ustar 00000000000000use serde_core::de::IntoDeserializer as _; use crate::de::ArrayDeserializer; use crate::de::DatetimeDeserializer; use crate::de::Error; use crate::de::TableDeserializer; /// 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 /// [`IntoDeserializer::into_deserializer`][serde_core::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 } } impl<'de> serde_core::Deserializer<'de> for ValueDeserializer { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: serde_core::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)) => { ArrayDeserializer::new(v.values, v.span).deserialize_any(visitor) } crate::Item::Value(crate::Value::InlineTable(v)) => { TableDeserializer::new(v.items, v.span).deserialize_any(visitor) } crate::Item::Table(v) => { TableDeserializer::new(v.items, v.span).deserialize_any(visitor) } crate::Item::ArrayOfTables(v) => { ArrayDeserializer::new(v.values, v.span).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_core::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_core::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_core::de::Visitor<'de>, { if serde_spanned::de::is_spanned(name) { if let Some(span) = self.input.span() { return visitor.visit_map( serde_spanned::de::SpannedDeserializer::::new(self, span), ); } else { return Err(Error::custom("value is missing a span", None)); } } if toml_datetime::de::is_datetime(name) { 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) => validate_struct_keys(&values.items, fields), crate::Item::Value(crate::Value::InlineTable(values)) => { 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_core::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 { TableDeserializer::new(v.items, v.span) .deserialize_enum(name, variants, visitor) } } crate::Item::Table(v) => { TableDeserializer::new(v.items, v.span).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_core::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 serde_core::de::IntoDeserializer<'_, Error> for ValueDeserializer { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } impl serde_core::de::IntoDeserializer<'_, Error> for crate::Value { type Deserializer = ValueDeserializer; fn into_deserializer(self) -> Self::Deserializer { ValueDeserializer::new(crate::Item::Value(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 value = s.parse::().map_err(Error::from)?; Ok(value.into_deserializer()) } } 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.24.0+spec-1.1.0/src/document.rs000064400000000000000000000134321046102023000162260ustar 00000000000000use std::str::FromStr; use crate::table::Iter; use crate::{Item, RawString, Table}; /// The root TOML [`Table`], containing [`Key`][crate::Key]/[`Value`][crate::Value] pairs and all other logic [`Table`]s #[derive(Debug, Clone)] pub struct Document { pub(crate) root: Item, // Trailing comments and whitespaces pub(crate) trailing: RawString, pub(crate) raw: S, } impl Document<&'static str> { /// Creates an empty document pub fn new() -> Self { Default::default() } } #[cfg(feature = "parse")] impl> Document { /// Parse a TOML document pub fn parse(raw: S) -> Result { let source = toml_parser::Source::new(raw.as_ref()); let mut sink = crate::error::TomlSink::>::new(source); let doc = crate::parser::parse_document(source, &mut sink); if let Some(err) = sink.into_inner() { Err(err) } else { Ok(Self { root: doc.root, trailing: doc.trailing, raw, }) } } } impl> Document { /// # Panics /// /// If run 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 Document { /// Returns a reference to the root item. pub fn as_item(&self) -> &Item { &self.root } /// Returns the root item. pub fn into_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 the root table. pub fn into_table(self) -> Table { self.root .into_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> Document { /// Access the raw, unparsed document pub fn raw(&self) -> &str { self.raw.as_ref() } } impl> Document { /// Allow editing of the [`DocumentMut`] pub fn into_mut(mut self) -> DocumentMut { self.despan(); DocumentMut { root: self.root, trailing: self.trailing, } } } impl Default for Document<&'static str> { fn default() -> Self { Self { root: Item::Table(Table::with_pos(Some(0))), trailing: Default::default(), raw: "", } } } #[cfg(feature = "parse")] impl FromStr for Document { 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 Document { type Target = Table; fn deref(&self) -> &Self::Target { self.as_table() } } /// The editable root TOML [`Table`], containing [`Key`][crate::Key]/[`Value`][crate::Value] pairs and all other logic [`Table`]s #[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 the root item. pub fn into_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 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 the root table. pub fn into_table(self) -> Table { self.root .into_table() .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 = Document::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.24.0+spec-1.1.0/src/encode.rs000064400000000000000000000266131046102023000156520ustar 00000000000000use std::borrow::Cow; use std::fmt::{Display, Formatter, Result, Write}; use toml_datetime::Datetime; use toml_writer::ToTomlValue as _; use toml_writer::TomlWrite as _; 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], mut 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 { buf.key_sep()?; 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], mut 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 { buf.key_sep()?; 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, mut buf: &mut dyn Write, input: Option<&str>, default_decor: (&str, &str), ) -> Result { let decor = this.decor(); decor.prefix_encode(buf, input, default_decor.0)?; buf.open_array()?; 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; buf.val_sep()?; } encode_value(elem, buf, input, inner_decor)?; } if this.trailing_comma() && !this.is_empty() { buf.val_sep()?; } this.trailing().encode_with_default(buf, input, "")?; buf.close_array()?; decor.suffix_encode(buf, input, default_decor.1)?; Ok(()) } pub(crate) fn encode_table( this: &InlineTable, mut buf: &mut dyn Write, input: Option<&str>, default_decor: (&str, &str), ) -> Result { let decor = this.decor(); decor.prefix_encode(buf, input, default_decor.0)?; buf.open_inline_table()?; let children = this.get_values(); let len = children.len(); for (i, (key_path, value)) in children.into_iter().enumerate() { if i != 0 { buf.val_sep()?; } 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)?; buf.keyval_sep()?; encode_value(value, buf, input, inner_decor)?; } if this.trailing_comma() && !this.is_empty() { buf.val_sep()?; } this.trailing().encode_with_default(buf, input, "")?; buf.close_inline_table()?; 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( mut 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)?; buf.open_array_of_tables_header()?; encode_key_path(path, buf, input, DEFAULT_KEY_PATH_DECOR)?; buf.close_array_of_tables_header()?; 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)?; buf.open_table_header()?; encode_key_path(path, buf, input, DEFAULT_KEY_PATH_DECOR)?; buf.close_table_header()?; 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)?; buf.keyval_sep()?; encode_value(value, buf, input, DEFAULT_VALUE_DECOR)?; writeln!(buf)?; } Ok(()) } impl ValueRepr for String { fn to_repr(&self) -> Repr { let output = toml_writer::TomlStringBuilder::new(self.as_str()) .as_default() .to_toml_value(); Repr::new_unchecked(output) } } impl ValueRepr for i64 { fn to_repr(&self) -> Repr { let repr = self.to_toml_value(); Repr::new_unchecked(repr) } } impl ValueRepr for f64 { fn to_repr(&self) -> Repr { let repr = self.to_toml_value(); Repr::new_unchecked(repr) } } impl ValueRepr for bool { fn to_repr(&self) -> Repr { let repr = self.to_toml_value(); Repr::new_unchecked(repr) } } 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 value = Value::from(string.clone()); let encoded = value.to_string(); let _: Value = encoded.parse().unwrap_or_else(|err| { panic!("error: {err} string: ``` {string} ``` value: ``` {value} ``` ") }); } } proptest! { #[test] #[cfg(feature = "parse")] fn parseable_key(string in "\\PC*") { let key = Key::new(string.clone()); let encoded = key.to_string(); let _: Key = encoded.parse().unwrap_or_else(|err| { panic!("error: {err} string: ``` {string} ``` key: ``` {key} ``` ") }); } } } toml_edit-0.24.0+spec-1.1.0/src/error.rs000064400000000000000000000203721046102023000155420ustar 00000000000000/// A TOML parse error #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct TomlError { message: String, input: Option>, keys: Vec, span: Option>, } impl TomlError { #[cfg(feature = "parse")] pub(crate) fn new(input: std::sync::Arc, error: toml_parser::ParseError) -> Self { let mut message = String::new(); message.push_str(error.description()); if let Some(expected) = error.expected() { message.push_str(", expected "); if expected.is_empty() { message.push_str("nothing"); } else { for (i, expected) in expected.iter().enumerate() { if i != 0 { message.push_str(", "); } match expected { toml_parser::Expected::Literal(desc) => { message.push_str(&render_literal(desc)); } toml_parser::Expected::Description(desc) => message.push_str(desc), _ => message.push_str("etc"), } } } } let span = error.unexpected().map(|span| span.start()..span.end()); Self { message, input: Some(input), keys: Vec::new(), span, } } #[cfg(feature = "serde")] pub(crate) fn custom(message: String, span: Option>) -> Self { Self { message, input: 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_input(&mut self, input: Option<&str>) { self.input = input.map(|s| s.into()); } } fn render_literal(literal: &str) -> String { match literal { "\n" => "newline".to_owned(), "`" => "'`'".to_owned(), s if s.chars().all(|c| c.is_ascii_control()) => { format!("`{}`", s.escape_debug()) } s => format!("`{s}`"), } } /// 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 std::fmt::Display for TomlError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut context = false; if let (Some(input), Some(span)) = (&self.input, self.span()) { context = true; let (line, column) = translate_position(input.as_bytes(), span.start); let line_num = line + 1; let col_num = column + 1; let gutter = line_num.to_string().len(); let content = input.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 {line_num}, column {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 std::error::Error for TomlError {} 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(feature = "parse")] pub(crate) struct TomlSink<'i, S> { source: toml_parser::Source<'i>, input: Option>, sink: S, } #[cfg(feature = "parse")] impl<'i, S: Default> TomlSink<'i, S> { pub(crate) fn new(source: toml_parser::Source<'i>) -> Self { Self { source, input: None, sink: Default::default(), } } pub(crate) fn into_inner(self) -> S { self.sink } } #[cfg(feature = "parse")] impl<'i> toml_parser::ErrorSink for TomlSink<'i, Option> { fn report_error(&mut self, error: toml_parser::ParseError) { if self.sink.is_none() { let input = self .input .get_or_insert_with(|| std::sync::Arc::from(self.source.input())); let error = TomlError::new(input.clone(), error); self.sink = Some(error); } } } #[cfg(feature = "parse")] impl<'i> toml_parser::ErrorSink for TomlSink<'i, Vec> { fn report_error(&mut self, error: toml_parser::ParseError) { let input = self .input .get_or_insert_with(|| std::sync::Arc::from(self.source.input())); let error = TomlError::new(input.clone(), error); self.sink.push(error); } } #[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.24.0+spec-1.1.0/src/index.rs000064400000000000000000000073111046102023000155160ustar 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 Index for &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 = Self; fn index(&self, index: I) -> &Self { index.index(self).expect("index not found") } } impl ops::IndexMut for Item where I: Index, { fn index_mut(&mut self, index: I) -> &mut Self { 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.24.0+spec-1.1.0/src/inline_table.rs000064400000000000000000000565461046102023000170520ustar 00000000000000use std::iter::FromIterator; use crate::key::Key; use crate::repr::Decor; use crate::table::{Iter, IterMut, KeyValuePairs, TableLike}; use crate::{Item, KeyMut, RawString, Table, Value}; /// A TOML [`Value`] that contains a collection of [`Key`]/[`Value`] pairs #[derive(Debug, Default, Clone)] pub struct InlineTable { // `trailing` represents whitespaces, newlines // and comments in an empty array or after the trailing comma trailing: RawString, trailing_comma: bool, // 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)); } Item::Table(table) => { table.append_all_values(&path, values); } _ => {} } } } /// Auto formats the table. pub fn fmt(&mut self) { decorate_inline_table(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 } /// Sorts [Key]/[Value]-pairs of the table /// ///
/// /// This is not recursive. /// ///
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). /// ///
/// /// This is not recursive. /// ///
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()) } /// The location within the original document /// /// This generally requires a [`Document`][crate::Document]. 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.trailing.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 = Self::new(); table.extend(iter); table } } impl IntoIterator for InlineTable { type Item = (String, 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 an [`InlineTable`]'s [`Key`]/[`Value`] pairs pub type InlineTableIntoIter = Box>; /// An iterator type over [`InlineTable`]'s [`Key`]/[`Value`] pairs pub type InlineTableIter<'a> = Box + 'a>; /// A mutable iterator type over [`InlineTable`]'s [`Key`]/[`Value`] pairs 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 `String`, 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) } } // `{ key1 = value1, ... }` pub(crate) const DEFAULT_INLINE_KEY_DECOR: (&str, &str) = (" ", " "); /// A view into a single location in an [`InlineTable`], 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 an [`InlineTable`]. 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 an [`InlineTable`]. 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.24.0+spec-1.1.0/src/item.rs000064400000000000000000000314161046102023000153500ustar 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: Self) -> &mut Self { 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 { Self::None => "none", Self::Value(v) => v.type_name(), Self::Table(..) => "table", Self::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<&Self> { 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 Self> { index.index_mut(self) } /// Casts `self` to [`Value`] pub fn as_value(&self) -> Option<&Value> { match *self { Self::Value(ref v) => Some(v), _ => None, } } /// Casts `self` to [`Table`] /// ///
/// /// To operate on both [`Table`]s and [`InlineTable`]s, see [`Item::as_table_like`] /// ///
pub fn as_table(&self) -> Option<&Table> { match *self { Self::Table(ref t) => Some(t), _ => None, } } /// Casts `self` to [`ArrayOfTables`] pub fn as_array_of_tables(&self) -> Option<&ArrayOfTables> { match *self { Self::ArrayOfTables(ref a) => Some(a), _ => None, } } /// Casts `self` to mutable [`Value`]. pub fn as_value_mut(&mut self) -> Option<&mut Value> { match *self { Self::Value(ref mut v) => Some(v), _ => None, } } /// Casts `self` to mutable [`Table`] /// ///
/// /// To operate on both [`Table`]s and [`InlineTable`]s, see [`Item::as_table_like_mut`] /// ///
pub fn as_table_mut(&mut self) -> Option<&mut Table> { match *self { Self::Table(ref mut t) => Some(t), _ => None, } } /// Casts `self` to mutable [`ArrayOfTables`] pub fn as_array_of_tables_mut(&mut self) -> Option<&mut ArrayOfTables> { match *self { Self::ArrayOfTables(ref mut a) => Some(a), _ => None, } } /// Casts `self` to [`Value`] pub fn into_value(self) -> Result { match self { Self::None => Err(self), Self::Value(v) => Ok(v), Self::Table(v) => { let v = v.into_inline_table(); Ok(Value::InlineTable(v)) } Self::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(Self::None); *self = other; } /// Casts `self` to [`Table`] /// ///
/// /// This does not include [`InlineTable`]s /// ///
pub fn into_table(self) -> Result { match self { Self::Table(t) => Ok(t), Self::Value(Value::InlineTable(t)) => Ok(t.into_table()), _ => Err(self), } } /// Casts `self` to [`ArrayOfTables`] pub fn into_array_of_tables(self) -> Result { match self { Self::ArrayOfTables(a) => Ok(a), Self::Value(Value::Array(a)) => { if a.is_empty() { Err(Self::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(Self::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`] /// ///
/// /// To operate on both [`Table`]s and [`InlineTable`]s, see [`Item::is_table_like`] /// ///
pub fn is_table(&self) -> bool { self.as_table().is_some() } /// Returns true if `self` is an [`ArrayOfTables`] 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, Self::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 { Self::Table(t) => Some(t as &mut dyn TableLike), Self::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 a [`Document`][crate::Document]. pub fn span(&self) -> Option> { match self { Self::None => None, Self::Value(v) => v.span(), Self::Table(v) => v.span(), Self::ArrayOfTables(v) => v.span(), } } pub(crate) fn despan(&mut self, input: &str) { match self { Self::None => {} Self::Value(v) => v.despan(input), Self::Table(v) => v.despan(input), Self::ArrayOfTables(v) => v.despan(input), } } } impl Clone for Item { #[inline(never)] fn clone(&self) -> Self { match self { Self::None => Self::None, Self::Value(v) => Self::Value(v.clone()), Self::Table(v) => Self::Table(v.clone()), Self::ArrayOfTables(v) => Self::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(Self::Value(value)) } } impl<'b> From<&'b Self> for Item { fn from(s: &'b Self) -> Self { s.clone() } } impl From
for Item { fn from(s: Table) -> Self { Self::Table(s) } } impl From for Item { fn from(s: ArrayOfTables) -> Self { Self::ArrayOfTables(s) } } impl> From for Item { fn from(s: V) -> Self { Self::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 { Self::None => Ok(()), Self::Value(v) => v.fmt(f), Self::Table(v) => v.fmt(f), Self::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.24.0+spec-1.1.0/src/key.rs000064400000000000000000000231541046102023000152020ustar 00000000000000use std::borrow::Cow; use std::str::FromStr; #[cfg(feature = "display")] use toml_writer::ToTomlKey as _; use crate::repr::{Decor, Repr}; /// For Key/[`Value`][crate::Value] pairs under a [`Table`][crate::Table] header or inside an /// [`InlineTable`][crate::InlineTable] /// /// # 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: String, 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 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 { let output = toml_writer::TomlKeyBuilder::new(&self.key) .as_default() .to_toml_key(); Repr::new_unchecked(output) } /// 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 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 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 a [`Document`][crate::Document]. 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 source = toml_parser::Source::new(s); let mut sink = crate::error::TomlSink::>::new(source); let mut key = crate::parser::parse_key(source, &mut sink); if let Some(err) = sink.into_inner() { Err(err) } else { key.despan(s); Ok(key) } } #[cfg(feature = "parse")] fn try_parse_path(s: &str) -> Result, crate::TomlError> { let source = toml_parser::Source::new(s); let mut sink = crate::error::TomlSink::>::new(source); let mut keys = crate::parser::parse_key_path(source, &mut sink); if let Some(err) = sink.into_inner() { Err(err) } else { 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: &Self) -> bool { PartialEq::eq(self.get(), other.get()) } } impl PartialEq for Key { #[inline] fn eq(&self, other: &str) -> bool { PartialEq::eq(self.get(), other) } } impl PartialEq<&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 { Self::try_parse_simple(s) } } impl<'b> From<&'b str> for Key { fn from(s: &'b str) -> Self { Self::new(s) } } impl<'b> From<&'b String> for Key { fn from(s: &'b String) -> Self { Self::new(s) } } impl From for Key { fn from(s: String) -> Self { Self::new(s) } } #[doc(hidden)] impl From for String { fn from(key: Key) -> Self { 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 KeyMut<'_> { /// 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 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 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 std::ops::Deref for KeyMut<'_> { type Target = str; fn deref(&self) -> &Self::Target { self.get() } } impl PartialEq for KeyMut<'_> { #[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 PartialEq for KeyMut<'_> { #[inline] fn eq(&self, other: &String) -> bool { PartialEq::eq(self.get(), other.as_str()) } } #[cfg(feature = "display")] impl std::fmt::Display for KeyMut<'_> { 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.24.0+spec-1.1.0/src/lib.rs000064400000000000000000000076121046102023000151610ustar 00000000000000//! # `toml_edit` //! //! This crate allows you to parse and modify toml //! documents, while preserving comments, spaces *and //! relative order* of 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_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 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, }; pub use crate::document::DocumentMut; /// Type representing a parsed TOML document #[deprecated(since = "0.23.0", note = "Replaced with `Document`")] pub type ImDocument = Document; pub use crate::document::Document; pub use crate::error::TomlError; pub use crate::inline_table::{ InlineEntry, InlineOccupiedEntry, InlineTable, InlineTableIntoIter, InlineTableIter, InlineTableIterMut, InlineVacantEntry, }; 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 Sealed for &T where T: Sealed {} impl Sealed for crate::Table {} impl Sealed for crate::InlineTable {} } #[doc = include_str!("../README.md")] #[cfg(doctest)] #[cfg(feature = "display")] #[cfg(feature = "parse")] pub struct ReadmeDoctests; toml_edit-0.24.0+spec-1.1.0/src/parser/array.rs000064400000000000000000000124171046102023000170240ustar 00000000000000use crate::parser::inline_table::on_inline_table; use crate::parser::value::on_scalar; use crate::{Array, RawString, Value}; use crate::parser::prelude::*; /// ```abnf /// ;; Array /// /// array = array-open array-values array-close /// 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 on_array( open_event: &toml_parser::parser::Event, input: &mut Input<'_>, source: toml_parser::Source<'_>, errors: &mut dyn ErrorSink, ) -> Value { #[cfg(feature = "debug")] let _scope = TraceScope::new("array::on_array"); let mut result = Array::new(); let mut state = State::default(); state.open(open_event); while let Some(event) = input.next_token() { match event.kind() { EventKind::StdTableOpen | EventKind::ArrayTableOpen | EventKind::InlineTableClose | EventKind::SimpleKey | EventKind::KeySep | EventKind::KeyValSep | EventKind::StdTableClose | EventKind::ArrayTableClose => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); break; } EventKind::Error => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); continue; } EventKind::InlineTableOpen => { let value = on_inline_table(event, input, source, errors); state.capture_value(event, value); } EventKind::ArrayOpen => { let value = on_array(event, input, source, errors); state.capture_value(event, value); } EventKind::Scalar => { let value = on_scalar(event, source, errors); state.capture_value(event, value); } EventKind::ValueSep => { state.finish_value(event, &mut result); state.sep_value(event); } EventKind::Whitespace | EventKind::Comment | EventKind::Newline => { state.whitespace(event); } EventKind::ArrayClose => { state.finish_value(event, &mut result); state.close(open_event, event, &mut result); break; } } } Value::Array(result) } #[derive(Default)] struct State { current_prefix: Option, current_value: Option, trailing_start: Option, current_suffix: Option, } impl State { fn open(&mut self, open_event: &toml_parser::parser::Event) { self.trailing_start = Some(open_event.span().end()); } fn whitespace(&mut self, event: &toml_parser::parser::Event) { let decor = if self.is_prefix() { self.current_prefix.get_or_insert(event.span()) } else { self.current_suffix.get_or_insert(event.span()) }; *decor = decor.append(event.span()); } fn is_prefix(&self) -> bool { self.current_value.is_none() } fn capture_value(&mut self, event: &toml_parser::parser::Event, value: Value) { self.trailing_start = None; self.current_prefix .get_or_insert_with(|| event.span().before()); self.current_value = Some(value); } fn finish_value(&mut self, event: &toml_parser::parser::Event, result: &mut Array) { #[cfg(feature = "debug")] let _scope = TraceScope::new("array::finish_value"); if let Some(mut value) = self.current_value.take() { let prefix = self .current_prefix .take() .expect("setting a value should set a prefix"); let suffix = self .current_suffix .take() .unwrap_or_else(|| event.span().before()); let decor = value.decor_mut(); decor.set_prefix(RawString::with_span(prefix.start()..prefix.end())); decor.set_suffix(RawString::with_span(suffix.start()..suffix.end())); result.push_formatted(value); } } fn sep_value(&mut self, event: &toml_parser::parser::Event) { self.trailing_start = Some(event.span().end()); } fn close( &mut self, open_event: &toml_parser::parser::Event, close_event: &toml_parser::parser::Event, result: &mut Array, ) { #[cfg(feature = "debug")] let _scope = TraceScope::new("array::close"); let trailing_comma = self.trailing_start.is_some() && !result.is_empty(); let span = open_event.span().append(close_event.span()); let trailing_start = self .trailing_start .unwrap_or_else(|| close_event.span().start()); let trailing_end = close_event.span().start(); result.set_trailing_comma(trailing_comma); result.set_trailing(RawString::with_span(trailing_start..trailing_end)); result.span = Some(span.start()..span.end()); } } toml_edit-0.24.0+spec-1.1.0/src/parser/debug.rs000064400000000000000000000043341046102023000167730ustar 00000000000000pub(crate) struct TraceScope { text: String, style: anstyle::Style, guard: DebugDepthGuard, } impl TraceScope { pub(crate) fn new(text: impl core::fmt::Display) -> Self { let text = text.to_string(); let style = anstyle::Style::new(); trace(&format!("> {text}"), style); Self { text, style, guard: DEBUG_DEPTH.scoped(), } } } impl Drop for TraceScope { fn drop(&mut self) { let text = &self.text; let style = self.style; drop(self.guard.take()); trace(&format!("< {text}"), style); } } pub(crate) fn trace(text: &str, style: anstyle::Style) { #![allow(unexpected_cfgs)] // HACK: fixed in newer versions let depth = DEBUG_DEPTH.depth(); anstream::eprintln!("{:depth$}{style}{text}{style:#}", ""); } pub(crate) struct DebugDepth(core::sync::atomic::AtomicUsize); impl DebugDepth { pub(crate) fn scoped(&self) -> DebugDepthGuard { DebugDepthGuard::new() } pub(crate) fn enter_unchecked(&self) -> usize { self.0.fetch_add(1, core::sync::atomic::Ordering::SeqCst) } pub(crate) fn exit_unchecked(&self) { let _ = self.0.fetch_sub(1, core::sync::atomic::Ordering::SeqCst); } pub(crate) fn depth(&self) -> usize { self.0.load(core::sync::atomic::Ordering::SeqCst) } } static DEBUG_DEPTH: DebugDepth = DebugDepth(core::sync::atomic::AtomicUsize::new(0)); pub(crate) struct DebugDepthGuard { depth: usize, inc: bool, } impl DebugDepthGuard { pub(crate) fn new() -> Self { let depth = DEBUG_DEPTH.enter_unchecked(); Self { depth, inc: true } } fn take(&mut self) -> Self { let depth = self.depth; let inc = self.inc; self.inc = false; Self { depth, inc } } } impl Drop for DebugDepthGuard { fn drop(&mut self) { if self.inc { DEBUG_DEPTH.exit_unchecked(); } } } impl AsRef for DebugDepthGuard { #[inline(always)] fn as_ref(&self) -> &usize { &self.depth } } impl core::ops::Deref for DebugDepthGuard { type Target = usize; #[inline(always)] fn deref(&self) -> &Self::Target { &self.depth } } toml_edit-0.24.0+spec-1.1.0/src/parser/document.rs000064400000000000000000000457241046102023000175330ustar 00000000000000use crate::key::Key; use crate::parser::key::on_key; use crate::parser::prelude::*; use crate::parser::value::value; use crate::repr::Decor; use crate::Item; use crate::RawString; use crate::Value; use crate::{ArrayOfTables, Document, Table}; /// ```abnf /// ;; TOML /// /// toml = expression *( newline expression ) /// /// expression = ( ( ws comment ) / /// ( ws keyval ws [ comment ] ) / /// ( ws table ws [ comment ] ) / /// ws ) /// ``` pub(crate) fn document<'s>( input: &mut Input<'_>, source: toml_parser::Source<'s>, errors: &mut dyn ErrorSink, ) -> Document<&'s str> { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::document"); let mut state = State::default(); while let Some(event) = input.next_token() { match event.kind() { EventKind::InlineTableOpen | EventKind::InlineTableClose | EventKind::ArrayOpen | EventKind::ArrayClose | EventKind::Scalar | EventKind::ValueSep | EventKind::Error | EventKind::KeySep | EventKind::KeyValSep | EventKind::StdTableClose | EventKind::ArrayTableClose => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); continue; } EventKind::StdTableOpen | EventKind::ArrayTableOpen => { state.finish_table(errors); let prefix = state.take_trailing(); let header = on_table(event, input, source, errors); let suffix = ws_comment_newline(input) .map(|s| RawString::with_span(s.start()..s.end())) .unwrap_or_default(); let decor = Decor::new(prefix, suffix); state.start_table(header, decor, errors); } EventKind::SimpleKey => { let key_prefix = state.take_trailing(); let (path, key) = on_key(event, input, source, errors); let Some(mut key) = key else { break; }; let Some(next_event) = input.next_token() else { break; }; let keyval_event; let key_suffix; if next_event.kind() == EventKind::Whitespace { key_suffix = Some(next_event); let Some(next_event) = input.next_token() else { break; }; keyval_event = next_event; } else { key_suffix = None; keyval_event = next_event; } if keyval_event.kind() != EventKind::KeyValSep { break; } let key_suffix = key_suffix .map(|e| RawString::with_span(e.span().start()..e.span().end())) .unwrap_or_default(); key.leaf_decor.set_prefix(key_prefix); key.leaf_decor.set_suffix(key_suffix); let value_prefix = if input .first() .map(|e| e.kind() == EventKind::Whitespace) .unwrap_or(false) { input .next_token() .map(|e| RawString::with_span(e.span().start()..e.span().end())) } else { None } .unwrap_or_default(); let mut value = value(input, source, errors); let value_suffix = ws_comment_newline(input) .map(|s| RawString::with_span(s.start()..s.end())) .unwrap_or_default(); let decor = value.decor_mut(); decor.set_prefix(value_prefix); decor.set_suffix(value_suffix); state.capture_key_value(path, key, value, errors); } EventKind::Whitespace | EventKind::Comment | EventKind::Newline => { state.capture_trailing(event); } } } state.finish_table(errors); let trailing = state.take_trailing(); Document { root: Item::Table(state.root), trailing, raw: source.input(), } } /// ```abnf /// ;; Standard Table /// /// std-table = std-table-open key *( table-key-sep key) std-table-close /// /// ;; Array Table /// /// array-table = array-table-open key *( table-key-sep key) array-table-close /// ``` fn on_table( open_event: &toml_parser::parser::Event, input: &mut Input<'_>, source: toml_parser::Source<'_>, errors: &mut dyn ErrorSink, ) -> TableHeader { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::on_table"); let is_array = open_event.kind() == EventKind::ArrayTableOpen; let mut current_path = None; let mut current_key = None; let mut current_span = open_event.span(); let mut current_prefix = None; let mut current_suffix = None; while let Some(event) = input.next_token() { match event.kind() { EventKind::InlineTableOpen | EventKind::InlineTableClose | EventKind::ArrayOpen | EventKind::ArrayClose | EventKind::Scalar | EventKind::ValueSep | EventKind::Error | EventKind::KeySep | EventKind::KeyValSep | EventKind::StdTableOpen | EventKind::ArrayTableOpen | EventKind::Comment | EventKind::Newline => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); continue; } EventKind::ArrayTableClose | EventKind::StdTableClose => { current_span = current_span.append(event.span()); break; } EventKind::SimpleKey => { current_prefix.get_or_insert_with(|| event.span().before()); let (path, key) = on_key(event, input, source, errors); current_path = Some(path); current_key = key; current_suffix.get_or_insert_with(|| event.span().after()); } EventKind::Whitespace => { if current_key.is_some() { current_suffix = Some(event.span()); } else { current_prefix = Some(event.span()); } } } } let prefix = current_prefix .take() .expect("setting a key should set a prefix"); let suffix = current_suffix .take() .expect("setting a key should set a suffix"); if let Some(last_key) = current_key.as_mut() { let prefix = RawString::with_span(prefix.start()..prefix.end()); let suffix = RawString::with_span(suffix.start()..suffix.end()); let leaf_decor = Decor::new(prefix, suffix); *last_key.leaf_decor_mut() = leaf_decor; } TableHeader { path: current_path.unwrap_or_default(), key: current_key, span: current_span, is_array, } } struct TableHeader { path: Vec, key: Option, span: toml_parser::Span, is_array: bool, } fn ws_comment_newline(input: &mut Input<'_>) -> Option { let mut current_span = None; while let Some(event) = input.next_token() { match event.kind() { EventKind::InlineTableOpen | EventKind::InlineTableClose | EventKind::ArrayOpen | EventKind::ArrayClose | EventKind::Scalar | EventKind::ValueSep | EventKind::Error | EventKind::SimpleKey | EventKind::KeySep | EventKind::KeyValSep | EventKind::StdTableOpen | EventKind::ArrayTableOpen | EventKind::StdTableClose | EventKind::ArrayTableClose => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); } EventKind::Whitespace | EventKind::Comment => { let span = current_span.get_or_insert_with(|| event.span()); *span = span.append(event.span()); } EventKind::Newline => { break; } } } current_span } #[derive(Default)] struct State { root: Table, current_table: Table, current_trailing: Option, current_header: Option, current_position: isize, } impl State { fn capture_trailing(&mut self, event: &toml_parser::parser::Event) { let decor = self.current_trailing.get_or_insert(event.span()); *decor = decor.append(event.span()); } fn capture_key_value( &mut self, path: Vec, key: Key, value: Value, errors: &mut dyn ErrorSink, ) { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::capture_key_value"); #[cfg(feature = "debug")] trace( &format!( "path={:?}", path.iter().map(|k| k.get()).collect::>() ), anstyle::AnsiColor::Blue.on_default(), ); #[cfg(feature = "debug")] trace( &format!("key={key}",), anstyle::AnsiColor::Blue.on_default(), ); #[cfg(feature = "debug")] trace( &format!("value={value:?}",), anstyle::AnsiColor::Blue.on_default(), ); let dotted = true; let Some(parent_table) = descend_path(&mut self.current_table, &path, dotted, errors) else { return; }; // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed" let mixed_table_types = parent_table.is_dotted() == path.is_empty(); if mixed_table_types { let key_span = get_key_span(&key).expect("all keys have spans"); errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span)); return; } let key_span = get_key_span(&key).expect("all keys have spans"); match parent_table.items.entry(key) { indexmap::map::Entry::Vacant(o) => { o.insert(Item::Value(value)); } indexmap::map::Entry::Occupied(existing) => { // "Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed" let old_span = existing.key().span().expect("all items have spans"); let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end); errors.report_error( ParseError::new("duplicate key") .with_unexpected(key_span) .with_context(old_span), ); } } } fn finish_table(&mut self, errors: &mut dyn ErrorSink) { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::finish_table"); let mut prev_table = std::mem::take(&mut self.current_table); if let Some(header) = self.current_header.take() { let Some(key) = &header.key else { return; }; prev_table.span = Some(header.span.start()..header.span.end()); let parent_key = &header.path; let dotted = false; let Some(parent_table) = descend_path(&mut self.root, parent_key, dotted, errors) else { return; }; #[cfg(feature = "debug")] trace( &format!("key={key}",), anstyle::AnsiColor::Blue.on_default(), ); if header.is_array { let entry = parent_table .entry_format(key) .or_insert(Item::ArrayOfTables(ArrayOfTables::new())); let Some(array) = entry.as_array_of_tables_mut() else { let key_span = get_key_span(key).expect("all keys have spans"); let old_span = entry.span().unwrap_or_default(); let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end); errors.report_error( ParseError::new("duplicate key") .with_unexpected(key_span) .with_context(old_span), ); return; }; array.push(prev_table); let span = if let (Some(first), Some(last)) = ( array.values.first().and_then(|t| t.span()), array.values.last().and_then(|t| t.span()), ) { Some((first.start)..(last.end)) } else { None }; array.span = span; } else { let existing = parent_table.insert_formatted(key, Item::Table(prev_table)); debug_assert!(existing.is_none()); } } else { prev_table.span = Some(Default::default()); self.root = prev_table; } } fn start_table(&mut self, header: TableHeader, decor: Decor, errors: &mut dyn ErrorSink) { if !header.is_array { // 1. Look up the table on start to ensure the duplicate_key error points to the right line // 2. Ensure any child tables from an implicit table are preserved let root = &mut self.root; if let (Some(parent_table), Some(key)) = (descend_path(root, &header.path, false, errors), &header.key) { if let Some((old_key, old_value)) = parent_table.remove_entry(key.get()) { match old_value { Item::Table(t) if t.implicit && !t.is_dotted() => { self.current_table = t; } // Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed. Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed. old_value => { let old_span = old_key.span().expect("all items have spans"); let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end); let key_span = get_key_span(key).expect("all keys have spans"); errors.report_error( ParseError::new("duplicate key") .with_unexpected(key_span) .with_context(old_span), ); if let Item::Table(t) = old_value { self.current_table = t; } } } } } } self.current_position += 1; self.current_table.decor = decor; self.current_table.set_implicit(false); self.current_table.set_dotted(false); self.current_table.set_position(Some(self.current_position)); self.current_table.span = Some(header.span.start()..header.span.end()); self.current_header = Some(header); } fn take_trailing(&mut self) -> RawString { self.current_trailing .take() .map(|s| RawString::with_span(s.start()..s.end())) .unwrap_or_default() } } fn descend_path<'t>( mut table: &'t mut Table, path: &[Key], dotted: bool, errors: &mut dyn ErrorSink, ) -> Option<&'t mut Table> { #[cfg(feature = "debug")] let _scope = TraceScope::new("document::descend_path"); #[cfg(feature = "debug")] trace( &format!( "path={:?}", path.iter().map(|k| k.get()).collect::>() ), anstyle::AnsiColor::Blue.on_default(), ); for key in path.iter() { table = match table.entry_format(key) { crate::Entry::Vacant(entry) => { let mut new_table = Table::new(); new_table.span = key.span(); new_table.set_implicit(true); new_table.set_dotted(dotted); entry.insert(Item::Table(new_table)).as_table_mut().unwrap() } crate::Entry::Occupied(entry) => { match entry.into_mut() { Item::ArrayOfTables(ref mut array) => { debug_assert!(!array.is_empty()); let index = array.len() - 1; let last_child = array.get_mut(index).unwrap(); last_child } Item::Table(ref mut sweet_child_of_mine) => { // Since tables cannot be defined more than once, redefining such tables using a // [table] header is not allowed. Likewise, using dotted keys to redefine tables // already defined in [table] form is not allowed. if dotted && !sweet_child_of_mine.is_implicit() { let key_span = get_key_span(key).expect("all keys have spans"); errors.report_error( ParseError::new("duplicate key").with_unexpected(key_span), ); return None; } sweet_child_of_mine } Item::Value(ref existing) => { let old_span = existing.span().expect("all items have spans"); let old_span = toml_parser::Span::new_unchecked(old_span.start, old_span.end); let key_span = get_key_span(key).expect("all keys have spans"); errors.report_error( ParseError::new(format!( "cannot extend value of type {} with a dotted key", existing.type_name() )) .with_unexpected(key_span) .with_context(old_span), ); return None; } Item::None => unreachable!(), } } }; } Some(table) } fn get_key_span(key: &Key) -> Option { key.as_repr() .and_then(|r| r.span()) .map(|s| toml_parser::Span::new_unchecked(s.start, s.end)) } toml_edit-0.24.0+spec-1.1.0/src/parser/inline_table.rs000064400000000000000000000252151046102023000203330ustar 00000000000000use crate::key::Key; use crate::parser::array::on_array; use crate::parser::key::on_key; use crate::parser::prelude::*; use crate::parser::value::on_scalar; use crate::repr::Decor; use crate::{InlineTable, Item, RawString, Value}; use indexmap::map::Entry; /// ```abnf /// ;; Inline Table /// /// inline-table = inline-table-open [ inline-table-keyvals ] ws-comment-newline inline-table-close /// ``` pub(crate) fn on_inline_table( open_event: &toml_parser::parser::Event, input: &mut Input<'_>, source: toml_parser::Source<'_>, errors: &mut dyn ErrorSink, ) -> Value { #[cfg(feature = "debug")] let _scope = TraceScope::new("inline_table::on_inline_table"); let mut result = InlineTable::new(); let mut state = State::default(); state.open(open_event); while let Some(event) = input.next_token() { match event.kind() { EventKind::StdTableOpen | EventKind::ArrayTableOpen | EventKind::StdTableClose | EventKind::ArrayClose | EventKind::ArrayTableClose | EventKind::KeySep => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); break; } EventKind::Error => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); continue; } EventKind::SimpleKey => { let (path, key) = on_key(event, input, source, errors); state.capture_key(event, path, key); } EventKind::KeyValSep => { state.finish_key(event); } EventKind::InlineTableOpen => { let value = on_inline_table(event, input, source, errors); state.capture_value(event, value); } EventKind::ArrayOpen => { let value = on_array(event, input, source, errors); state.capture_value(event, value); } EventKind::Scalar => { let value = on_scalar(event, source, errors); state.capture_value(event, value); } EventKind::ValueSep => { state.finish_value(event, &mut result, errors); state.sep_value(event); } EventKind::Whitespace | EventKind::Comment | EventKind::Newline => { state.whitespace(event); } EventKind::InlineTableClose => { state.finish_value(event, &mut result, errors); state.close(open_event, event, &mut result); break; } } } Value::InlineTable(result) } #[derive(Default)] struct State { current_prefix: Option, current_key: Option<(Vec, Key)>, seen_keyval_sep: bool, current_value: Option, trailing_start: Option, current_suffix: Option, } impl State { fn open(&mut self, open_event: &toml_parser::parser::Event) { self.trailing_start = Some(open_event.span().end()); } fn whitespace(&mut self, event: &toml_parser::parser::Event) { let decor = if self.is_prefix() { self.current_prefix.get_or_insert(event.span()) } else { self.current_suffix.get_or_insert(event.span()) }; *decor = decor.append(event.span()); } fn is_prefix(&self) -> bool { if self.seen_keyval_sep { self.current_value.is_none() } else { self.current_key.is_none() } } fn capture_key( &mut self, event: &toml_parser::parser::Event, path: Vec, key: Option, ) { self.trailing_start = None; self.current_prefix .get_or_insert_with(|| event.span().before()); if let Some(key) = key { self.current_key = Some((path, key)); } } fn finish_key(&mut self, event: &toml_parser::parser::Event) { self.seen_keyval_sep = true; if let Some(last_key) = self.current_key.as_mut().map(|(_, k)| k) { let prefix = self .current_prefix .take() .expect("setting a key should set a prefix"); let suffix = self .current_suffix .take() .unwrap_or_else(|| event.span().before()); let prefix = RawString::with_span(prefix.start()..prefix.end()); let suffix = RawString::with_span(suffix.start()..suffix.end()); let leaf_decor = Decor::new(prefix, suffix); *last_key.leaf_decor_mut() = leaf_decor; } } fn capture_value(&mut self, event: &toml_parser::parser::Event, value: Value) { self.current_prefix .get_or_insert_with(|| event.span().before()); self.current_value = Some(value); } fn finish_value( &mut self, event: &toml_parser::parser::Event, result: &mut InlineTable, errors: &mut dyn ErrorSink, ) { #[cfg(feature = "debug")] let _scope = TraceScope::new("inline_table::finish_value"); self.seen_keyval_sep = false; if let (Some((path, key)), Some(mut value)) = (self.current_key.take(), self.current_value.take()) { let prefix = self .current_prefix .take() .expect("setting a value should set a prefix"); let suffix = self .current_suffix .take() .unwrap_or_else(|| event.span().before()); let Some(table) = descend_path(result, &path, true, errors) else { return; }; let decor = value.decor_mut(); decor.set_prefix(RawString::with_span(prefix.start()..prefix.end())); decor.set_suffix(RawString::with_span(suffix.start()..suffix.end())); // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed" let mixed_table_types = table.is_dotted() == path.is_empty(); if mixed_table_types { let key_span = get_key_span(&key).unwrap_or_else(|| event.span()); errors.report_error(ParseError::new("duplicate key").with_unexpected(key_span)); } else { let key_span = get_key_span(&key).unwrap_or_else(|| event.span()); match table.items.entry(key) { Entry::Vacant(o) => { o.insert(Item::Value(value)); } Entry::Occupied(o) => { let old_span = get_key_span(o.key()).unwrap_or_else(|| event.span()); errors.report_error( ParseError::new("duplicate key") .with_unexpected(key_span) .with_context(old_span), ); } } } } } fn sep_value(&mut self, event: &toml_parser::parser::Event) { self.trailing_start = Some(event.span().end()); } fn close( &mut self, open_event: &toml_parser::parser::Event, close_event: &toml_parser::parser::Event, result: &mut InlineTable, ) { #[cfg(feature = "debug")] let _scope = TraceScope::new("inline_table::close"); let trailing_comma = self.trailing_start.is_some() && !result.is_empty(); let span = open_event.span().append(close_event.span()); let trailing_start = self .trailing_start .unwrap_or_else(|| close_event.span().start()); let trailing_end = close_event.span().start(); result.set_trailing_comma(trailing_comma); result.set_trailing(RawString::with_span(trailing_start..trailing_end)); result.span = Some(span.start()..span.end()); } } fn descend_path<'a>( mut table: &'a mut InlineTable, path: &'a [Key], dotted: bool, errors: &mut dyn ErrorSink, ) -> Option<&'a mut InlineTable> { #[cfg(feature = "debug")] let _scope = TraceScope::new("inline_table::descend_path"); #[cfg(feature = "debug")] trace( &format!("key={:?}", path.iter().map(|k| k.get()).collect::>()), anstyle::AnsiColor::Blue.on_default(), ); for key in path.iter() { table = match table.entry_format(key) { crate::InlineEntry::Vacant(entry) => { let mut new_table = InlineTable::new(); new_table.span = key.span(); new_table.set_implicit(true); new_table.set_dotted(dotted); entry .insert(Value::InlineTable(new_table)) .as_inline_table_mut() .unwrap() } crate::InlineEntry::Occupied(entry) => { match entry.into_mut() { Value::InlineTable(ref mut sweet_child_of_mine) => { // Since tables cannot be defined more than once, redefining such tables using a // [table] header is not allowed. Likewise, using dotted keys to redefine tables // already defined in [table] form is not allowed. if dotted && !sweet_child_of_mine.is_implicit() { let key_span = get_key_span(key).expect("all keys have spans"); errors.report_error( ParseError::new("duplicate key").with_unexpected(key_span), ); return None; } sweet_child_of_mine } item => { let key_span = get_key_span(key).expect("all keys have spans"); errors.report_error( ParseError::new(format!( "cannot extend value of type {} with a dotted key", item.type_name() )) .with_unexpected(key_span), ); return None; } } } }; } Some(table) } fn get_key_span(key: &Key) -> Option { key.as_repr() .and_then(|r| r.span()) .map(|s| toml_parser::Span::new_unchecked(s.start, s.end)) } toml_edit-0.24.0+spec-1.1.0/src/parser/key.rs000064400000000000000000000121211046102023000164660ustar 00000000000000use crate::key::Key; use crate::parser::prelude::*; use crate::repr::Decor; use crate::repr::Repr; use crate::RawString; /// ```abnf /// key = simple-key / dotted-key /// dotted-key = simple-key 1*( dot-sep simple-key ) /// ``` pub(crate) fn on_key( key_event: &toml_parser::parser::Event, input: &mut Input<'_>, source: toml_parser::Source<'_>, errors: &mut dyn ErrorSink, ) -> (Vec, Option) { #[cfg(feature = "debug")] let _scope = TraceScope::new("key::on_key"); let mut result_path = Vec::new(); let mut result_key = None; let mut state = State::new(key_event); if more_key(input) { while let Some(event) = input.next_token() { match event.kind() { EventKind::StdTableOpen | EventKind::ArrayTableOpen | EventKind::InlineTableOpen | EventKind::InlineTableClose | EventKind::ArrayOpen | EventKind::ArrayClose | EventKind::Scalar | EventKind::ValueSep | EventKind::Comment | EventKind::Newline | EventKind::KeyValSep | EventKind::StdTableClose | EventKind::ArrayTableClose | EventKind::Error => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); continue; } EventKind::SimpleKey => { state.current_key = Some(*event); if !more_key(input) { break; } } EventKind::Whitespace => { state.whitespace(event); } EventKind::KeySep => { state.close_key(&mut result_path, &mut result_key, source, errors); } } } } state.close_key(&mut result_path, &mut result_key, source, errors); #[cfg(not(feature = "unbounded"))] if super::LIMIT <= result_path.len() as u32 { errors.report_error(ParseError::new("recursion limit")); return (Vec::new(), None); } (result_path, result_key) } fn more_key(input: &Input<'_>) -> bool { let first = input.get(0).map(|e| e.kind()); let second = input.get(1).map(|e| e.kind()); if first == Some(EventKind::KeySep) { true } else if first == Some(EventKind::Whitespace) && second == Some(EventKind::KeySep) { true } else { false } } struct State { current_prefix: Option, current_key: Option, current_suffix: Option, } impl State { fn new(key_event: &toml_parser::parser::Event) -> Self { Self { current_prefix: None, current_key: Some(*key_event), current_suffix: None, } } fn whitespace(&mut self, event: &toml_parser::parser::Event) { if self.current_key.is_some() { self.current_suffix = Some(event.span()); } else { self.current_prefix = Some(event.span()); } } fn close_key( &mut self, result_path: &mut Vec, result_key: &mut Option, source: toml_parser::Source<'_>, errors: &mut dyn ErrorSink, ) { let Some(key) = self.current_key.take() else { return; }; let prefix_span = self .current_prefix .take() .unwrap_or_else(|| key.span().before()); let prefix = RawString::with_span(prefix_span.start()..prefix_span.end()); let suffix_span = self .current_suffix .take() .unwrap_or_else(|| key.span().after()); let suffix = RawString::with_span(suffix_span.start()..suffix_span.end()); let key_span = key.span(); let key_raw = RawString::with_span(key_span.start()..key_span.end()); let raw = source.get(key).unwrap(); let mut decoded = std::borrow::Cow::Borrowed(""); raw.decode_key(&mut decoded, errors); let key = Key::new(decoded) .with_repr_unchecked(Repr::new_unchecked(key_raw)) .with_dotted_decor(Decor::new(prefix, suffix)); if let Some(last_key) = result_key.replace(key) { result_path.push(last_key); } } } /// ```abnf /// simple-key = quoted-key / unquoted-key /// quoted-key = basic-string / literal-string /// ``` pub(crate) fn on_simple_key( event: &toml_parser::parser::Event, source: toml_parser::Source<'_>, errors: &mut dyn ErrorSink, ) -> (RawString, String) { #[cfg(feature = "debug")] let _scope = TraceScope::new("key::on_simple_key"); let raw = source.get(event).unwrap(); let mut key = std::borrow::Cow::Borrowed(""); raw.decode_key(&mut key, errors); let span = event.span(); let raw = RawString::with_span(span.start()..span.end()); let key = String::from(key); (raw, key) } toml_edit-0.24.0+spec-1.1.0/src/parser/mod.rs000064400000000000000000000121331046102023000164600ustar 00000000000000#![allow(clippy::type_complexity)] use crate::RawString; #[cfg(not(feature = "unbounded"))] use toml_parser::parser::RecursionGuard; use toml_parser::parser::ValidateWhitespace; use winnow::stream::Stream as _; pub(crate) mod array; #[cfg(feature = "debug")] pub(crate) mod debug; pub(crate) mod document; pub(crate) mod inline_table; pub(crate) mod key; pub(crate) mod value; pub(crate) fn parse_document<'s>( source: toml_parser::Source<'s>, errors: &mut dyn prelude::ErrorSink, ) -> crate::Document<&'s str> { let tokens = source.lex().into_vec(); let mut events = Vec::with_capacity(tokens.len()); let mut receiver = ValidateWhitespace::new(&mut events, source); #[cfg(not(feature = "unbounded"))] let mut receiver = RecursionGuard::new(&mut receiver, LIMIT); #[cfg(not(feature = "unbounded"))] let receiver = &mut receiver; #[cfg(feature = "unbounded")] let receiver = &mut receiver; toml_parser::parser::parse_document(&tokens, receiver, errors); let mut input = prelude::Input::new(&events); let doc = document::document(&mut input, source, errors); doc } pub(crate) fn parse_key( source: toml_parser::Source<'_>, errors: &mut dyn prelude::ErrorSink, ) -> crate::Key { let tokens = source.lex().into_vec(); let mut events = Vec::with_capacity(tokens.len()); let mut receiver = ValidateWhitespace::new(&mut events, source); #[cfg(not(feature = "unbounded"))] let mut receiver = RecursionGuard::new(&mut receiver, LIMIT); #[cfg(not(feature = "unbounded"))] let receiver = &mut receiver; #[cfg(feature = "unbounded")] let receiver = &mut receiver; toml_parser::parser::parse_simple_key(&tokens, receiver, errors); if let Some(event) = events .iter() .find(|e| e.kind() == toml_parser::parser::EventKind::SimpleKey) { let (raw, key) = key::on_simple_key(event, source, errors); crate::Key::new(key).with_repr_unchecked(crate::Repr::new_unchecked(raw)) } else { let key = source.input(); let raw = RawString::with_span(0..source.input().len()); crate::Key::new(key).with_repr_unchecked(crate::Repr::new_unchecked(raw)) } } pub(crate) fn parse_key_path( source: toml_parser::Source<'_>, errors: &mut dyn prelude::ErrorSink, ) -> Vec { let tokens = source.lex().into_vec(); let mut events = Vec::with_capacity(tokens.len()); let mut receiver = ValidateWhitespace::new(&mut events, source); #[cfg(not(feature = "unbounded"))] let mut receiver = RecursionGuard::new(&mut receiver, LIMIT); #[cfg(not(feature = "unbounded"))] let receiver = &mut receiver; #[cfg(feature = "unbounded")] let receiver = &mut receiver; toml_parser::parser::parse_key(&tokens, receiver, errors); let mut input = prelude::Input::new(&events); let mut prefix = None; let mut path = None; let mut key = None; let mut suffix = None; while let Some(event) = input.next_token() { match event.kind() { toml_parser::parser::EventKind::Whitespace => { let raw = RawString::with_span(event.span().start()..event.span().end()); if prefix.is_none() { prefix = Some(raw); } else if suffix.is_none() { suffix = Some(raw); } } _ => { let (local_path, local_key) = key::on_key(event, &mut input, source, errors); path = Some(local_path); key = local_key; } } } if let Some(mut key) = key { if let Some(prefix) = prefix { key.leaf_decor.set_prefix(prefix); } if let Some(suffix) = suffix { key.leaf_decor.set_suffix(suffix); } let mut path = path.unwrap_or_default(); path.push(key); path } else { Default::default() } } pub(crate) fn parse_value( source: toml_parser::Source<'_>, errors: &mut dyn prelude::ErrorSink, ) -> crate::Value { let tokens = source.lex().into_vec(); let mut events = Vec::with_capacity(tokens.len()); let mut receiver = ValidateWhitespace::new(&mut events, source); #[cfg(not(feature = "unbounded"))] let mut receiver = RecursionGuard::new(&mut receiver, LIMIT); #[cfg(not(feature = "unbounded"))] let receiver = &mut receiver; #[cfg(feature = "unbounded")] let receiver = &mut receiver; toml_parser::parser::parse_value(&tokens, receiver, errors); let mut input = prelude::Input::new(&events); let value = value::value(&mut input, source, errors); value } #[cfg(not(feature = "unbounded"))] const LIMIT: u32 = 80; pub(crate) mod prelude { pub(crate) use toml_parser::parser::EventKind; pub(crate) use toml_parser::ErrorSink; pub(crate) use toml_parser::ParseError; pub(crate) use winnow::stream::Stream as _; pub(crate) type Input<'i> = winnow::stream::TokenSlice<'i, toml_parser::parser::Event>; #[cfg(feature = "debug")] pub(crate) use super::debug::trace; #[cfg(feature = "debug")] pub(crate) use super::debug::TraceScope; } toml_edit-0.24.0+spec-1.1.0/src/parser/value.rs000064400000000000000000000123551046102023000170230ustar 00000000000000use crate::parser::array::on_array; use crate::parser::inline_table::on_inline_table; use crate::parser::prelude::*; use crate::repr::{Formatted, Repr}; use crate::RawString; use crate::Value; /// ```abnf /// val = string / boolean / array / inline-table / date-time / float / integer /// ``` pub(crate) fn value( input: &mut Input<'_>, source: toml_parser::Source<'_>, errors: &mut dyn ErrorSink, ) -> Value { #[cfg(feature = "debug")] let _scope = TraceScope::new("value"); if let Some(event) = input.next_token() { match event.kind() { EventKind::StdTableOpen | EventKind::ArrayTableOpen | EventKind::InlineTableClose | EventKind::ArrayClose | EventKind::ValueSep | EventKind::Comment | EventKind::Newline | EventKind::Error | EventKind::SimpleKey | EventKind::KeySep | EventKind::KeyValSep | EventKind::StdTableClose | EventKind::ArrayTableClose => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); } EventKind::Whitespace => { #[cfg(feature = "debug")] trace( &format!("unexpected {event:?}"), anstyle::AnsiColor::Red.on_default(), ); } EventKind::InlineTableOpen => { return on_inline_table(event, input, source, errors); } EventKind::ArrayOpen => { return on_array(event, input, source, errors); } EventKind::Scalar => { return on_scalar(event, source, errors); } } } Value::from(0) } pub(crate) fn on_scalar( event: &toml_parser::parser::Event, source: toml_parser::Source<'_>, errors: &mut dyn ErrorSink, ) -> Value { #[cfg(feature = "debug")] let _scope = TraceScope::new("on_scalar"); let value_span = event.span(); let value_raw = RawString::with_span(value_span.start()..value_span.end()); let raw = source.get(event).unwrap(); let mut decoded = std::borrow::Cow::Borrowed(""); let kind = raw.decode_scalar(&mut decoded, errors); match kind { toml_parser::decoder::ScalarKind::String => { let mut f = Formatted::new(decoded.into()); f.set_repr_unchecked(Repr::new_unchecked(value_raw)); Value::String(f) } toml_parser::decoder::ScalarKind::Boolean(value) => { let mut f = Formatted::new(value); f.set_repr_unchecked(Repr::new_unchecked(value_raw)); Value::Boolean(f) } toml_parser::decoder::ScalarKind::DateTime => { let value = match decoded.parse::() { Ok(value) => value, Err(err) => { errors.report_error( ParseError::new(err.to_string()).with_unexpected(event.span()), ); toml_datetime::Datetime { date: None, time: None, offset: None, } } }; let mut f = Formatted::new(value); f.set_repr_unchecked(Repr::new_unchecked(value_raw)); Value::Datetime(f) } toml_parser::decoder::ScalarKind::Float => { let value = match decoded.parse::() { Ok(value) => { if value.is_infinite() && !(decoded .strip_prefix(['+', '-']) .unwrap_or(&decoded) .chars() .all(|c| c.is_ascii_alphabetic())) { errors.report_error( ParseError::new("floating-point number overflowed") .with_unexpected(event.span()), ); } value } Err(_) => { errors.report_error( ParseError::new(kind.invalid_description()).with_unexpected(event.span()), ); f64::NAN } }; let mut f = Formatted::new(value); f.set_repr_unchecked(Repr::new_unchecked(value_raw)); Value::Float(f) } toml_parser::decoder::ScalarKind::Integer(radix) => { let value = match i64::from_str_radix(&decoded, radix.value()) { Ok(value) => value, Err(_) => { // Assuming the decoder fully validated it, leaving only overflow errors errors.report_error( ParseError::new("integer number overflowed").with_unexpected(event.span()), ); i64::MAX } }; let mut f = Formatted::new(value); f.set_repr_unchecked(Repr::new_unchecked(value_raw)); Value::Integer(f) } } } toml_edit-0.24.0+spec-1.1.0/src/raw_string.rs000064400000000000000000000112351046102023000165660ustar 00000000000000/// Opaque string storage for raw TOML; internal to `toml_edit` #[derive(PartialEq, Eq, Clone, Hash)] pub struct RawString(RawStringInner); #[derive(PartialEq, Eq, Clone, Hash)] enum RawStringInner { Empty, Explicit(String), Spanned(std::ops::Range), } impl RawString { pub(crate) fn with_span(span: std::ops::Range) -> Self { Self(RawStringInner::Spanned(span)) } /// Access the underlying string /// /// This generally requires a [`DocumentMut`][crate::DocumentMut]. pub fn as_str(&self) -> Option<&str> { match &self.0 { RawStringInner::Empty => Some(""), RawStringInner::Explicit(s) => Some(s.as_str()), RawStringInner::Spanned(_) => None, } } /// The location within the original document /// /// This generally requires a [`Document`][crate::Document]. pub fn span(&self) -> Option> { match &self.0 { RawStringInner::Empty => None, RawStringInner::Explicit(_) => None, RawStringInner::Spanned(span) => Some(span.clone()), } } pub(crate) fn to_str<'s>(&'s self, input: &'s str) -> &'s str { match &self.0 { RawStringInner::Empty => "", RawStringInner::Explicit(s) => s.as_str(), RawStringInner::Spanned(span) => input .get(span.clone()) .unwrap_or_else(|| panic!("span {span:?} should be in input:\n```\n{input}\n```")), } } pub(crate) fn to_str_with_default<'s>( &'s self, input: Option<&'s str>, default: &'s str, ) -> &'s str { match &self.0 { RawStringInner::Empty => "", RawStringInner::Explicit(s) => s.as_str(), RawStringInner::Spanned(span) => { if let Some(input) = input { input.get(span.clone()).unwrap_or_else(|| { panic!("span {span:?} should be in input:\n```\n{input}\n```") }) } else { default } } } } pub(crate) fn despan(&mut self, input: &str) { match &self.0 { RawStringInner::Empty => {} RawStringInner::Explicit(_) => {} RawStringInner::Spanned(span) => { if span.start == span.end { *self = Self(RawStringInner::Empty); } else { *self = Self::from(input.get(span.clone()).unwrap_or_else(|| { panic!("span {span:?} should be in input:\n```\n{input}\n```") })); } } } } #[cfg(feature = "display")] pub(crate) fn encode(&self, buf: &mut dyn std::fmt::Write, input: &str) -> std::fmt::Result { let raw = self.to_str(input); for part in raw.split('\r') { write!(buf, "{part}")?; } Ok(()) } #[cfg(feature = "display")] pub(crate) fn encode_with_default( &self, buf: &mut dyn std::fmt::Write, input: Option<&str>, default: &str, ) -> std::fmt::Result { let raw = self.to_str_with_default(input, default); for part in raw.split('\r') { write!(buf, "{part}")?; } Ok(()) } } impl Default for RawString { fn default() -> Self { Self(RawStringInner::Empty) } } impl std::fmt::Debug for RawString { #[inline] fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match &self.0 { RawStringInner::Empty => write!(formatter, "empty"), RawStringInner::Explicit(s) => write!(formatter, "{s:?}"), RawStringInner::Spanned(s) => write!(formatter, "{s:?}"), } } } impl From<&str> for RawString { #[inline] fn from(s: &str) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { String::from(s).into() } } } impl From for RawString { #[inline] fn from(s: String) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { Self(RawStringInner::Explicit(s)) } } } impl From<&String> for RawString { #[inline] fn from(s: &String) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { String::from(s).into() } } } impl From> for RawString { #[inline] fn from(s: Box) -> Self { if s.is_empty() { Self(RawStringInner::Empty) } else { String::from(s).into() } } } toml_edit-0.24.0+spec-1.1.0/src/repr.rs000064400000000000000000000155441046102023000153660ustar 00000000000000use std::borrow::Cow; use crate::RawString; /// A scalar TOML [`Value`][crate::Value]'s logical value and its representation in a `&str` /// /// This includes the surrounding whitespace and comments. #[derive(Eq, PartialEq, Clone, Hash)] pub struct Formatted { value: T, repr: Option, decor: Decor, } impl Formatted where T: ValueRepr, { /// Default-formatted value pub fn new(value: T) -> Self { Self { value, repr: None, decor: Default::default(), } } pub(crate) fn set_repr_unchecked(&mut self, repr: Repr) { self.repr = Some(repr); } /// The wrapped value pub fn value(&self) -> &T { &self.value } /// The wrapped value pub fn into_value(self) -> T { self.value } /// Returns the 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 { self.value.to_repr() } /// 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()) }) } /// The location within the original document /// /// This generally requires a [`Document`][crate::Document]. pub fn span(&self) -> Option> { self.repr.as_ref().and_then(|r| r.span()) } pub(crate) fn despan(&mut self, input: &str) { self.decor.despan(input); if let Some(repr) = &mut self.repr { repr.despan(input); } } /// 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 } /// Auto formats the value. pub fn fmt(&mut self) { self.repr = None; } } impl std::fmt::Debug for Formatted where T: std::fmt::Debug, { #[inline] fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { let mut d = formatter.debug_struct("Formatted"); d.field("value", &self.value); match &self.repr { Some(r) => d.field("repr", r), None => d.field("repr", &"default"), }; d.field("decor", &self.decor); d.finish() } } #[cfg(feature = "display")] impl std::fmt::Display for Formatted where T: ValueRepr, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { crate::encode::encode_formatted(self, f, None, ("", "")) } } pub trait ValueRepr: crate::private::Sealed { /// The TOML representation of the value #[cfg(feature = "display")] fn to_repr(&self) -> Repr; } #[cfg(not(feature = "display"))] mod inner { use super::ValueRepr; impl ValueRepr for String {} impl ValueRepr for i64 {} impl ValueRepr for f64 {} impl ValueRepr for bool {} impl ValueRepr for toml_datetime::Datetime {} } /// A TOML [`Value`][crate::Value] encoded as a `&str` #[derive(Eq, PartialEq, Clone, Hash)] pub struct Repr { raw_value: RawString, } impl Repr { pub(crate) fn new_unchecked(raw: impl Into) -> Self { Self { raw_value: raw.into(), } } /// Access the underlying value pub fn as_raw(&self) -> &RawString { &self.raw_value } /// The location within the original document /// /// This generally requires a [`Document`][crate::Document]. pub fn span(&self) -> Option> { self.raw_value.span() } pub(crate) fn despan(&mut self, input: &str) { self.raw_value.despan(input); } #[cfg(feature = "display")] pub(crate) fn encode(&self, buf: &mut dyn std::fmt::Write, input: &str) -> std::fmt::Result { self.as_raw().encode(buf, input) } } impl std::fmt::Debug for Repr { #[inline] fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { self.raw_value.fmt(formatter) } } /// A prefix and suffix, /// /// Including comments, whitespaces and newlines. #[derive(Eq, PartialEq, Clone, Default, Hash)] pub struct Decor { prefix: Option, suffix: Option, } impl Decor { /// Creates a new decor from the given prefix and suffix. pub fn new(prefix: impl Into, suffix: impl Into) -> Self { Self { prefix: Some(prefix.into()), suffix: Some(suffix.into()), } } /// Go back to default decor pub fn clear(&mut self) { self.prefix = None; self.suffix = None; } /// Get the prefix. pub fn prefix(&self) -> Option<&RawString> { self.prefix.as_ref() } #[cfg(feature = "display")] pub(crate) fn prefix_encode( &self, buf: &mut dyn std::fmt::Write, input: Option<&str>, default: &str, ) -> std::fmt::Result { if let Some(prefix) = self.prefix() { prefix.encode_with_default(buf, input, default) } else { write!(buf, "{default}") } } /// Set the prefix. pub fn set_prefix(&mut self, prefix: impl Into) { self.prefix = Some(prefix.into()); } /// Get the suffix. pub fn suffix(&self) -> Option<&RawString> { self.suffix.as_ref() } #[cfg(feature = "display")] pub(crate) fn suffix_encode( &self, buf: &mut dyn std::fmt::Write, input: Option<&str>, default: &str, ) -> std::fmt::Result { if let Some(suffix) = self.suffix() { suffix.encode_with_default(buf, input, default) } else { write!(buf, "{default}") } } /// Set the suffix. pub fn set_suffix(&mut self, suffix: impl Into) { self.suffix = Some(suffix.into()); } pub(crate) fn despan(&mut self, input: &str) { if let Some(prefix) = &mut self.prefix { prefix.despan(input); } if let Some(suffix) = &mut self.suffix { suffix.despan(input); } } } impl std::fmt::Debug for Decor { #[inline] fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { let mut d = formatter.debug_struct("Decor"); match &self.prefix { Some(r) => d.field("prefix", r), None => d.field("prefix", &"default"), }; match &self.suffix { Some(r) => d.field("suffix", r), None => d.field("suffix", &"default"), }; d.finish() } } toml_edit-0.24.0+spec-1.1.0/src/ser/array.rs000064400000000000000000000053241046102023000163200ustar 00000000000000use super::Error; #[doc(hidden)] pub struct SerializeValueArray { values: Vec, } impl SerializeValueArray { pub(crate) fn seq(len: Option) -> Self { let mut values = Vec::new(); if let Some(len) = len { values.reserve(len); } Self { values } } } impl serde_core::ser::SerializeSeq for SerializeValueArray { type Ok = crate::Value; type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Error> where T: serde_core::ser::Serialize + ?Sized, { let value = value.serialize(super::ValueSerializer {})?; self.values.push(crate::Item::Value(value)); Ok(()) } fn end(self) -> Result { Ok(crate::Value::Array(crate::Array::with_vec(self.values))) } } impl serde_core::ser::SerializeTuple for SerializeValueArray { type Ok = crate::Value; type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Error> where T: serde_core::ser::Serialize + ?Sized, { serde_core::ser::SerializeSeq::serialize_element(self, value) } fn end(self) -> Result { serde_core::ser::SerializeSeq::end(self) } } impl serde_core::ser::SerializeTupleStruct for SerializeValueArray { type Ok = crate::Value; type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<(), Error> where T: serde_core::ser::Serialize + ?Sized, { serde_core::ser::SerializeSeq::serialize_element(self, value) } fn end(self) -> Result { serde_core::ser::SerializeSeq::end(self) } } pub struct SerializeTupleVariant { variant: &'static str, inner: SerializeValueArray, } impl SerializeTupleVariant { pub(crate) fn tuple(variant: &'static str, len: usize) -> Self { Self { variant, inner: SerializeValueArray::seq(Some(len)), } } } impl serde_core::ser::SerializeTupleVariant for SerializeTupleVariant { type Ok = crate::Value; type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<(), Error> where T: serde_core::ser::Serialize + ?Sized, { serde_core::ser::SerializeSeq::serialize_element(&mut self.inner, value) } fn end(self) -> Result { let inner = serde_core::ser::SerializeSeq::end(self.inner)?; let mut items = crate::table::KeyValuePairs::new(); let value = crate::Item::Value(inner); items.insert(crate::Key::new(self.variant), value); Ok(crate::Value::InlineTable(crate::InlineTable::with_pairs( items, ))) } } toml_edit-0.24.0+spec-1.1.0/src/ser/error.rs000064400000000000000000000045331046102023000163340ustar 00000000000000/// Errors that can occur when deserializing a type. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum Error { /// Type could not be serialized to TOML UnsupportedType(Option<&'static str>), /// Value was out of range for the given type OutOfRange(Option<&'static str>), /// `None` could not be serialized to TOML UnsupportedNone, /// Key was not convertible to `String` for serializing to TOML KeyNotString, /// A serialized date was invalid DateInvalid, /// Other serialization error Custom(String), } impl Error { pub(crate) fn custom(msg: T) -> Self where T: std::fmt::Display, { Self::Custom(msg.to_string()) } pub(crate) fn unsupported_type(t: Option<&'static str>) -> Self { Self::UnsupportedType(t) } pub(crate) fn out_of_range(t: Option<&'static str>) -> Self { Self::OutOfRange(t) } pub(crate) fn unsupported_none() -> Self { Self::UnsupportedNone } pub(crate) fn key_not_string() -> Self { Self::KeyNotString } pub(crate) fn date_invalid() -> Self { Self::DateInvalid } } impl serde_core::ser::Error for Error { fn custom(msg: T) -> Self where T: std::fmt::Display, { Self::custom(msg) } } impl std::fmt::Display for Error { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::UnsupportedType(Some(t)) => write!(formatter, "unsupported {t} type"), Self::UnsupportedType(None) => write!(formatter, "unsupported rust type"), Self::OutOfRange(Some(t)) => write!(formatter, "out-of-range value for {t} type"), Self::OutOfRange(None) => write!(formatter, "out-of-range value"), Self::UnsupportedNone => "unsupported None value".fmt(formatter), Self::KeyNotString => "map key was not a string".fmt(formatter), Self::DateInvalid => "a serialized date was invalid".fmt(formatter), Self::Custom(s) => s.fmt(formatter), } } } impl From for Error { fn from(e: crate::TomlError) -> Self { Self::custom(e) } } impl From for crate::TomlError { fn from(e: Error) -> Self { Self::custom(e.to_string(), None) } } impl std::error::Error for Error {} toml_edit-0.24.0+spec-1.1.0/src/ser/key.rs000064400000000000000000000117751046102023000160010ustar 00000000000000use crate::Key; use super::Error; pub(crate) struct KeySerializer; impl serde_core::ser::Serializer for KeySerializer { type Ok = Key; type Error = Error; type SerializeSeq = serde_core::ser::Impossible; type SerializeTuple = serde_core::ser::Impossible; type SerializeTupleStruct = serde_core::ser::Impossible; type SerializeTupleVariant = serde_core::ser::Impossible; type SerializeMap = serde_core::ser::Impossible; type SerializeStruct = serde_core::ser::Impossible; type SerializeStructVariant = serde_core::ser::Impossible; fn serialize_bool(self, v: bool) -> Result { Ok(Key::new(v.to_string())) } fn serialize_i8(self, v: i8) -> Result { Ok(Key::new(v.to_string())) } fn serialize_i16(self, v: i16) -> Result { Ok(Key::new(v.to_string())) } fn serialize_i32(self, v: i32) -> Result { Ok(Key::new(v.to_string())) } fn serialize_i64(self, v: i64) -> Result { Ok(Key::new(v.to_string())) } fn serialize_i128(self, v: i128) -> Result { Ok(Key::new(v.to_string())) } fn serialize_u8(self, v: u8) -> Result { Ok(Key::new(v.to_string())) } fn serialize_u16(self, v: u16) -> Result { Ok(Key::new(v.to_string())) } fn serialize_u32(self, v: u32) -> Result { Ok(Key::new(v.to_string())) } fn serialize_u64(self, v: u64) -> Result { Ok(Key::new(v.to_string())) } fn serialize_u128(self, v: u128) -> Result { Ok(Key::new(v.to_string())) } fn serialize_f32(self, _v: f32) -> Result { Err(Error::key_not_string()) } fn serialize_f64(self, _v: f64) -> Result { Err(Error::key_not_string()) } fn serialize_char(self, v: char) -> Result { Ok(Key::new(v.to_string())) } fn serialize_str(self, value: &str) -> Result { Ok(Key::new(value)) } fn serialize_bytes(self, _value: &[u8]) -> Result { Err(Error::key_not_string()) } fn serialize_none(self) -> Result { Err(Error::key_not_string()) } fn serialize_some(self, _value: &T) -> Result where T: serde_core::ser::Serialize + ?Sized, { Err(Error::key_not_string()) } fn serialize_unit(self) -> Result { Err(Error::key_not_string()) } fn serialize_unit_struct(self, _name: &'static str) -> Result { Err(Error::key_not_string()) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result { Ok(variant.into()) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result where T: serde_core::ser::Serialize + ?Sized, { value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result where T: serde_core::ser::Serialize + ?Sized, { Err(Error::key_not_string()) } fn serialize_seq(self, _len: Option) -> Result { Err(Error::key_not_string()) } fn serialize_tuple(self, _len: usize) -> Result { Err(Error::key_not_string()) } fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(Error::key_not_string()) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::key_not_string()) } fn serialize_map(self, _len: Option) -> Result { Err(Error::key_not_string()) } fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(Error::key_not_string()) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::key_not_string()) } } toml_edit-0.24.0+spec-1.1.0/src/ser/map.rs000064400000000000000000000311631046102023000157570ustar 00000000000000use super::array::SerializeTupleVariant; use super::array::SerializeValueArray; use super::key::KeySerializer; use super::value::ValueSerializer; use super::Error; #[doc(hidden)] #[allow(clippy::large_enum_variant)] pub enum SerializeMap { Datetime(SerializeDatetime), Table(SerializeInlineTable), } impl SerializeMap { pub(crate) fn map(len: Option) -> Self { Self::Table(SerializeInlineTable::map(len)) } pub(crate) fn struct_(name: &'static str, len: Option) -> Self { if toml_datetime::ser::is_datetime(name) { Self::Datetime(SerializeDatetime::new()) } else { Self::map(len) } } } impl serde_core::ser::SerializeMap for SerializeMap { type Ok = crate::Value; type Error = Error; fn serialize_key(&mut self, input: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { match self { Self::Datetime(s) => s.serialize_key(input), Self::Table(s) => s.serialize_key(input), } } fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { match self { Self::Datetime(s) => s.serialize_value(value), Self::Table(s) => s.serialize_value(value), } } fn end(self) -> Result { match self { Self::Datetime(s) => s.end().map(|items| items.into()), Self::Table(s) => s.end().map(|items| items.into()), } } } impl serde_core::ser::SerializeStruct for SerializeMap { type Ok = crate::Value; type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { match self { Self::Datetime(s) => s.serialize_field(key, value), Self::Table(s) => s.serialize_field(key, value), } } fn end(self) -> Result { match self { Self::Datetime(s) => s.end().map(|items| items.into()), Self::Table(s) => s.end().map(|items| items.into()), } } } #[doc(hidden)] pub struct SerializeDatetime { inner: toml_datetime::ser::DatetimeSerializer, } impl SerializeDatetime { pub(crate) fn new() -> Self { Self { inner: toml_datetime::ser::DatetimeSerializer::new(), } } } impl serde_core::ser::SerializeMap for SerializeDatetime { type Ok = crate::Datetime; type Error = Error; fn serialize_key(&mut self, _input: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { unreachable!("datetimes should only be serialized as structs, not maps") } fn serialize_value(&mut self, _value: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { unreachable!("datetimes should only be serialized as structs, not maps") } fn end(self) -> Result { unreachable!("datetimes should only be serialized as structs, not maps") } } impl serde_core::ser::SerializeStruct for SerializeDatetime { type Ok = crate::Datetime; type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { self.inner.serialize_field(key, value).map_err(dt_err)?; Ok(()) } fn end(self) -> Result { let value = self.inner.end().map_err(dt_err)?; Ok(value) } } fn dt_err(err: toml_datetime::ser::SerializerError) -> Error { match err { toml_datetime::ser::SerializerError::InvalidFormat(err) => Error::custom(err), _ => Error::date_invalid(), } } #[doc(hidden)] pub struct SerializeInlineTable { items: crate::table::KeyValuePairs, key: Option, } impl SerializeInlineTable { pub(crate) fn map(len: Option) -> Self { let mut items: crate::table::KeyValuePairs = Default::default(); let key = Default::default(); if let Some(len) = len { items.reserve(len); } Self { items, key } } } impl serde_core::ser::SerializeMap for SerializeInlineTable { type Ok = crate::InlineTable; type Error = Error; fn serialize_key(&mut self, input: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { self.key = Some(input.serialize(KeySerializer)?); Ok(()) } fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { let mut is_none = false; let value_serializer = MapValueSerializer::new(&mut is_none); let res = value.serialize(value_serializer); match res { Ok(item) => { let key = self.key.take().unwrap(); let item = crate::Item::Value(item); self.items.insert(key, item); } Err(e) => { if !(e == Error::unsupported_none() && is_none) { return Err(e); } } } Ok(()) } fn end(self) -> Result { Ok(crate::InlineTable::with_pairs(self.items)) } } impl serde_core::ser::SerializeStruct for SerializeInlineTable { type Ok = crate::InlineTable; type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { let mut is_none = false; let value_serializer = MapValueSerializer::new(&mut is_none); let res = value.serialize(value_serializer); match res { Ok(item) => { let item = crate::Item::Value(item); self.items.insert(crate::Key::new(key), item); } Err(e) => { if !(e == Error::unsupported_none() && is_none) { return Err(e); } } }; Ok(()) } fn end(self) -> Result { Ok(crate::InlineTable::with_pairs(self.items)) } } struct MapValueSerializer<'d> { is_none: &'d mut bool, } impl<'d> MapValueSerializer<'d> { fn new(is_none: &'d mut bool) -> Self { Self { is_none } } } impl serde_core::ser::Serializer for MapValueSerializer<'_> { type Ok = crate::Value; type Error = Error; type SerializeSeq = SerializeValueArray; type SerializeTuple = SerializeValueArray; type SerializeTupleStruct = SerializeValueArray; type SerializeTupleVariant = SerializeTupleVariant; type SerializeMap = SerializeMap; type SerializeStruct = SerializeMap; type SerializeStructVariant = SerializeStructVariant; fn serialize_bool(self, v: bool) -> Result { ValueSerializer::new().serialize_bool(v) } fn serialize_i8(self, v: i8) -> Result { ValueSerializer::new().serialize_i8(v) } fn serialize_i16(self, v: i16) -> Result { ValueSerializer::new().serialize_i16(v) } fn serialize_i32(self, v: i32) -> Result { ValueSerializer::new().serialize_i32(v) } fn serialize_i64(self, v: i64) -> Result { ValueSerializer::new().serialize_i64(v) } fn serialize_u8(self, v: u8) -> Result { ValueSerializer::new().serialize_u8(v) } fn serialize_u16(self, v: u16) -> Result { ValueSerializer::new().serialize_u16(v) } fn serialize_u32(self, v: u32) -> Result { ValueSerializer::new().serialize_u32(v) } fn serialize_u64(self, v: u64) -> Result { ValueSerializer::new().serialize_u64(v) } fn serialize_f32(self, v: f32) -> Result { ValueSerializer::new().serialize_f32(v) } fn serialize_f64(self, v: f64) -> Result { ValueSerializer::new().serialize_f64(v) } fn serialize_char(self, v: char) -> Result { ValueSerializer::new().serialize_char(v) } fn serialize_str(self, v: &str) -> Result { ValueSerializer::new().serialize_str(v) } fn serialize_bytes(self, value: &[u8]) -> Result { ValueSerializer::new().serialize_bytes(value) } fn serialize_none(self) -> Result { *self.is_none = true; Err(Error::unsupported_none()) } fn serialize_some(self, value: &T) -> Result where T: serde_core::ser::Serialize + ?Sized, { ValueSerializer::new().serialize_some(value) } fn serialize_unit(self) -> Result { ValueSerializer::new().serialize_unit() } fn serialize_unit_struct(self, name: &'static str) -> Result { ValueSerializer::new().serialize_unit_struct(name) } fn serialize_unit_variant( self, name: &'static str, variant_index: u32, variant: &'static str, ) -> Result { ValueSerializer::new().serialize_unit_variant(name, variant_index, variant) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result where T: serde_core::ser::Serialize + ?Sized, { value.serialize(self) } fn serialize_newtype_variant( self, name: &'static str, variant_index: u32, variant: &'static str, value: &T, ) -> Result where T: serde_core::ser::Serialize + ?Sized, { ValueSerializer::new().serialize_newtype_variant(name, variant_index, variant, value) } fn serialize_seq(self, len: Option) -> Result { ValueSerializer::new().serialize_seq(len) } fn serialize_tuple(self, len: usize) -> Result { ValueSerializer::new().serialize_tuple(len) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { ValueSerializer::new().serialize_tuple_struct(name, len) } fn serialize_tuple_variant( self, name: &'static str, variant_index: u32, variant: &'static str, len: usize, ) -> Result { ValueSerializer::new().serialize_tuple_variant(name, variant_index, variant, len) } fn serialize_map(self, len: Option) -> Result { ValueSerializer::new().serialize_map(len) } fn serialize_struct( self, name: &'static str, len: usize, ) -> Result { ValueSerializer::new().serialize_struct(name, len) } fn serialize_struct_variant( self, name: &'static str, variant_index: u32, variant: &'static str, len: usize, ) -> Result { ValueSerializer::new().serialize_struct_variant(name, variant_index, variant, len) } } pub struct SerializeStructVariant { variant: &'static str, inner: SerializeInlineTable, } impl SerializeStructVariant { pub(crate) fn struct_(variant: &'static str, len: usize) -> Self { Self { variant, inner: SerializeInlineTable::map(Some(len)), } } } impl serde_core::ser::SerializeStructVariant for SerializeStructVariant { type Ok = crate::Value; type Error = Error; #[inline] fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: serde_core::ser::Serialize + ?Sized, { serde_core::ser::SerializeStruct::serialize_field(&mut self.inner, key, value) } #[inline] fn end(self) -> Result { let inner = serde_core::ser::SerializeStruct::end(self.inner)?.into(); let mut items = crate::table::KeyValuePairs::new(); let value = crate::Item::Value(inner); items.insert(crate::Key::new(self.variant), value); Ok(crate::Value::InlineTable(crate::InlineTable::with_pairs( items, ))) } } toml_edit-0.24.0+spec-1.1.0/src/ser/mod.rs000064400000000000000000000056211046102023000157610ustar 00000000000000//! Serializing Rust structures into TOML. //! //! This module contains all the Serde support for serializing Rust structures into TOML. mod array; mod error; mod key; mod map; mod pretty; mod value; use crate::visit_mut::VisitMut as _; #[allow(clippy::wildcard_imports)] use array::*; #[allow(clippy::wildcard_imports)] use map::*; pub use error::Error; pub use value::ValueSerializer; /// Serialize the given data structure as a TOML byte vector. /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to /// fail, if `T` contains a map with non-string keys, or if `T` attempts to /// serialize an unsupported datatype such as an enum, tuple, or tuple struct. #[cfg(feature = "display")] pub fn to_vec(value: &T) -> Result, Error> where T: serde_core::ser::Serialize + ?Sized, { to_string(value).map(|e| e.into_bytes()) } /// Serialize the given data structure as a String of TOML. /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to /// fail, if `T` contains a map with non-string keys, or if `T` attempts to /// serialize an unsupported datatype such as an enum, tuple, or tuple struct. /// /// # Examples /// /// ``` /// use serde::Serialize; /// /// #[derive(Serialize)] /// struct Config { /// database: Database, /// } /// /// #[derive(Serialize)] /// struct Database { /// ip: String, /// port: Vec, /// connection_max: u32, /// enabled: bool, /// } /// /// let config = Config { /// database: Database { /// ip: "192.168.1.1".to_string(), /// port: vec![8001, 8002, 8003], /// connection_max: 5000, /// enabled: false, /// }, /// }; /// /// let toml = toml_edit::ser::to_string(&config).unwrap(); /// println!("{}", toml) /// ``` #[cfg(feature = "display")] pub fn to_string(value: &T) -> Result where T: serde_core::ser::Serialize + ?Sized, { to_document(value).map(|e| e.to_string()) } /// Serialize the given data structure as a "pretty" String of TOML. /// /// This is identical to `to_string` except the output string has a more /// "pretty" output. See `ValueSerializer::pretty` for more details. #[cfg(feature = "display")] pub fn to_string_pretty(value: &T) -> Result where T: serde_core::ser::Serialize + ?Sized, { let mut document = to_document(value)?; pretty::Pretty::new().visit_document_mut(&mut document); Ok(document.to_string()) } /// Serialize the given data structure into a TOML document. /// /// This would allow custom formatting to be applied, mixing with format preserving edits, etc. pub fn to_document(value: &T) -> Result where T: serde_core::ser::Serialize + ?Sized, { let value = value.serialize(ValueSerializer::new())?; let item = crate::Item::Value(value); let root = item .into_table() .map_err(|_| Error::UnsupportedType(None))?; Ok(root.into()) } toml_edit-0.24.0+spec-1.1.0/src/ser/pretty.rs000064400000000000000000000030431046102023000165250ustar 00000000000000pub(crate) struct Pretty { in_value: bool, } impl Pretty { pub(crate) fn new() -> Self { Self { in_value: false } } } impl crate::visit_mut::VisitMut for Pretty { fn visit_document_mut(&mut self, node: &mut crate::DocumentMut) { crate::visit_mut::visit_document_mut(self, node); } fn visit_item_mut(&mut self, node: &mut crate::Item) { if !self.in_value { node.make_item(); } crate::visit_mut::visit_item_mut(self, node); } fn visit_table_mut(&mut self, node: &mut crate::Table) { node.decor_mut().clear(); // Empty tables could be semantically meaningful, so make sure they are not implicit if !node.is_empty() { node.set_implicit(true); } crate::visit_mut::visit_table_mut(self, node); } fn visit_value_mut(&mut self, node: &mut crate::Value) { node.decor_mut().clear(); let old_in_value = self.in_value; self.in_value = true; crate::visit_mut::visit_value_mut(self, node); self.in_value = old_in_value; } fn visit_array_mut(&mut self, node: &mut crate::Array) { crate::visit_mut::visit_array_mut(self, node); if (0..=1).contains(&node.len()) { node.set_trailing(""); node.set_trailing_comma(false); } else { for item in node.iter_mut() { item.decor_mut().set_prefix("\n "); } node.set_trailing("\n"); node.set_trailing_comma(true); } } } toml_edit-0.24.0+spec-1.1.0/src/ser/value.rs000064400000000000000000000156341046102023000163230ustar 00000000000000use super::Error; use super::SerializeMap; use super::SerializeStructVariant; use super::SerializeTupleVariant; use super::SerializeValueArray; /// Serialization for TOML [values][crate::Value]. /// /// This structure implements serialization support for TOML to serialize an /// arbitrary type to TOML. Note that the TOML format does not support all /// datatypes in Rust, such as enums, tuples, and tuple structs. These types /// will generate an error when serialized. /// /// Currently a serializer always writes its output to an in-memory `String`, /// which is passed in when creating the serializer itself. /// /// # Examples /// /// ``` /// # #[cfg(feature = "parse")] { /// # #[cfg(feature = "display")] { /// use serde::Serialize; /// /// #[derive(Serialize)] /// struct Config { /// database: Database, /// } /// /// #[derive(Serialize)] /// struct Database { /// ip: String, /// port: Vec, /// connection_max: u32, /// enabled: bool, /// } /// /// let config = Config { /// database: Database { /// ip: "192.168.1.1".to_string(), /// port: vec![8001, 8002, 8003], /// connection_max: 5000, /// enabled: false, /// }, /// }; /// /// let value = serde::Serialize::serialize( /// &config, /// toml_edit::ser::ValueSerializer::new() /// ).unwrap(); /// println!("{}", value) /// # } /// # } /// ``` #[derive(Default)] #[non_exhaustive] pub struct ValueSerializer {} impl ValueSerializer { /// Creates a new serializer generate a TOML document. pub fn new() -> Self { Self {} } } impl serde_core::ser::Serializer for ValueSerializer { type Ok = crate::Value; type Error = Error; type SerializeSeq = SerializeValueArray; type SerializeTuple = SerializeValueArray; type SerializeTupleStruct = SerializeValueArray; type SerializeTupleVariant = SerializeTupleVariant; type SerializeMap = SerializeMap; type SerializeStruct = SerializeMap; type SerializeStructVariant = SerializeStructVariant; fn serialize_bool(self, v: bool) -> Result { Ok(v.into()) } fn serialize_i8(self, v: i8) -> Result { self.serialize_i64(v as i64) } fn serialize_i16(self, v: i16) -> Result { self.serialize_i64(v as i64) } fn serialize_i32(self, v: i32) -> Result { self.serialize_i64(v as i64) } fn serialize_i64(self, v: i64) -> Result { Ok(v.into()) } fn serialize_u8(self, v: u8) -> Result { self.serialize_i64(v as i64) } fn serialize_u16(self, v: u16) -> Result { self.serialize_i64(v as i64) } fn serialize_u32(self, v: u32) -> Result { self.serialize_i64(v as i64) } fn serialize_u64(self, v: u64) -> Result { let v: i64 = v .try_into() .map_err(|_err| Error::out_of_range(Some("u64")))?; self.serialize_i64(v) } fn serialize_f32(self, v: f32) -> Result { self.serialize_f64(v as f64) } fn serialize_f64(self, mut v: f64) -> Result { // Discard sign of NaN when serialized using Serde. // // In all likelihood the sign of NaNs is not meaningful in the user's // program. Ending up with `-nan` in the TOML document would usually be // surprising and undesirable, when the sign of the NaN was not // intentionally controlled by the caller, or may even be // nondeterministic if it comes from arithmetic operations or a cast. if v.is_nan() { v = v.copysign(1.0); } Ok(v.into()) } fn serialize_char(self, v: char) -> Result { let mut buf = [0; 4]; self.serialize_str(v.encode_utf8(&mut buf)) } fn serialize_str(self, v: &str) -> Result { Ok(v.into()) } fn serialize_bytes(self, value: &[u8]) -> Result { use serde_core::ser::Serialize; value.serialize(self) } fn serialize_none(self) -> Result { Err(Error::unsupported_none()) } fn serialize_some(self, value: &T) -> Result where T: serde_core::ser::Serialize + ?Sized, { value.serialize(self) } fn serialize_unit(self) -> Result { Err(Error::unsupported_type(Some("unit"))) } fn serialize_unit_struct(self, name: &'static str) -> Result { Err(Error::unsupported_type(Some(name))) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result { self.serialize_str(variant) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result where T: serde_core::ser::Serialize + ?Sized, { value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result where T: serde_core::ser::Serialize + ?Sized, { let value = value.serialize(self)?; let mut table = crate::InlineTable::new(); table.insert(variant, value); Ok(table.into()) } fn serialize_seq(self, len: Option) -> Result { Ok(SerializeValueArray::seq(len)) } fn serialize_tuple(self, len: usize) -> Result { self.serialize_seq(Some(len)) } fn serialize_tuple_struct( self, _name: &'static str, len: usize, ) -> Result { self.serialize_seq(Some(len)) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { Ok(SerializeTupleVariant::tuple(variant, len)) } fn serialize_map(self, len: Option) -> Result { Ok(SerializeMap::map(len)) } fn serialize_struct( self, name: &'static str, len: usize, ) -> Result { Ok(SerializeMap::struct_(name, Some(len))) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { Ok(SerializeStructVariant::struct_(variant, len)) } } toml_edit-0.24.0+spec-1.1.0/src/table.rs000064400000000000000000000632441046102023000155050ustar 00000000000000use std::iter::FromIterator; use indexmap::map::IndexMap; use crate::key::Key; use crate::repr::Decor; use crate::value::DEFAULT_VALUE_DECOR; use crate::{InlineTable, Item, KeyMut, Value}; /// A TOML table, a top-level collection of key/[`Value`] pairs under a header and logical /// sub-tables #[derive(Clone, Debug, Default)] pub struct Table { // Comments/spaces before and after the header pub(crate) decor: Decor, // Whether to hide an empty table pub(crate) implicit: bool, // Whether this is a proxy for dotted keys pub(crate) dotted: bool, // Used for putting tables back in their original order when serialising. // // `None` for user created tables (can be overridden with `set_position`) doc_position: Option, pub(crate) span: Option>, pub(crate) items: KeyValuePairs, } /// Constructors /// /// See also `FromIterator` impl Table { /// Creates an empty table. pub fn new() -> Self { Default::default() } pub(crate) fn with_pos(doc_position: Option) -> Self { Self { doc_position, ..Default::default() } } pub(crate) fn with_pairs(items: KeyValuePairs) -> Self { Self { items, ..Default::default() } } /// Convert to an inline table pub fn into_inline_table(mut self) -> InlineTable { for (_, value) in self.items.iter_mut() { value.make_value(); } let mut t = InlineTable::with_pairs(self.items); t.fmt(); t } } /// Formatting impl Table { /// 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 } 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::Table(table) if table.is_dotted() => { table.append_values(&path, values); } Item::Value(value) => { if let Some(table) = value.as_inline_table() { if table.is_dotted() { table.append_values(&path, values); } else { values.push((path, value)); } } else { values.push((path, value)); } } _ => {} } } } pub(crate) fn append_all_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::Table(table) => { table.append_all_values(&path, values); } Item::Value(value) => { if let Some(table) = value.as_inline_table() { if table.is_dotted() { table.append_values(&path, values); } else { values.push((path, value)); } } else { values.push((path, value)); } } _ => {} } } } /// Auto formats the table. pub fn fmt(&mut self) { decorate_table(self); } /// Sorts [Key]/[Value]-pairs of the table /// ///
/// /// This sorts the syntactic table (everything under the `[header]`) and not the logical map of /// key-value pairs. /// This does not affect the order of [sub-tables][Table] or [sub-arrays][crate::ArrayOfTables]. /// This is not recursive. /// ///
pub fn sort_values(&mut self) { // Assuming standard tables have their doc_position set and this won't negatively impact them self.items.sort_keys(); for value in self.items.values_mut() { match value { Item::Table(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). /// ///
/// /// This sorts the syntactic table (everything under the `[header]`) and not the logical map of /// key-value pairs. /// This does not affect the order of [sub-tables][Table] or [sub-arrays][crate::ArrayOfTables]. /// This is not recursive. /// ///
pub fn sort_values_by(&mut self, mut compare: F) where F: FnMut(&Key, &Item, &Key, &Item) -> std::cmp::Ordering, { self.sort_values_by_internal(&mut compare); } fn sort_values_by_internal(&mut self, compare: &mut F) where F: FnMut(&Key, &Item, &Key, &Item) -> std::cmp::Ordering, { let modified_cmp = |key1: &Key, val1: &Item, key2: &Key, val2: &Item| -> std::cmp::Ordering { compare(key1, val1, key2, val2) }; self.items.sort_by(modified_cmp); for value in self.items.values_mut() { match value { Item::Table(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 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 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 } /// Sets the position of the `Table` within the [`DocumentMut`][crate::DocumentMut]. /// /// Use `None` for having an unspecified location pub fn set_position(&mut self, doc_position: Option) { self.doc_position = doc_position; } /// The position of the `Table` within the [`DocumentMut`][crate::DocumentMut]. /// /// Returns `None` if the `Table` was created manually (i.e. not via parsing) /// in which case its position is set automatically. This can be overridden with /// [`Table::set_position`]. pub fn position(&self) -> Option { self.doc_position } /// Returns the surrounding whitespace pub fn decor_mut(&mut self) -> &mut Decor { &mut self.decor } /// Returns the decor associated with a given key of the table. 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()) } /// The location within the original document /// /// This generally requires a [`Document`][crate::Document]. 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); for (key, value) in self.items.iter_mut2() { key.despan(input); value.despan(input); } } } impl Table { /// Returns an iterator over all key/value pairs, including empty. pub fn iter(&self) -> Iter<'_> { Box::new( self.items .iter() .filter(|(_, value)| !value.is_none()) .map(|(key, value)| (key.get(), value)), ) } /// Returns an mutable iterator over all key/value pairs, including empty. pub fn iter_mut(&mut self) -> IterMut<'_> { use indexmap::map::MutableKeys; Box::new( self.items .iter_mut2() .filter(|(_, value)| !value.is_none()) .map(|(key, value)| (key.as_mut(), value)), ) } /// Returns the number of non-empty items in the table. 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<'a>(&'a mut self, key: &str) -> Entry<'a> { // Accept a `&str` rather than an owned type to keep `String`, well, internal match self.items.entry(key.into()) { indexmap::map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { entry }), indexmap::map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { 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) -> Entry<'a> { // Accept a `&Key` to be consistent with `entry` match self.items.entry(key.clone()) { indexmap::map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { entry }), indexmap::map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { entry }), } } /// Returns an optional reference to an item given the key. pub fn get<'a>(&'a self, key: &str) -> Option<&'a Item> { self.items .get(key) .and_then(|value| if !value.is_none() { Some(value) } else { None }) } /// Returns an optional mutable reference to an item given the key. pub fn get_mut<'a>(&'a mut self, key: &str) -> Option<&'a mut Item> { self.items .get_mut(key) .and_then(|value| if !value.is_none() { Some(value) } else { None }) } /// 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 an item with the given key. pub fn contains_key(&self, key: &str) -> bool { if let Some(value) = self.items.get(key) { !value.is_none() } else { false } } /// Returns true if the table contains a table with the given key. pub fn contains_table(&self, key: &str) -> bool { if let Some(value) = self.items.get(key) { value.is_table() } else { false } } /// Returns true if the table contains a value with the given key. pub fn contains_value(&self, key: &str) -> bool { if let Some(value) = self.items.get(key) { value.is_value() } else { false } } /// Returns true if the table contains an array of tables with the given key. pub fn contains_array_of_tables(&self, key: &str) -> bool { if let Some(value) = self.items.get(key) { value.is_array_of_tables() } else { false } } /// Inserts a key-value pair into the map. pub fn insert(&mut self, key: &str, item: Item) -> Option { use indexmap::map::MutableEntryKey; let key = Key::new(key); match self.items.entry(key.clone()) { indexmap::map::Entry::Occupied(mut entry) => { entry.key_mut().fmt(); let old = std::mem::replace(entry.get_mut(), item); Some(old) } indexmap::map::Entry::Vacant(entry) => { entry.insert(item); None } } } /// Inserts a key-value pair into the map. pub fn insert_formatted(&mut self, key: &Key, item: Item) -> Option { use indexmap::map::MutableEntryKey; 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(), item); Some(old) } indexmap::map::Entry::Vacant(entry) => { entry.insert(item); None } } } /// Removes an item given the key. pub fn remove(&mut self, key: &str) -> Option { self.items.shift_remove(key) } /// 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, Item)> { self.items.shift_remove_entry(key) } /// Retains only the elements specified by the `keep` predicate. /// /// In other words, remove all pairs `(key, item)` for which /// `keep(&key, &mut item)` returns `false`. /// /// The elements are visited in iteration order. pub fn retain(&mut self, mut keep: F) where F: FnMut(&str, &mut Item) -> bool, { self.items.retain(|key, value| keep(key, value)); } } #[cfg(feature = "display")] impl std::fmt::Display for Table { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let children = self.get_values(); // print table body for (key_path, value) in children { crate::encode::encode_key_path_ref(&key_path, f, None, DEFAULT_KEY_DECOR)?; write!(f, "=")?; crate::encode::encode_value(value, f, None, DEFAULT_VALUE_DECOR)?; writeln!(f)?; } Ok(()) } } impl, V: Into> Extend<(K, V)> for Table { fn extend>(&mut self, iter: T) { for (key, value) in iter { let key = key.into(); let value = value.into(); self.items.insert(key, value); } } } impl, V: Into> FromIterator<(K, V)> for Table { fn from_iter(iter: I) -> Self where I: IntoIterator, { let mut table = Self::new(); table.extend(iter); table } } impl IntoIterator for Table { type Item = (String, Item); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { Box::new(self.items.into_iter().map(|(k, value)| (k.into(), value))) } } impl<'s> IntoIterator for &'s Table { type Item = (&'s str, &'s Item); type IntoIter = Iter<'s>; fn into_iter(self) -> Self::IntoIter { self.iter() } } pub(crate) type KeyValuePairs = IndexMap; fn decorate_table(table: &mut Table) { 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(); } } // `key1 = value1` pub(crate) const DEFAULT_ROOT_DECOR: (&str, &str) = ("", ""); pub(crate) const DEFAULT_KEY_DECOR: (&str, &str) = ("", " "); pub(crate) const DEFAULT_TABLE_DECOR: (&str, &str) = ("\n", ""); pub(crate) const DEFAULT_KEY_PATH_DECOR: (&str, &str) = ("", ""); /// An owned iterator type over [`Table`]'s [`Key`]/[`Item`] pairs pub type IntoIter = Box>; /// An iterator type over [`Table`]'s [`Key`]/[`Item`] pairs pub type Iter<'a> = Box + 'a>; /// A mutable iterator type over [`Table`]'s [`Key`]/[`Item`] pairs pub type IterMut<'a> = Box, &'a mut Item)> + 'a>; /// This trait represents either a `Table`, or an `InlineTable`. pub trait TableLike: crate::private::Sealed { /// Returns an iterator over key/value pairs. fn iter(&self) -> Iter<'_>; /// Returns an mutable iterator over all key/value pairs, including empty. fn iter_mut(&mut self) -> IterMut<'_>; /// Returns the number of nonempty items. fn len(&self) -> usize { self.iter().filter(|&(_, v)| !v.is_none()).count() } /// Returns true if the table is empty. fn is_empty(&self) -> bool { self.len() == 0 } /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse. fn clear(&mut self); /// Gets the given key's corresponding entry in the Table for in-place manipulation. fn entry<'a>(&'a mut self, key: &str) -> Entry<'a>; /// Gets the given key's corresponding entry in the Table for in-place manipulation. fn entry_format<'a>(&'a mut self, key: &Key) -> Entry<'a>; /// Returns an optional reference to an item given the key. fn get<'s>(&'s self, key: &str) -> Option<&'s Item>; /// Returns an optional mutable reference to an item given the key. fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item>; /// Return references to the key-value pair stored for key, if it is present, else None. fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)>; /// Return mutable references to the key-value pair stored for key, if it is present, else None. fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)>; /// Returns true if the table contains an item with the given key. fn contains_key(&self, key: &str) -> bool; /// Inserts a key-value pair into the map. fn insert(&mut self, key: &str, value: Item) -> Option; /// Removes an item given the key. fn remove(&mut self, key: &str) -> Option; /// Get key/values for values that are visually children of this table /// /// For example, this will return dotted keys fn get_values(&self) -> Vec<(Vec<&Key>, &Value)>; /// Auto formats the table. fn fmt(&mut self); /// Sorts [Key]/[Value]-pairs of the table /// ///
/// /// This sorts the syntactic table (everything under the `[header]`) and not the logical map of /// key-value pairs. /// This does not affect the order of [sub-tables][Table] or [sub-arrays][crate::ArrayOfTables]. /// This is not recursive. /// ///
fn sort_values(&mut self); /// Change this table's dotted status fn set_dotted(&mut self, yes: bool); /// Check if this is a wrapper for dotted keys, rather than a standard table fn is_dotted(&self) -> bool; /// Returns an accessor to a key's formatting fn key(&self, key: &str) -> Option<&'_ Key>; /// Returns an accessor to a key's formatting fn key_mut(&mut self, key: &str) -> Option>; } impl TableLike for Table { fn iter(&self) -> Iter<'_> { self.iter() } fn iter_mut(&mut self) -> IterMut<'_> { self.iter_mut() } fn clear(&mut self) { self.clear(); } fn entry<'a>(&'a mut self, key: &str) -> Entry<'a> { self.entry(key) } fn entry_format<'a>(&'a mut self, key: &Key) -> Entry<'a> { self.entry_format(key) } fn get<'s>(&'s self, key: &str) -> Option<&'s Item> { self.get(key) } fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> { self.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) } fn remove(&mut self, key: &str) -> Option { self.remove(key) } 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 is_dotted(&self) -> bool { self.is_dotted() } fn set_dotted(&mut self, yes: bool) { self.set_dotted(yes); } fn key(&self, key: &str) -> Option<&'_ Key> { self.key(key) } fn key_mut(&mut self, key: &str) -> Option> { self.key_mut(key) } } /// A view into a single location in a [`Table`], which may be vacant or occupied. pub enum Entry<'a> { /// An occupied Entry. Occupied(OccupiedEntry<'a>), /// A vacant Entry. Vacant(VacantEntry<'a>), } impl<'a> Entry<'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 { Entry::Occupied(e) => e.key(), Entry::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: Item) -> &'a mut Item { match self { Entry::Occupied(entry) => entry.into_mut(), Entry::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 Item>(self, default: F) -> &'a mut Item { match self { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert(default()), } } } /// A view into a single occupied location in a [`Table`]. pub struct OccupiedEntry<'a> { pub(crate) entry: indexmap::map::OccupiedEntry<'a, Key, Item>, } impl<'a> OccupiedEntry<'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) -> &Item { self.entry.get() } /// Gets a mutable reference to the value in the entry. pub fn get_mut(&mut self) -> &mut Item { self.entry.get_mut() } /// 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 Item { self.entry.into_mut() } /// Sets the value of the entry, and returns the entry's old value pub fn insert(&mut self, value: Item) -> Item { self.entry.insert(value) } /// Takes the value out of the entry, and returns it pub fn remove(self) -> Item { self.entry.shift_remove() } } /// A view into a single empty location in a [`Table`]. pub struct VacantEntry<'a> { pub(crate) entry: indexmap::map::VacantEntry<'a, Key, Item>, } impl<'a> VacantEntry<'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: Item) -> &'a mut Item { let entry = self.entry; entry.insert(value) } } toml_edit-0.24.0+spec-1.1.0/src/value.rs000064400000000000000000000241121046102023000155210ustar 00000000000000use std::iter::FromIterator; use std::str::FromStr; use toml_datetime::{Date, Datetime, Time}; use crate::key::Key; use crate::repr::{Decor, Formatted}; use crate::{Array, InlineTable, RawString}; /// For [`Key`]/Value pairs under a [`Table`][crate::Table] header or inside another /// Value #[derive(Debug, Clone)] pub enum Value { /// A string value. String(Formatted), /// A 64-bit integer value. Integer(Formatted), /// A 64-bit float value. Float(Formatted), /// A boolean value. Boolean(Formatted), /// An RFC 3339 formatted date-time with offset. Datetime(Formatted), /// An inline array of values. Array(Array), /// An inline table of key/value pairs. InlineTable(InlineTable), } /// Downcasting impl Value { /// Text description of value type pub fn type_name(&self) -> &'static str { match self { Self::String(..) => "string", Self::Integer(..) => "integer", Self::Float(..) => "float", Self::Boolean(..) => "boolean", Self::Datetime(..) => "datetime", Self::Array(..) => "array", Self::InlineTable(..) => "inline table", } } /// Casts `self` to str. pub fn as_str(&self) -> Option<&str> { match *self { Self::String(ref value) => Some(value.value()), _ => None, } } /// Returns true if `self` is a string. pub fn is_str(&self) -> bool { self.as_str().is_some() } /// Casts `self` to integer. pub fn as_integer(&self) -> Option { match *self { Self::Integer(ref value) => Some(*value.value()), _ => None, } } /// 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 { match *self { Self::Float(ref value) => Some(*value.value()), _ => None, } } /// 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 { match *self { Self::Boolean(ref value) => Some(*value.value()), _ => None, } } /// Returns true if `self` is a boolean. pub fn is_bool(&self) -> bool { self.as_bool().is_some() } /// Casts `self` to date-time. pub fn as_datetime(&self) -> Option<&Datetime> { match *self { Self::Datetime(ref value) => Some(value.value()), _ => None, } } /// 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> { match *self { Self::Array(ref value) => Some(value), _ => None, } } /// Casts `self` to mutable array. pub fn as_array_mut(&mut self) -> Option<&mut Array> { match *self { Self::Array(ref mut value) => Some(value), _ => None, } } /// 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> { match *self { Self::InlineTable(ref value) => Some(value), _ => None, } } /// Casts `self` to mutable inline table. pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> { match *self { Self::InlineTable(ref mut value) => Some(value), _ => None, } } /// Returns true if `self` is an inline table. pub fn is_inline_table(&self) -> bool { self.as_inline_table().is_some() } } impl Value { /// Get the decoration of the value. /// # Example /// ```rust /// let v = toml_edit::Value::from(true); /// assert_eq!(v.decor().suffix(), None); ///``` pub fn decor_mut(&mut self) -> &mut Decor { match self { Self::String(f) => f.decor_mut(), Self::Integer(f) => f.decor_mut(), Self::Float(f) => f.decor_mut(), Self::Boolean(f) => f.decor_mut(), Self::Datetime(f) => f.decor_mut(), Self::Array(a) => a.decor_mut(), Self::InlineTable(t) => t.decor_mut(), } } /// Get the decoration of the value. /// # Example /// ```rust /// let v = toml_edit::Value::from(true); /// assert_eq!(v.decor().suffix(), None); ///``` pub fn decor(&self) -> &Decor { match *self { Self::String(ref f) => f.decor(), Self::Integer(ref f) => f.decor(), Self::Float(ref f) => f.decor(), Self::Boolean(ref f) => f.decor(), Self::Datetime(ref f) => f.decor(), Self::Array(ref a) => a.decor(), Self::InlineTable(ref t) => t.decor(), } } /// Sets the prefix and the suffix for value. /// # Example /// ```rust /// # #[cfg(feature = "display")] { /// let mut v = toml_edit::Value::from(42); /// assert_eq!(&v.to_string(), "42"); /// let d = v.decorated(" ", " "); /// assert_eq!(&d.to_string(), " 42 "); /// # } /// ``` pub fn decorated(mut self, prefix: impl Into, suffix: impl Into) -> Self { self.decorate(prefix, suffix); self } pub(crate) fn decorate(&mut self, prefix: impl Into, suffix: impl Into) { let decor = self.decor_mut(); *decor = Decor::new(prefix, suffix); } /// The location within the original document /// /// This generally requires a [`Document`][crate::Document]. pub fn span(&self) -> Option> { match self { Self::String(f) => f.span(), Self::Integer(f) => f.span(), Self::Float(f) => f.span(), Self::Boolean(f) => f.span(), Self::Datetime(f) => f.span(), Self::Array(a) => a.span(), Self::InlineTable(t) => t.span(), } } pub(crate) fn despan(&mut self, input: &str) { match self { Self::String(f) => f.despan(input), Self::Integer(f) => f.despan(input), Self::Float(f) => f.despan(input), Self::Boolean(f) => f.despan(input), Self::Datetime(f) => f.despan(input), Self::Array(a) => a.despan(input), Self::InlineTable(t) => t.despan(input), } } } #[cfg(feature = "parse")] impl FromStr for Value { type Err = crate::TomlError; /// Parses a value from a &str fn from_str(s: &str) -> Result { let source = toml_parser::Source::new(s); let mut sink = crate::error::TomlSink::>::new(source); let mut value = crate::parser::parse_value(source, &mut sink); if let Some(err) = sink.into_inner() { Err(err) } else { // Only take the repr and not decor, as its probably not intended value.decor_mut().clear(); value.despan(s); Ok(value) } } } impl<'b> From<&'b Self> for Value { fn from(s: &'b Self) -> Self { s.clone() } } impl<'b> From<&'b str> for Value { fn from(s: &'b str) -> Self { s.to_owned().into() } } impl<'b> From<&'b String> for Value { fn from(s: &'b String) -> Self { s.to_owned().into() } } impl From for Value { fn from(s: String) -> Self { Self::String(Formatted::new(s)) } } impl From for Value { fn from(i: i64) -> Self { Self::Integer(Formatted::new(i)) } } impl From for Value { fn from(f: f64) -> Self { // Preserve sign of NaN. It may get written to TOML as `-nan`. Self::Float(Formatted::new(f)) } } impl From for Value { fn from(b: bool) -> Self { Self::Boolean(Formatted::new(b)) } } impl From for Value { fn from(d: Datetime) -> Self { Self::Datetime(Formatted::new(d)) } } impl From for Value { fn from(d: Date) -> Self { let d: Datetime = d.into(); d.into() } } impl From