daft-derive-0.1.5/.cargo_vcs_info.json0000644000000001510000000000100132260ustar { "git": { "sha1": "5dc889ee3f1ec59b196b298cd30646da62c5914b" }, "path_in_vcs": "daft-derive" }daft-derive-0.1.5/Cargo.lock0000644000000406050000000000100112110ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[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.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", "windows-sys", ] [[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 = "camino" version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_derive" version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "clap_lex" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "console" version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", "libc", "once_cell", "unicode-width", "windows-sys", ] [[package]] name = "daft-derive" version = "0.1.5" dependencies = [ "datatest-stable", "expectorate", "prettyplease", "proc-macro2", "quote", "syn", "trybuild", "uuid", ] [[package]] name = "datatest-stable" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ebbb3c403031a3739980c2864e3b5ee4efca009dd83d2c0f80a31555243981" dependencies = [ "camino", "fancy-regex", "libtest-mimic", "walkdir", ] [[package]] name = "encode_unicode" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "escape8259" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" [[package]] name = "expectorate" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de6f19b25bdfa2747ae775f37cd109c31f1272d4e4c83095be0727840aa1d75f" dependencies = [ "console", "newline-converter", "similar", ] [[package]] name = "fancy-regex" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" dependencies = [ "bit-set", "regex-automata", "regex-syntax", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "glob" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" 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.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libtest-mimic" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5297962ef19edda4ce33aaa484386e0a5b3d7f2f4e037cbeee00503ef6b29d33" dependencies = [ "anstream", "anstyle", "clap", "escape8259", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "newline-converter" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f" dependencies = [ "unicode-segmentation", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "prettyplease" version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ "proc-macro2", "syn", ] [[package]] name = "proc-macro2" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "serde" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] [[package]] name = "similar" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "target-triple" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "toml" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "trybuild" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b812699e0c4f813b872b373a4471717d9eb550da14b311058a4d9cf4173cbca6" dependencies = [ "glob", "serde", "serde_derive", "serde_json", "target-triple", "termcolor", "toml", ] [[package]] name = "unicode-ident" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" [[package]] name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ "getrandom", ] [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e49d2d35d3fad69b39b94139037ecfb4f359f08958b9c11e7315ce770462419" dependencies = [ "memchr", ] daft-derive-0.1.5/Cargo.toml0000644000000040250000000000100112300ustar # 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.81.0" name = "daft-derive" version = "0.1.5" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Derive macro for daft" readme = "README.md" keywords = [ "diff", "difference", "semantic-diff", "structural-diff", ] categories = ["development-tools"] license = "MIT OR Apache-2.0" repository = "https://github.com/oxidecomputer/daft" [package.metadata.cargo-sync-rdme.badge.badges] crates-io = true docs-rs = true license = true rust-version = true [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "src/lib.rs" replace = '#![doc(html_root_url = "https://docs.rs/daft-derive/{{version}}")]' search = '^#!\[doc\(html_root_url = "https://docs.rs/daft-derive/.*"\)\]$' [lib] name = "daft_derive" path = "src/lib.rs" proc-macro = true [[test]] name = "integration_test" path = "tests/integration_test.rs" [[test]] name = "snapshot_test" path = "tests/snapshot_test.rs" harness = false [[test]] name = "ui_test" path = "tests/ui_test.rs" [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.syn] version = "2.0" features = [ "full", "visit", ] [dev-dependencies.datatest-stable] version = "0.3.2" [dev-dependencies.expectorate] version = "1.1.0" [dev-dependencies.prettyplease] version = "0.2.29" [dev-dependencies.trybuild] version = "1.0.103" [dev-dependencies.uuid] version = "1.12.0" features = ["v4"] [lints.rust.unexpected_cfgs] level = "warn" priority = 0 check-cfg = ["cfg(doc_cfg)"] daft-derive-0.1.5/Cargo.toml.orig000064400000000000000000000021371046102023000147130ustar 00000000000000[package] name = "daft-derive" version = "0.1.5" description = "Derive macro for daft" readme = "README.md" categories = ["development-tools"] keywords.workspace = true edition.workspace = true repository.workspace = true rust-version.workspace = true license.workspace = true [lints] workspace = true [lib] proc-macro = true [dependencies] proc-macro2.workspace = true quote.workspace = true syn = { workspace = true, features = ["full", "visit"] } [dev-dependencies] daft = { workspace = true, features = ["derive"] } datatest-stable.workspace = true expectorate.workspace = true prettyplease.workspace = true trybuild.workspace = true uuid = { workspace = true, features = ["v4"] } [[test]] name = "snapshot_test" harness = false [package.metadata.cargo-sync-rdme.badge.badges] license = true crates-io = true docs-rs = true rust-version = true [package.metadata.release] pre-release-replacements = [ { file = "src/lib.rs", search = "^#!\\[doc\\(html_root_url = \"https://docs.rs/daft-derive/.*\"\\)\\]$", replace = "#![doc(html_root_url = \"https://docs.rs/daft-derive/{{version}}\")]", exactly = 1 }, ] daft-derive-0.1.5/LICENSE-APACHE000064400000000000000000000251721046102023000137540ustar 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 (c) 2016 Alex Crichton Copyright (c) 2017 The Tokio Authors 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. daft-derive-0.1.5/LICENSE-MIT000064400000000000000000000020521046102023000134540ustar 00000000000000Copyright (c) 2025 Oxide Computer Company 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. daft-derive-0.1.5/README.md000064400000000000000000000016311046102023000133010ustar 00000000000000 # daft-derive ![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/daft-derive.svg?) [![crates.io](https://img.shields.io/crates/v/daft-derive.svg?logo=rust)](https://crates.io/crates/daft-derive) [![docs.rs](https://img.shields.io/docsrs/daft-derive.svg?logo=docs.rs)](https://docs.rs/daft-derive) [![Rust: ^1.81.0](https://img.shields.io/badge/rust-^1.81.0-93450a.svg?logo=rust)](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field) Derive macro for daft (internal crate). For more information about daft, see [its documentation](https://docs.rs/daft). ## License This project is available under the terms of either the [Apache 2.0 license](LICENSE-APACHE) or the [MIT license](LICENSE-MIT). daft-derive-0.1.5/src/internals/error_store.rs000064400000000000000000000114061046102023000175240ustar 00000000000000// Copyright 2025 Oxide Computer Company //! Handle lists of errors that occur while generating the proc macro. //! //! See the documentation of [`ErrorStore`] for more information. use std::cell::RefCell; /// Top-level struct that holds all errors encountered during the invocation of /// a proc macro. /// /// This allows for collecting errors from multiple sources, and for tracking /// errors in a hierarchical fashion. #[derive(Debug)] pub(crate) struct ErrorStore { data: RefCell>, } impl ErrorStore { /// Create a new `ErrorStore`. pub(crate) fn new() -> Self { Self { data: RefCell::new(ErrorStoreData::default()) } } /// Obtain the list of errors collected by this store. /// /// This consumes the store, and implies that there are no [`ErrorSink`] /// instances that are still alive. pub(crate) fn into_inner(self) -> Vec { std::mem::take(&mut self.data.borrow_mut().errors) } /// Create a new sink for collecting errors. /// /// This is a top-level sink, i.e. it has no parent. pub(crate) fn sink(&mut self) -> ErrorSink<'_, T> { let new_id = self.data.borrow_mut().register_sink(None); ErrorSink { data: &self.data, id: new_id } } } /// A collector for errors. /// /// An `ErrorSink` is a context into which errors can be pushed. It can have /// child `ErrorSink` instances, and the [`ErrorStore`] from which it is /// ultimately derived tracks whether any errors were pushed to a given /// `ErrorSink` or its descendants. /// /// The lifetime parameter `'a` is the lifetime of the `ErrorStore` that the /// `ErrorSink` is ultimately derived from. The parameter ensures that /// `ErrorSink` instances don't outlive the [`ErrorStore`] -- this means that at /// the time an [`ErrorStore`] is consumed, there aren't any outstanding /// `ErrorSink` instances. #[derive(Debug)] pub(crate) struct ErrorSink<'a, T> { // It's a bit weird to use both a lifetime parameter and a RefCell, but it // makes sense here. With `Rc>`, there's no way to statically // guarantee that the error collection process is done. The lifetime // parameter statically guarantees that. // // Do we need interior mutability? Because of our nested structure, the only // other alternatives are some kind of `&mut &mut &mut ... T`, or dynamic // dispatch. Both seem worse than just doing this. data: &'a RefCell>, id: usize, } impl<'a, T> ErrorSink<'a, T> { pub(crate) fn push_critical(&self, error: T) { // This is always okay because we only briefly borrow the RefCell at any // time. self.data.borrow_mut().push_critical(self.id, error); } pub(crate) fn push_warning(&self, error: T) { // This is always okay because we only briefly borrow the RefCell at any // time. self.data.borrow_mut().push_warning(error); } pub(crate) fn has_critical_errors(&self) -> bool { // ErrorStore::push_critical_error propagates `has_critical_errors` up the tree while // writing errors, so we can just check the current ID while reading // this information. self.data.borrow().sinks[self.id].has_critical_errors } pub(crate) fn new_child(&self) -> ErrorSink<'a, T> { let mut errors = self.data.borrow_mut(); let new_id = errors.register_sink(Some(self.id)); Self { data: self.data, id: new_id } } } #[derive(Debug)] struct ErrorStoreData { errors: Vec, sinks: Vec, } impl Default for ErrorStoreData { fn default() -> Self { Self { errors: Vec::new(), sinks: Vec::new() } } } impl ErrorStoreData { /// Critical errors block progress fn push_critical(&mut self, id: usize, error: T) { self.errors.push(error); self.sinks[id].has_critical_errors = true; // Propagate the fact that errors were encountered up the tree. let mut curr = id; while let Some(parent) = self.sinks[curr].parent { self.sinks[parent].has_critical_errors = true; curr = parent; } } /// Warning errors do not block progress fn push_warning(&mut self, error: T) { self.errors.push(error); } fn register_sink(&mut self, parent: Option) -> usize { // len is the next ID let id = self.sinks.len(); self.sinks.push(ErrorSinkData::new(parent)); id } } #[derive(Debug)] struct ErrorSinkData { // The parent ID in the map. parent: Option, // Whether an error was pushed via this specific context or a descendant. has_critical_errors: bool, } impl ErrorSinkData { fn new(parent: Option) -> Self { Self { parent, has_critical_errors: false } } } daft-derive-0.1.5/src/internals/imp.rs000064400000000000000000000623371046102023000157550ustar 00000000000000use super::error_store::{ErrorSink, ErrorStore}; use proc_macro2::{Span, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use syn::{ parse_quote, parse_quote_spanned, parse_str, spanned::Spanned, visit::Visit, Attribute, Data, DataStruct, DeriveInput, Expr, Field, Fields, GenericParam, Generics, Index, Lifetime, LifetimeParam, Path, Token, WhereClause, WherePredicate, }; pub struct DeriveDiffableOutput { pub out: Option, pub errors: Vec, } impl ToTokens for DeriveDiffableOutput { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.extend(self.out.clone()); tokens.extend(self.errors.iter().map(|error| error.to_compile_error())); } } pub fn derive_diffable(input: syn::DeriveInput) -> DeriveDiffableOutput { let mut error_store = ErrorStore::new(); match &input.data { Data::Enum(_) => { // Implement all Enums as `Leaf`s let out = make_leaf(&input, AttrPosition::Enum, error_store.sink()); DeriveDiffableOutput { out: Some(out), errors: error_store.into_inner(), } } Data::Struct(s) => { // This might be None if there are errors. let out = make_struct_impl(&input, s, error_store.sink()); DeriveDiffableOutput { out, errors: error_store.into_inner() } } Data::Union(_) => { // Implement all unions as `Leaf`s let out = make_leaf(&input, AttrPosition::Union, error_store.sink()); DeriveDiffableOutput { out: Some(out), errors: error_store.into_inner(), } } } } // TODO: allow the crate name to be passed in as a macro argument fn daft_crate() -> Path { parse_quote! { ::daft } } fn daft_lifetime() -> LifetimeParam { // Use an underscore to avoid clashing with a user-defined `'daft` lifetime. LifetimeParam::new(Lifetime::new("'__daft", Span::call_site())) } // We need to add our lifetime parameter 'daft and ensure any other parameters // live as long as `daft` fn add_lifetime_to_generics( input: &DeriveInput, daft_lt: &LifetimeParam, ) -> Generics { let mut new_generics = input.generics.clone(); new_generics .lifetimes_mut() .for_each(|lt| lt.bounds.push(daft_lt.lifetime.clone())); new_generics.type_params_mut().for_each(|lt| { lt.bounds.push(syn::TypeParamBound::Lifetime(daft_lt.lifetime.clone())) }); // Add the 'daft lifetime to the beginning of the parameter list -- the // exact order is not hugely important, but doing this makes tests simpler // (they can just check the first element). new_generics.params.insert(0, GenericParam::from(daft_lt.clone())); new_generics } // Implement `Diffable` as a `Leaf`. fn make_leaf( input: &DeriveInput, position: AttrPosition, errors: ErrorSink<'_, syn::Error>, ) -> TokenStream { // The input should not have any daft attributes. for attr in &input.attrs { if attr.path().is_ident("daft") { let res = attr.parse_nested_meta(|meta| { if meta.path.is_ident("leaf") { // Accept this for leaf structs, but not for anything else. if position == AttrPosition::LeafStruct { return Ok(()); } errors.push_critical(meta.error(format!( "this is unnecessary: the Diffable \ implementation {} is always a leaf", position.as_purpose_str(), ))); } else { errors.push_critical(meta.error(format!( "daft attributes are not allowed {}", position.as_locative_str(), ))); } Ok(()) }); if let Err(err) = res { errors.push_critical(err); } } } // Variants should not have any daft attributes. let mut v = BanDaftAttrsVisitor { position, errors: errors.new_child() }; v.visit_data(&input.data); // Even though errors might have occurred above, we *do* generate the // implementation. That allows rust-analyzer to still understand that the // `Diffable` impl exists. let ident = &input.ident; let daft_crate = daft_crate(); let daft_lt = daft_lifetime(); // The "where Self: #daft_lt" condition appears to be enough to satisfy // Rust's borrow checker, so we don't need to add further constraints via // `add_lifetime_to_generics`. let (impl_gen, ty_gen, where_clause) = &input.generics.split_for_impl(); quote! { impl #impl_gen #daft_crate::Diffable for #ident #ty_gen #where_clause { type Diff<#daft_lt> = #daft_crate::Leaf<&#daft_lt Self> where Self: #daft_lt; fn diff<#daft_lt>(&#daft_lt self, other: &#daft_lt Self) -> Self::Diff<#daft_lt> { #daft_crate::Leaf {before: self, after: other} } } } } struct BanDaftAttrsVisitor<'a> { position: AttrPosition, errors: ErrorSink<'a, syn::Error>, } impl Visit<'_> for BanDaftAttrsVisitor<'_> { fn visit_attribute(&mut self, attr: &Attribute) { if attr.path().is_ident("daft") { self.errors.push_critical(syn::Error::new_spanned( attr, format!( "daft attributes are not allowed {}", self.position.as_locative_str(), ), )); } } fn visit_variant(&mut self, v: &syn::Variant) { let old_position = self.position; self.position = self.position.visit_variant(); syn::visit::visit_variant(self, v); self.position = old_position; } fn visit_field(&mut self, f: &syn::Field) { let old_position = self.position; self.position = self.position.visit_field(); syn::visit::visit_field(self, f); self.position = old_position; } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum AttrPosition { // Catch-all in case something unexpected happens with the visitor. General, LeafStruct, LeafStructField, Enum, Variant, VariantField, Union, UnionField, } impl AttrPosition { fn visit_variant(self) -> Self { match self { Self::Enum => Self::Variant, Self::General | Self::LeafStruct | Self::LeafStructField | Self::Variant | Self::VariantField | Self::Union | Self::UnionField => Self::General, } } fn visit_field(self) -> Self { match self { Self::LeafStruct => Self::LeafStructField, Self::Variant => Self::VariantField, Self::Union => Self::UnionField, Self::General | Self::LeafStructField | Self::Enum | Self::VariantField | Self::UnionField => Self::General, } } // purpose = prepositional phrase to indicate what something applies to, // e.g. "the implementation for enums is always" fn as_purpose_str(self) -> &'static str { match self { Self::General => "for this type", Self::LeafStruct => "for structs annotated with #[daft(leaf)]", Self::LeafStructField => { "for fields on structs annotated with #[daft(leaf)]" } Self::Enum => "for enums", Self::Variant => "for enum variants", Self::VariantField => "for enum variant fields", Self::Union => "for unions", Self::UnionField => "for union fields", } } // "locative" = indicating location: "not allowed on enums", etc. fn as_locative_str(self) -> &'static str { match self { Self::General => "here", Self::LeafStruct => "on structs annotated with #[daft(leaf)]", Self::LeafStructField => { "on fields of structs annotated with #[daft(leaf)]" } Self::Enum => "on enums", Self::Variant => "on enum variants", Self::VariantField => "on enum variant fields", Self::Union => "on unions", Self::UnionField => "on union fields", } } } fn make_struct_impl( input: &DeriveInput, s: &DataStruct, errors: ErrorSink<'_, syn::Error>, ) -> Option { let Some(struct_config) = StructConfig::parse_from(&input.attrs, errors.new_child()) else { // An error occurred parsing the struct configuration -- don't generate // anything. return None; }; match struct_config.mode { StructMode::Default => make_diff_struct(input, s, errors.new_child()) .map(|(generated_struct, diff_fields)| { let diff_impl = make_diff_impl(input, &diff_fields); // Uncomment for some debugging // eprintln!("{generated_struct}"); // eprintln!("{diff_impl}"); quote! { #generated_struct #diff_impl } }), StructMode::Leaf => { Some(make_leaf(input, AttrPosition::LeafStruct, errors.new_child())) } } } /// Create the `Diff` struct fn make_diff_struct( input: &DeriveInput, s: &DataStruct, errors: ErrorSink<'_, syn::Error>, ) -> Option<(TokenStream, DiffFields)> { // The name of the original type let vis = &input.vis; // The name of the generated type let name = parse_str::(&format!("{}Diff", input.ident)).unwrap(); // Copy over the non-exhaustive attribute from the original struct. (Do we // need to copy over other attributes?) let non_exhaustive = input.attrs.iter().find(|attr| attr.path().is_ident("non_exhaustive")); let daft_lt = daft_lifetime(); // We are creating a new type, so use only generics with our new lifetime // and bounds. // // Most of the other generics users use `split_for_impl`, but that is geared // specifically for trait implementations, not type definitions. For type // definitions, we use the original `Generics`. // // The `ToTokens` implementation for `Generics` does not print the `where` // clause, so we also include that separately. let new_generics = add_lifetime_to_generics(input, &daft_lt); let where_clause = &new_generics.where_clause; let Some(diff_fields) = DiffFields::new(&s.fields, where_clause.as_ref(), errors.new_child()) else { // An error occurred parsing fields -- don't generate the diff struct. return None; }; // --- No more errors past this point --- let struct_def = match &s.fields { Fields::Named(_) => quote! { #non_exhaustive #vis struct #name #new_generics #where_clause #diff_fields }, Fields::Unnamed(_) => quote! { #non_exhaustive #vis struct #name #new_generics #diff_fields #where_clause; }, Fields::Unit => quote! { // This is kinda silly #non_exhaustive #vis struct #name #new_generics {} #where_clause }, }; // Generate PartialEq, Eq, and Debug implementations for the diff struct. We // can't rely on `#[derive] because we want to put bounds on the // Diffable::Diff types, not on the original types. let (impl_gen, ty_gen, _) = &new_generics.split_for_impl(); let debug_impl = { let where_clause = diff_fields.where_clause_with_trait_bound( &parse_quote! { ::core::fmt::Debug }, ); let members = diff_fields.fields.members(); let finish = if non_exhaustive.is_some() { quote! { .finish_non_exhaustive() } } else { quote! { .finish() } }; let debug_body = match &s.fields { Fields::Named(_) => { quote! { f.debug_struct(stringify!(#name)) #( .field(stringify!(#members), &self.#members) )* #finish } } Fields::Unnamed(_) => quote! { f.debug_tuple(stringify!(#name)) #( .field(&self.#members) )* #finish }, Fields::Unit => quote! { f.debug_struct(stringify!(#name)) #finish }, }; quote! { impl #impl_gen ::core::fmt::Debug for #name #ty_gen #where_clause { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { #debug_body } } } }; let partial_eq_impl = { let where_clause = diff_fields.where_clause_with_trait_bound( &parse_quote! { ::core::cmp::PartialEq }, ); let members = diff_fields.fields.members(); let partial_eq_body: Expr = parse_quote! { #(self.#members == other.#members) && * }; quote! { impl #impl_gen ::core::cmp::PartialEq for #name #ty_gen #where_clause { fn eq(&self, other: &Self) -> bool { #partial_eq_body } } } }; let eq_impl = { let where_clause = diff_fields .where_clause_with_trait_bound(&parse_quote! { ::core::cmp::Eq }); quote! { impl #impl_gen ::core::cmp::Eq for #name #ty_gen #where_clause {} } }; Some(( quote! { #struct_def #debug_impl #partial_eq_impl #eq_impl }, diff_fields, )) } /// Impl `Diffable` for the original struct fn make_diff_impl( input: &DeriveInput, diff_fields: &DiffFields, ) -> TokenStream { // The name of the original type let ident = &input.ident; // The name of the generated type let name = parse_str::(&format!("{}Diff", input.ident)).unwrap(); let diffs = generate_field_diffs(&diff_fields.fields, &diff_fields.field_configs); let daft_crate = daft_crate(); let daft_lt = daft_lifetime(); let new_generics = add_lifetime_to_generics(input, &daft_lt); let (impl_gen, ty_gen, _) = &input.generics.split_for_impl(); let (_, new_ty_gen, where_clause) = &new_generics.split_for_impl(); quote! { impl #impl_gen #daft_crate::Diffable for #ident #ty_gen #where_clause { type Diff<#daft_lt> = #name #new_ty_gen where Self: #daft_lt; fn diff<#daft_lt>(&#daft_lt self, other: &#daft_lt Self) -> #name #new_ty_gen { Self::Diff { #diffs } } } } } /// For a `Diff` struct generated by this derive macro, tracks the fields that /// will be put into that struct. /// /// This also tracks the `where` clause. /// /// The goal of this wrapper is to provide helpers to iterate over the fields /// and members. struct DiffFields { fields: Fields, // Configuration for each field -- a vector with the same length as `self.fields`. field_configs: Vec, // The base where clause for the diff struct. where_clause: WhereClause, } impl DiffFields { /// None means there was an error parsing a config. fn new( fields: &Fields, where_clause: Option<&WhereClause>, errors: ErrorSink<'_, syn::Error>, ) -> Option { let (fields, field_configs) = match fields { Fields::Named(fields) => { let (named, configs) = fields .named .iter() .filter_map(|field| { Self::diff_field(field, errors.new_child()) }) .unzip(); ( Fields::Named(syn::FieldsNamed { brace_token: fields.brace_token, named, }), configs, ) } Fields::Unnamed(fields) => { let (unnamed, configs) = fields .unnamed .iter() .filter_map(|field| { Self::diff_field(field, errors.new_child()) }) .unzip(); ( Fields::Unnamed(syn::FieldsUnnamed { paren_token: fields.paren_token, unnamed, }), configs, ) } Fields::Unit => (Fields::Unit, Vec::new()), }; // Initialize an empty where clause if none was provided. let where_clause = where_clause.cloned().unwrap_or_else(|| WhereClause { where_token: ::default(), predicates: Default::default(), }); if errors.has_critical_errors() { None } else { Some(Self { fields, field_configs, where_clause }) } } /// Return a field for a diff with the appropriate type. /// /// If the type is ignored, or if there's an error parsing configuration, /// return None. fn diff_field( f: &Field, errors: ErrorSink<'_, syn::Error>, ) -> Option<(Field, FieldConfig)> { let Some(config) = FieldConfig::parse_from(&f.attrs, errors.new_child()) else { // None means there's an error parsing a config -- return None here, // we'll emit errors at the top level. return None; }; if config.mode == FieldMode::Ignore { // Skip over this field if there's an ignore. return None; } // Always use the daft lifetime for the diff -- associations between the // daft lifetime and existing parameters (both lifetime and type // parameters) are created in `add_lifetime_to_generics`, e.g. `'a: // '__daft`, or `T: '__daft`. let lt = daft_lifetime(); let daft_crate = daft_crate(); let ty = &f.ty; let mut f = f.clone(); f.ty = if config.mode == FieldMode::Leaf { parse_quote_spanned! {f.span()=> #daft_crate::Leaf<&#lt #ty> } } else { parse_quote_spanned! {f.span()=> <#ty as #daft_crate::Diffable>::Diff<#lt> } }; // Drop all attributes for now. We may want to carry some over in the // future. f.attrs = vec![]; Some((f, config)) } /// Returns an iterator over field types. fn types(&self) -> impl Iterator { self.fields.iter().map(|f| &f.ty) } /// Returns an expanded where clause where the fields have had a trait bound /// applied to them. fn where_clause_with_trait_bound( &self, trait_bound: &syn::TraitBound, ) -> WhereClause { let predicates = self.types().map(|ty| -> WherePredicate { parse_quote_spanned! {ty.span()=> #ty: #trait_bound } }); let mut where_clause = self.where_clause.clone(); where_clause.predicates.extend(predicates); where_clause } } impl ToTokens for DiffFields { fn to_tokens(&self, tokens: &mut TokenStream) { self.fields.to_tokens(tokens); } } /// Generate a call to `diff` for each field of the original struct that isn't /// ignored. fn generate_field_diffs( fields: &Fields, // Should be the same length as `fields`. field_configs: &[FieldConfig], ) -> TokenStream { let daft_crate = daft_crate(); let field_diffs = fields.iter().zip(field_configs).enumerate().map(|(i, (f, config))| { let field_name = match &f.ident { Some(ident) => quote! { #ident }, None => { let ident: Index = i.into(); quote! { #ident } } }; if config.mode == FieldMode::Leaf { quote_spanned! {f.span()=> #field_name: #daft_crate::Leaf { before: &self.#field_name, after: &other.#field_name } } } else { quote_spanned! {f.span()=> #field_name: #daft_crate::Diffable::diff( &self.#field_name, &other.#field_name ) } } }); quote! { #(#field_diffs),* } } #[derive(Debug)] struct StructConfig { mode: StructMode, } impl StructConfig { fn parse_from( attrs: &[Attribute], errors: ErrorSink<'_, syn::Error>, ) -> Option { let mut mode = StructMode::Default; for attr in attrs { { if attr.path().is_ident("daft") { let res = attr.parse_nested_meta(|meta| { if meta.path.is_ident("leaf") { match mode { StructMode::Default => { mode = StructMode::Leaf; } StructMode::Leaf => { errors.push_warning(meta.error( "#[daft(leaf)] specified multiple times", )); } } } else { errors.push_critical(meta.error( "unknown attribute \ (supported attributes: leaf)", )); } Ok(()) }); if let Err(err) = res { errors.push_critical(err); } } } } if errors.has_critical_errors() { None } else { Some(Self { mode }) } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum StructMode { // The default mode: do a recursive diff for this struct. Default, // Use a `Leaf` for this struct. Leaf, } #[derive(Debug)] struct FieldConfig { mode: FieldMode, } impl FieldConfig { fn parse_from( attrs: &[Attribute], errors: ErrorSink<'_, syn::Error>, ) -> Option { let mut mode = FieldMode::Default; for attr in attrs { if attr.path().is_ident("daft") { let res = attr.parse_nested_meta(|meta| { if meta.path.is_ident("leaf") { // #[daft(leaf)] match mode { FieldMode::Default => { mode = FieldMode::Leaf; } FieldMode::Leaf => { errors.push_warning(meta.error( "#[daft(leaf)] specified multiple times", )); } _ => { errors.push_critical(meta.error( "#[daft(leaf)] conflicts with \ other attributes", )); } } } else if meta.path.is_ident("ignore") { // #[daft(ignore)] match mode { FieldMode::Default => { mode = FieldMode::Ignore; } FieldMode::Ignore => { errors.push_warning(meta.error( "#[daft(ignore)] specified multiple times", )); } _ => { errors.push_critical(meta.error( "#[daft(ignore)] conflicts with \ other attributes", )); } } } else { errors.push_critical(meta.error( "unknown attribute \ (supported attributes: leaf, ignore)", )); } Ok(()) }); // We don't return an error from our callback, but syn might. if let Err(err) = res { errors.push_critical(err); } } } if errors.has_critical_errors() { None } else { Some(Self { mode }) } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum FieldMode { // The default mode: do a recursive diff for this field. Default, // Use a `Leaf` for this field. Leaf, // Ignore this field. Ignore, } daft-derive-0.1.5/src/internals/mod.rs000064400000000000000000000002371046102023000157360ustar 00000000000000//! Internals for daft-derive. //! //! This is imported both by this crate's lib.rs and by tests/snapshot_test.rs. mod error_store; mod imp; pub use imp::*; daft-derive-0.1.5/src/lib.rs000064400000000000000000000014331046102023000137250ustar 00000000000000//! Derive macro for daft (internal crate). //! //! For more information about daft, see [its documentation](https://docs.rs/daft). // Setting html_root_url allows daft's readme to have links to daft-derive. This // line is updated by cargo-release. #![doc(html_root_url = "https://docs.rs/daft-derive/0.1.5")] mod internals; use quote::ToTokens; use syn::parse_macro_input; // NOTE: We do not define documentation here -- only in daft while re-exporting // these items. This is so that doctests that depend on daft work. #[proc_macro_derive(Diffable, attributes(daft))] pub fn derive_diffable( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let input = parse_macro_input!(input as syn::DeriveInput); internals::derive_diffable(input).into_token_stream().into() } daft-derive-0.1.5/tests/fixtures/README.md000064400000000000000000000013311046102023000163110ustar 00000000000000# daft-derive fixtures ## Valid fixtures These fixtures ensure that: * the macro's output is stable, via `snapshot_test.rs` * the macro's output compiles, via `ui_test.rs` Each file in `valid` is automatically picked up by the snapshot and UI tests. `snapshot_test.rs` tests all macro invocations annotated with `#[derive(Diffable)]`. ## Invalid fixtures These fixtures ensure that: * the macro's success output, if any, is stable, via `snapshot_test.rs`. * the macro's output fails with a good error message, via `ui_test.rs`. Each file in `invalid` is automatically picked up by the snapshot and UI tests. Like with valid fixtures, `snapshot_test.rs` tests all macro invocations annotated with `#[derive(Diffable)]`. daft-derive-0.1.5/tests/fixtures/invalid/enum-attributes.rs000064400000000000000000000010441046102023000221570ustar 00000000000000use daft::Diffable; #[derive(Diffable)] #[daft(leaf)] enum MyEnum { #[daft(leaf)] A(#[daft(ignore)] i32), #[daft(leaf)] B { #[daft(ignore)] data: usize, }, } #[derive(Diffable)] #[daft(ignore)] enum MyEnum2 { A(i32), } fn main() { // MyEnum/MyEnum2 and its Diffable impl should all exist. let before = MyEnum::A(0); let after = MyEnum::B { data: 1 }; let _diff = before.diff(&after); let before = MyEnum2::A(0); let after = MyEnum2::A(1); let _diff = before.diff(&after); } daft-derive-0.1.5/tests/fixtures/invalid/enum-attributes.stderr000064400000000000000000000017321046102023000230420ustar 00000000000000error: this is unnecessary: the Diffable implementation for enums is always a leaf --> tests/fixtures/invalid/enum-attributes.rs:4:8 | 4 | #[daft(leaf)] | ^^^^ error: daft attributes are not allowed on enum variants --> tests/fixtures/invalid/enum-attributes.rs:6:5 | 6 | #[daft(leaf)] | ^^^^^^^^^^^^^ error: daft attributes are not allowed on enum variant fields --> tests/fixtures/invalid/enum-attributes.rs:7:7 | 7 | A(#[daft(ignore)] i32), | ^^^^^^^^^^^^^^^ error: daft attributes are not allowed on enum variants --> tests/fixtures/invalid/enum-attributes.rs:8:5 | 8 | #[daft(leaf)] | ^^^^^^^^^^^^^ error: daft attributes are not allowed on enum variant fields --> tests/fixtures/invalid/enum-attributes.rs:10:9 | 10 | #[daft(ignore)] | ^^^^^^^^^^^^^^^ error: daft attributes are not allowed on enums --> tests/fixtures/invalid/enum-attributes.rs:16:8 | 16 | #[daft(ignore)] | ^^^^^^ daft-derive-0.1.5/tests/fixtures/invalid/field-attribute-with-value.rs000064400000000000000000000005421046102023000242000ustar 00000000000000use daft::Diffable; #[derive(Diffable)] struct MyStruct { // We accept just `leaf`, not `leaf = true`. #[daft(leaf = true)] a: i32, #[daft(ignore = "yes")] b: String, } fn main() { // MyStruct should still exist, even though the Diffable impl couldn't be // generated. let _ = MyStruct { a: 0, b: "foo".to_string() }; } daft-derive-0.1.5/tests/fixtures/invalid/field-attribute-with-value.stderr000064400000000000000000000004321046102023000250550ustar 00000000000000error: expected `,` --> tests/fixtures/invalid/field-attribute-with-value.rs:6:17 | 6 | #[daft(leaf = true)] | ^ error: expected `,` --> tests/fixtures/invalid/field-attribute-with-value.rs:8:19 | 8 | #[daft(ignore = "yes")] | ^ daft-derive-0.1.5/tests/fixtures/invalid/field-leaf-and-ignore.rs000064400000000000000000000005761046102023000230510ustar 00000000000000use daft::Diffable; #[derive(Diffable)] struct MyStruct { // Having both `leaf` and `ignore` should result in an error. #[daft(leaf, ignore)] a: i32, #[daft(ignore)] #[daft(leaf)] b: String, } fn main() { // MyStruct should still exist, even though the Diffable impl couldn't be // generated. let _ = MyStruct { a: 0, b: "foo".to_string() }; } daft-derive-0.1.5/tests/fixtures/invalid/field-leaf-and-ignore.stderr000064400000000000000000000005151046102023000237210ustar 00000000000000error: #[daft(ignore)] conflicts with other attributes --> tests/fixtures/invalid/field-leaf-and-ignore.rs:6:18 | 6 | #[daft(leaf, ignore)] | ^^^^^^ error: #[daft(leaf)] conflicts with other attributes --> tests/fixtures/invalid/field-leaf-and-ignore.rs:9:12 | 9 | #[daft(leaf)] | ^^^^ daft-derive-0.1.5/tests/fixtures/invalid/field-specified-multiple-times.rs000064400000000000000000000005261046102023000250170ustar 00000000000000use daft::Diffable; #[derive(Diffable)] struct MyStruct { #[daft(leaf, leaf, leaf)] a: i32, #[daft(ignore)] #[daft(ignore)] #[daft(ignore)] b: String, } fn main() { // MyStruct should still exist, even though the Diffable impl couldn't be // generated. let _ = MyStruct { a: 0, b: "foo".to_string() }; } daft-derive-0.1.5/tests/fixtures/invalid/field-specified-multiple-times.stderr000064400000000000000000000012651046102023000256770ustar 00000000000000error: #[daft(leaf)] specified multiple times --> tests/fixtures/invalid/field-specified-multiple-times.rs:5:18 | 5 | #[daft(leaf, leaf, leaf)] | ^^^^ error: #[daft(leaf)] specified multiple times --> tests/fixtures/invalid/field-specified-multiple-times.rs:5:24 | 5 | #[daft(leaf, leaf, leaf)] | ^^^^ error: #[daft(ignore)] specified multiple times --> tests/fixtures/invalid/field-specified-multiple-times.rs:8:12 | 8 | #[daft(ignore)] | ^^^^^^ error: #[daft(ignore)] specified multiple times --> tests/fixtures/invalid/field-specified-multiple-times.rs:9:12 | 9 | #[daft(ignore)] | ^^^^^^ daft-derive-0.1.5/tests/fixtures/invalid/field-unknown-attribute.rs000064400000000000000000000004361046102023000236140ustar 00000000000000use daft::Diffable; #[derive(Diffable)] struct MyStruct { #[daft(foo)] a: i32, #[daft(bar)] b: String, } fn main() { // MyStruct should still exist, even though the Diffable impl couldn't be // generated. let _ = MyStruct { a: 0, b: "foo".to_string() }; } daft-derive-0.1.5/tests/fixtures/invalid/field-unknown-attribute.stderr000064400000000000000000000005151046102023000244710ustar 00000000000000error: unknown attribute (supported attributes: leaf, ignore) --> tests/fixtures/invalid/field-unknown-attribute.rs:5:12 | 5 | #[daft(foo)] | ^^^ error: unknown attribute (supported attributes: leaf, ignore) --> tests/fixtures/invalid/field-unknown-attribute.rs:7:12 | 7 | #[daft(bar)] | ^^^ daft-derive-0.1.5/tests/fixtures/invalid/output/enum-attributes.output.rs000064400000000000000000000010731046102023000250600ustar 00000000000000impl ::daft::Diffable for MyEnum { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } impl ::daft::Diffable for MyEnum2 { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } daft-derive-0.1.5/tests/fixtures/invalid/output/field-attribute-with-value.output.rs000064400000000000000000000000001046102023000270640ustar 00000000000000daft-derive-0.1.5/tests/fixtures/invalid/output/field-leaf-and-ignore.output.rs000064400000000000000000000000001046102023000257260ustar 00000000000000daft-derive-0.1.5/tests/fixtures/invalid/output/field-specified-multiple-times.output.rs000064400000000000000000000017721046102023000277220ustar 00000000000000struct MyStructDiff<'__daft> { a: ::daft::Leaf<&'__daft i32>, } impl<'__daft> ::core::fmt::Debug for MyStructDiff<'__daft> where ::daft::Leaf<&'__daft i32>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(MyStructDiff)).field(stringify!(a), &self.a).finish() } } impl<'__daft> ::core::cmp::PartialEq for MyStructDiff<'__daft> where ::daft::Leaf<&'__daft i32>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.a == other.a } } impl<'__daft> ::core::cmp::Eq for MyStructDiff<'__daft> where ::daft::Leaf<&'__daft i32>: ::core::cmp::Eq, {} impl ::daft::Diffable for MyStruct { type Diff<'__daft> = MyStructDiff<'__daft> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> MyStructDiff<'__daft> { Self::Diff { a: ::daft::Leaf { before: &self.a, after: &other.a, }, } } } daft-derive-0.1.5/tests/fixtures/invalid/output/field-unknown-attribute.output.rs000064400000000000000000000000001046102023000264760ustar 00000000000000daft-derive-0.1.5/tests/fixtures/invalid/output/struct-attribute-with-value.output.rs000064400000000000000000000000001046102023000273250ustar 00000000000000daft-derive-0.1.5/tests/fixtures/invalid/output/struct-field-not-diffable.output.rs000064400000000000000000000026511046102023000266700ustar 00000000000000struct MyStructDiff<'__daft> { a: ::Diff<'__daft>, b: ::Diff<'__daft>, } impl<'__daft> ::core::fmt::Debug for MyStructDiff<'__daft> where ::Diff<'__daft>: ::core::fmt::Debug, ::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(MyStructDiff)) .field(stringify!(a), &self.a) .field(stringify!(b), &self.b) .finish() } } impl<'__daft> ::core::cmp::PartialEq for MyStructDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::PartialEq, ::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.a == other.a && self.b == other.b } } impl<'__daft> ::core::cmp::Eq for MyStructDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::Eq, ::Diff<'__daft>: ::core::cmp::Eq, {} impl ::daft::Diffable for MyStruct { type Diff<'__daft> = MyStructDiff<'__daft> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> MyStructDiff<'__daft> { Self::Diff { a: ::daft::Diffable::diff(&self.a, &other.a), b: ::daft::Diffable::diff(&self.b, &other.b), } } } daft-derive-0.1.5/tests/fixtures/invalid/output/struct-leaf-attributes.output.rs000064400000000000000000000004371046102023000263500ustar 00000000000000impl ::daft::Diffable for MyStruct { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } daft-derive-0.1.5/tests/fixtures/invalid/output/struct-specified-multiple-times.output.rs000064400000000000000000000010771046102023000301610ustar 00000000000000impl ::daft::Diffable for MyStruct { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } impl ::daft::Diffable for MyStruct2 { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } daft-derive-0.1.5/tests/fixtures/invalid/output/struct-unknown-attribute-multiple.output.rs000064400000000000000000000000001046102023000305700ustar 00000000000000daft-derive-0.1.5/tests/fixtures/invalid/output/struct-unknown-attribute.output.rs000064400000000000000000000000001046102023000267370ustar 00000000000000daft-derive-0.1.5/tests/fixtures/invalid/output/union-attributes.output.rs000064400000000000000000000010751046102023000252460ustar 00000000000000impl ::daft::Diffable for MyUnion { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } impl ::daft::Diffable for MyUnion2 { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } daft-derive-0.1.5/tests/fixtures/invalid/struct-attribute-with-value.rs000064400000000000000000000004211046102023000244350ustar 00000000000000use daft::Diffable; #[derive(Diffable)] #[daft(leaf = true)] struct MyStruct { a: i32, b: String, } fn main() { // MyStruct should still exist, even though the Diffable impl couldn't be // generated. let _ = MyStruct { a: 0, b: "foo".to_string() }; } daft-derive-0.1.5/tests/fixtures/invalid/struct-attribute-with-value.stderr000064400000000000000000000002031046102023000253120ustar 00000000000000error: expected `,` --> tests/fixtures/invalid/struct-attribute-with-value.rs:4:13 | 4 | #[daft(leaf = true)] | ^ daft-derive-0.1.5/tests/fixtures/invalid/struct-field-not-diffable.rs000064400000000000000000000004031046102023000237620ustar 00000000000000use daft::Diffable; struct NonDiffable {} #[derive(Diffable)] struct MyStruct { a: i32, b: NonDiffable, } fn main() { // MyStruct should still exist, even though the Diffable impl has errors. let _ = MyStruct { a: 0, b: NonDiffable {} }; } daft-derive-0.1.5/tests/fixtures/invalid/struct-field-not-diffable.stderr000064400000000000000000000063011046102023000246440ustar 00000000000000error[E0277]: the trait bound `NonDiffable: Diffable` is not satisfied --> tests/fixtures/invalid/struct-field-not-diffable.rs:8:5 | 8 | b: NonDiffable, | ^ the trait `Diffable` is not implemented for `NonDiffable` | = help: the following other types implement trait `Diffable`: &'a T () (A, B) (A, B, C) (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) (A, B, C, D, E, F, G) and $N others error[E0277]: the trait bound `NonDiffable: Diffable` is not satisfied --> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10 | 5 | #[derive(Diffable)] | ^^^^^^^^ the trait `Diffable` is not implemented for `NonDiffable` | = help: the following other types implement trait `Diffable`: &'a T () (A, B) (A, B, C) (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) (A, B, C, D, E, F, G) and $N others = note: this error originates in the derive macro `Diffable` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NonDiffable: Diffable` is not satisfied in `MyStructDiff<'__daft>` --> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10 | 5 | #[derive(Diffable)] | ^^^^^^^^ within `MyStructDiff<'__daft>`, the trait `Diffable` is not implemented for `NonDiffable` | = help: the following other types implement trait `Diffable`: &'a T () (A, B) (A, B, C) (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) (A, B, C, D, E, F, G) and $N others note: required because it appears within the type `MyStructDiff<'__daft>` --> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10 | 5 | #[derive(Diffable)] | ^^^^^^^^ note: required by a bound in `daft::Diffable::Diff` --> $WORKSPACE/daft/src/diffable.rs | | / type Diff<'daft> | | where | | Self: 'daft; | |____________________^ required by this bound in `Diffable::Diff` = note: this error originates in the derive macro `Diffable` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NonDiffable: Diffable` is not satisfied in `MyStructDiff<'__daft>` --> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10 | 5 | #[derive(Diffable)] | ^^^^^^^^ within `MyStructDiff<'__daft>`, the trait `Diffable` is not implemented for `NonDiffable` | = help: the following other types implement trait `Diffable`: &'a T () (A, B) (A, B, C) (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) (A, B, C, D, E, F, G) and $N others note: required because it appears within the type `MyStructDiff<'__daft>` --> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10 | 5 | #[derive(Diffable)] | ^^^^^^^^ = note: the return type of a function must have a statically known size = note: this error originates in the derive macro `Diffable` (in Nightly builds, run with -Z macro-backtrace for more info) daft-derive-0.1.5/tests/fixtures/invalid/struct-leaf-attributes.rs000064400000000000000000000005641046102023000234520ustar 00000000000000use daft::Diffable; #[derive(Diffable)] #[daft(leaf)] struct MyStruct { // Attributes on leaf-struct fields are banned. #[daft(ignore)] a: i32, #[daft(leaf)] b: i32, } fn main() { // MyStruct and its Diffable should exist. let before = MyStruct { a: 0, b: 0 }; let after = MyStruct { a: 0, b: 1 }; let _diff = before.diff(&after); } daft-derive-0.1.5/tests/fixtures/invalid/struct-leaf-attributes.stderr000064400000000000000000000006131046102023000243240ustar 00000000000000error: daft attributes are not allowed on fields of structs annotated with #[daft(leaf)] --> tests/fixtures/invalid/struct-leaf-attributes.rs:7:5 | 7 | #[daft(ignore)] | ^^^^^^^^^^^^^^^ error: daft attributes are not allowed on fields of structs annotated with #[daft(leaf)] --> tests/fixtures/invalid/struct-leaf-attributes.rs:9:5 | 9 | #[daft(leaf)] | ^^^^^^^^^^^^^ daft-derive-0.1.5/tests/fixtures/invalid/struct-specified-multiple-times.rs000064400000000000000000000007111046102023000252540ustar 00000000000000use daft::Diffable; #[derive(Diffable)] #[daft(leaf, leaf, leaf)] struct MyStruct { a: i32, b: String, } #[derive(Diffable)] #[daft(leaf)] #[daft(leaf)] #[daft(leaf)] struct MyStruct2 { a: i32, b: String, } fn main() { // MyStruct and MyStruct2 should still exist, even though the Diffable impl // couldn't be generated. let _ = MyStruct { a: 0, b: "foo".to_string() }; let _ = MyStruct2 { a: 0, b: "foo".to_string() }; } daft-derive-0.1.5/tests/fixtures/invalid/struct-specified-multiple-times.stderr000064400000000000000000000012251046102023000261340ustar 00000000000000error: #[daft(leaf)] specified multiple times --> tests/fixtures/invalid/struct-specified-multiple-times.rs:4:14 | 4 | #[daft(leaf, leaf, leaf)] | ^^^^ error: #[daft(leaf)] specified multiple times --> tests/fixtures/invalid/struct-specified-multiple-times.rs:4:20 | 4 | #[daft(leaf, leaf, leaf)] | ^^^^ error: #[daft(leaf)] specified multiple times --> tests/fixtures/invalid/struct-specified-multiple-times.rs:12:8 | 12 | #[daft(leaf)] | ^^^^ error: #[daft(leaf)] specified multiple times --> tests/fixtures/invalid/struct-specified-multiple-times.rs:13:8 | 13 | #[daft(leaf)] | ^^^^ daft-derive-0.1.5/tests/fixtures/invalid/struct-unknown-attribute-multiple.rs000064400000000000000000000004301046102023000257000ustar 00000000000000use daft::Diffable; #[derive(Diffable)] #[daft(ignore, leaf, leaf)] struct MyStruct { a: i32, b: String, } fn main() { // MyStruct should still exist, even though the Diffable impl couldn't be // generated. let _ = MyStruct { a: 0, b: "foo".to_string() }; } daft-derive-0.1.5/tests/fixtures/invalid/struct-unknown-attribute-multiple.stderr000064400000000000000000000005501046102023000265620ustar 00000000000000error: unknown attribute (supported attributes: leaf) --> tests/fixtures/invalid/struct-unknown-attribute-multiple.rs:4:8 | 4 | #[daft(ignore, leaf, leaf)] | ^^^^^^ error: #[daft(leaf)] specified multiple times --> tests/fixtures/invalid/struct-unknown-attribute-multiple.rs:4:22 | 4 | #[daft(ignore, leaf, leaf)] | ^^^^ daft-derive-0.1.5/tests/fixtures/invalid/struct-unknown-attribute.rs000064400000000000000000000004141046102023000240510ustar 00000000000000use daft::Diffable; #[derive(Diffable)] #[daft(ignore)] struct MyStruct { a: i32, b: String, } fn main() { // MyStruct should still exist, even though the Diffable impl couldn't be // generated. let _ = MyStruct { a: 0, b: "foo".to_string() }; } daft-derive-0.1.5/tests/fixtures/invalid/struct-unknown-attribute.stderr000064400000000000000000000002341046102023000247300ustar 00000000000000error: unknown attribute (supported attributes: leaf) --> tests/fixtures/invalid/struct-unknown-attribute.rs:4:8 | 4 | #[daft(ignore)] | ^^^^^^ daft-derive-0.1.5/tests/fixtures/invalid/union-attributes.rs000064400000000000000000000007751046102023000223550ustar 00000000000000use daft::Diffable; #[derive(Diffable)] #[daft(leaf)] union MyUnion { #[daft(leaf)] a: i32, #[daft(ignore)] b: u32, } #[derive(Diffable)] #[daft(ignore)] union MyUnion2 { a: i32, b: u32, } fn main() { // MyEnum/MyEnum2 and its Diffable impl should all exist. let before = MyUnion { a: 0 }; let after = MyUnion { b: 1 }; let _diff = before.diff(&after); let before = MyUnion2 { a: 0 }; let after = MyUnion2 { a: 1 }; let _diff = before.diff(&after); } daft-derive-0.1.5/tests/fixtures/invalid/union-attributes.stderr000064400000000000000000000011771046102023000232310ustar 00000000000000error: this is unnecessary: the Diffable implementation for unions is always a leaf --> tests/fixtures/invalid/union-attributes.rs:4:8 | 4 | #[daft(leaf)] | ^^^^ error: daft attributes are not allowed on union fields --> tests/fixtures/invalid/union-attributes.rs:6:5 | 6 | #[daft(leaf)] | ^^^^^^^^^^^^^ error: daft attributes are not allowed on union fields --> tests/fixtures/invalid/union-attributes.rs:8:5 | 8 | #[daft(ignore)] | ^^^^^^^^^^^^^^^ error: daft attributes are not allowed on unions --> tests/fixtures/invalid/union-attributes.rs:13:8 | 13 | #[daft(ignore)] | ^^^^^^ daft-derive-0.1.5/tests/fixtures/valid/attributes.rs000064400000000000000000000006451046102023000206740ustar 00000000000000use daft::Diffable; use std::collections::{BTreeMap, BTreeSet}; use uuid::Uuid; #[derive(Debug, Eq, PartialEq, Diffable)] struct WithAttrs { a: i32, b: BTreeMap>, #[daft(ignore)] c: std::time::Instant, #[daft(leaf)] d: Lazy, #[daft(leaf)] e: usize, f: usize, } #[derive(Debug, Eq, PartialEq, Diffable)] struct Lazy { x: usize, y: usize, } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/basic.rs000064400000000000000000000003161046102023000175620ustar 00000000000000use daft::Diffable; use std::collections::{BTreeMap, BTreeSet}; use uuid::Uuid; #[derive(Debug, Eq, PartialEq, Diffable)] struct Basic { a: i32, b: BTreeMap>, } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/complex-lifetimes.rs000064400000000000000000000010631046102023000221270ustar 00000000000000use daft::Diffable; use std::{cell::Cell, fmt::Debug, marker::PhantomData}; #[derive(Debug, Eq, PartialEq, Diffable)] // 'daft is named as such to test potential clashes with generated code. struct S<'a, 'b, 'daft: 'a, 'inv, 'contra> { // Multiple lifetime params. multi_ref: &'a &'b Vec, // Lifetime param with a lifetime bound. bound_ref: &'daft Vec, // Invariant lifetime parameter. inv_ref: PhantomData>, // Contravariant lifetime parameter. contra_ref: PhantomData, } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/default-type-param.rs000064400000000000000000000002501046102023000221770ustar 00000000000000use daft::Diffable; use std::fmt::Debug; #[derive(Debug, Eq, PartialEq, Diffable)] struct StructWithDefaultTypeParam { field: T, } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/generic-enum.rs000064400000000000000000000002361046102023000210600ustar 00000000000000use daft::Diffable; use std::fmt::Debug; #[derive(Debug, Eq, PartialEq, Diffable)] enum EnumWithGenerics<'a, T, U> { A(T), B(&'a U), } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/generic-struct-2.rs000064400000000000000000000004021046102023000215720ustar 00000000000000use daft::Diffable; use std::collections::BTreeMap; #[derive(Debug, Eq, PartialEq, Diffable)] struct S<'a, T, U> where T: Diffable + Eq + 'a, U: Diffable + 'a, { a: BTreeMap, b: usize, c: &'a U, d: &'a str, } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/generic-struct-leaf.rs000064400000000000000000000004461046102023000223500ustar 00000000000000use daft::Diffable; #[derive(Debug, Eq, PartialEq, Diffable)] #[daft(leaf)] struct StructWithGenerics<'d, 'e, T, U> where // daft(leaf) on the struct means Diffable shouldn't be necessary. T: 'd + ?Sized, U: 'e + ?Sized, { b: usize, c: &'d T, d: &'e U, } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/generic-struct.rs000064400000000000000000000004331046102023000214370ustar 00000000000000// Check that no-std works. #![no_std] use daft::Diffable; #[derive(Debug, Eq, PartialEq, Diffable)] struct StructWithGenerics<'d, 'e, T, U> where T: daft::Diffable + 'd + ?Sized, U: daft::Diffable + 'e + ?Sized, { b: usize, c: &'d T, d: &'e U, } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/non-eq.rs000064400000000000000000000010571046102023000177010ustar 00000000000000use daft::{Diffable, Leaf}; #[derive(Diffable)] struct Inner { a: i32, b: i32, } #[derive(Diffable)] struct Outer { inner: Inner, c: i32, } fn main() { // Ensure that diffing works even though the structs don't implement Eq. let a = Outer { inner: Inner { a: 1, b: 2 }, c: 3 }; let b = Outer { inner: Inner { a: 4, b: 5 }, c: 6 }; let diff = a.diff(&b); assert_eq!( diff.inner, InnerDiff { a: Leaf { before: &1, after: &4 }, b: Leaf { before: &2, after: &5 }, } ); } daft-derive-0.1.5/tests/fixtures/valid/non-exhaustive.rs000064400000000000000000000004051046102023000214550ustar 00000000000000use daft::Diffable; #[non_exhaustive] #[derive(Diffable)] struct NonExhaustive { pub a: i32, pub b: i32, } #[non_exhaustive] #[derive(Diffable)] enum NonExhaustiveEnum { A(i32), #[non_exhaustive] B { b: i32, }, } fn main() {} daft-derive-0.1.5/tests/fixtures/valid/output/attributes.output.rs000064400000000000000000000100571046102023000235710ustar 00000000000000struct WithAttrsDiff<'__daft> { a: ::Diff<'__daft>, b: > as ::daft::Diffable>::Diff<'__daft>, d: ::daft::Leaf<&'__daft Lazy>, e: ::daft::Leaf<&'__daft usize>, f: ::Diff<'__daft>, } impl<'__daft> ::core::fmt::Debug for WithAttrsDiff<'__daft> where ::Diff<'__daft>: ::core::fmt::Debug, , > as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, ::daft::Leaf<&'__daft Lazy>: ::core::fmt::Debug, ::daft::Leaf<&'__daft usize>: ::core::fmt::Debug, ::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(WithAttrsDiff)) .field(stringify!(a), &self.a) .field(stringify!(b), &self.b) .field(stringify!(d), &self.d) .field(stringify!(e), &self.e) .field(stringify!(f), &self.f) .finish() } } impl<'__daft> ::core::cmp::PartialEq for WithAttrsDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::PartialEq, , > as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, ::daft::Leaf<&'__daft Lazy>: ::core::cmp::PartialEq, ::daft::Leaf<&'__daft usize>: ::core::cmp::PartialEq, ::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.a == other.a && self.b == other.b && self.d == other.d && self.e == other.e && self.f == other.f } } impl<'__daft> ::core::cmp::Eq for WithAttrsDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::Eq, , > as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, ::daft::Leaf<&'__daft Lazy>: ::core::cmp::Eq, ::daft::Leaf<&'__daft usize>: ::core::cmp::Eq, ::Diff<'__daft>: ::core::cmp::Eq, {} impl ::daft::Diffable for WithAttrs { type Diff<'__daft> = WithAttrsDiff<'__daft> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> WithAttrsDiff<'__daft> { Self::Diff { a: ::daft::Diffable::diff(&self.a, &other.a), b: ::daft::Diffable::diff(&self.b, &other.b), d: ::daft::Leaf { before: &self.d, after: &other.d, }, e: ::daft::Leaf { before: &self.e, after: &other.e, }, f: ::daft::Diffable::diff(&self.f, &other.f), } } } struct LazyDiff<'__daft> { x: ::Diff<'__daft>, y: ::Diff<'__daft>, } impl<'__daft> ::core::fmt::Debug for LazyDiff<'__daft> where ::Diff<'__daft>: ::core::fmt::Debug, ::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(LazyDiff)) .field(stringify!(x), &self.x) .field(stringify!(y), &self.y) .finish() } } impl<'__daft> ::core::cmp::PartialEq for LazyDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::PartialEq, ::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.x == other.x && self.y == other.y } } impl<'__daft> ::core::cmp::Eq for LazyDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::Eq, ::Diff<'__daft>: ::core::cmp::Eq, {} impl ::daft::Diffable for Lazy { type Diff<'__daft> = LazyDiff<'__daft> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> LazyDiff<'__daft> { Self::Diff { x: ::daft::Diffable::diff(&self.x, &other.x), y: ::daft::Diffable::diff(&self.y, &other.y), } } } daft-derive-0.1.5/tests/fixtures/valid/output/basic.output.rs000064400000000000000000000030461046102023000224640ustar 00000000000000struct BasicDiff<'__daft> { a: ::Diff<'__daft>, b: > as ::daft::Diffable>::Diff<'__daft>, } impl<'__daft> ::core::fmt::Debug for BasicDiff<'__daft> where ::Diff<'__daft>: ::core::fmt::Debug, , > as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(BasicDiff)) .field(stringify!(a), &self.a) .field(stringify!(b), &self.b) .finish() } } impl<'__daft> ::core::cmp::PartialEq for BasicDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::PartialEq, , > as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.a == other.a && self.b == other.b } } impl<'__daft> ::core::cmp::Eq for BasicDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::Eq, , > as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, {} impl ::daft::Diffable for Basic { type Diff<'__daft> = BasicDiff<'__daft> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> BasicDiff<'__daft> { Self::Diff { a: ::daft::Diffable::diff(&self.a, &other.a), b: ::daft::Diffable::diff(&self.b, &other.b), } } } daft-derive-0.1.5/tests/fixtures/valid/output/complex-lifetimes.output.rs000064400000000000000000000064531046102023000250360ustar 00000000000000struct SDiff< '__daft, 'a: '__daft, 'b: '__daft, 'daft: 'a + '__daft, 'inv: '__daft, 'contra: '__daft, > { multi_ref: <&'a &'b Vec as ::daft::Diffable>::Diff<'__daft>, bound_ref: <&'daft Vec as ::daft::Diffable>::Diff<'__daft>, inv_ref: > as ::daft::Diffable>::Diff<'__daft>, contra_ref: as ::daft::Diffable>::Diff<'__daft>, } impl< '__daft, 'a: '__daft, 'b: '__daft, 'daft: 'a + '__daft, 'inv: '__daft, 'contra: '__daft, > ::core::fmt::Debug for SDiff<'__daft, 'a, 'b, 'daft, 'inv, 'contra> where <&'a &'b Vec as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, <&'daft Vec as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, > as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(SDiff)) .field(stringify!(multi_ref), &self.multi_ref) .field(stringify!(bound_ref), &self.bound_ref) .field(stringify!(inv_ref), &self.inv_ref) .field(stringify!(contra_ref), &self.contra_ref) .finish() } } impl< '__daft, 'a: '__daft, 'b: '__daft, 'daft: 'a + '__daft, 'inv: '__daft, 'contra: '__daft, > ::core::cmp::PartialEq for SDiff<'__daft, 'a, 'b, 'daft, 'inv, 'contra> where <&'a &'b Vec as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, <&'daft Vec as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, , > as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.multi_ref == other.multi_ref && self.bound_ref == other.bound_ref && self.inv_ref == other.inv_ref && self.contra_ref == other.contra_ref } } impl< '__daft, 'a: '__daft, 'b: '__daft, 'daft: 'a + '__daft, 'inv: '__daft, 'contra: '__daft, > ::core::cmp::Eq for SDiff<'__daft, 'a, 'b, 'daft, 'inv, 'contra> where <&'a &'b Vec as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, <&'daft Vec as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, > as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, {} impl<'a, 'b, 'daft: 'a, 'inv, 'contra> ::daft::Diffable for S<'a, 'b, 'daft, 'inv, 'contra> { type Diff<'__daft> = SDiff<'__daft, 'a, 'b, 'daft, 'inv, 'contra> where Self: '__daft; fn diff<'__daft>( &'__daft self, other: &'__daft Self, ) -> SDiff<'__daft, 'a, 'b, 'daft, 'inv, 'contra> { Self::Diff { multi_ref: ::daft::Diffable::diff(&self.multi_ref, &other.multi_ref), bound_ref: ::daft::Diffable::diff(&self.bound_ref, &other.bound_ref), inv_ref: ::daft::Diffable::diff(&self.inv_ref, &other.inv_ref), contra_ref: ::daft::Diffable::diff(&self.contra_ref, &other.contra_ref), } } } daft-derive-0.1.5/tests/fixtures/valid/output/default-type-param.output.rs000064400000000000000000000025261046102023000251060ustar 00000000000000struct StructWithDefaultTypeParamDiff<'__daft, T: Diffable + '__daft = ()> { field: ::Diff<'__daft>, } impl<'__daft, T: Diffable + '__daft> ::core::fmt::Debug for StructWithDefaultTypeParamDiff<'__daft, T> where ::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(StructWithDefaultTypeParamDiff)) .field(stringify!(field), &self.field) .finish() } } impl<'__daft, T: Diffable + '__daft> ::core::cmp::PartialEq for StructWithDefaultTypeParamDiff<'__daft, T> where ::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.field == other.field } } impl<'__daft, T: Diffable + '__daft> ::core::cmp::Eq for StructWithDefaultTypeParamDiff<'__daft, T> where ::Diff<'__daft>: ::core::cmp::Eq, {} impl ::daft::Diffable for StructWithDefaultTypeParam { type Diff<'__daft> = StructWithDefaultTypeParamDiff<'__daft, T> where Self: '__daft; fn diff<'__daft>( &'__daft self, other: &'__daft Self, ) -> StructWithDefaultTypeParamDiff<'__daft, T> { Self::Diff { field: ::daft::Diffable::diff(&self.field, &other.field), } } } daft-derive-0.1.5/tests/fixtures/valid/output/generic-enum.output.rs000064400000000000000000000004731046102023000237620ustar 00000000000000impl<'a, T, U> ::daft::Diffable for EnumWithGenerics<'a, T, U> { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } daft-derive-0.1.5/tests/fixtures/valid/output/generic-struct-2.output.rs000064400000000000000000000051541046102023000245020ustar 00000000000000struct SDiff<'__daft, 'a: '__daft, T: '__daft, U: '__daft> where T: Diffable + Eq + 'a, U: Diffable + 'a, { a: as ::daft::Diffable>::Diff<'__daft>, b: ::Diff<'__daft>, c: <&'a U as ::daft::Diffable>::Diff<'__daft>, d: <&'a str as ::daft::Diffable>::Diff<'__daft>, } impl<'__daft, 'a: '__daft, T: '__daft, U: '__daft> ::core::fmt::Debug for SDiff<'__daft, 'a, T, U> where T: Diffable + Eq + 'a, U: Diffable + 'a, as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, ::Diff<'__daft>: ::core::fmt::Debug, <&'a U as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, <&'a str as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(SDiff)) .field(stringify!(a), &self.a) .field(stringify!(b), &self.b) .field(stringify!(c), &self.c) .field(stringify!(d), &self.d) .finish() } } impl<'__daft, 'a: '__daft, T: '__daft, U: '__daft> ::core::cmp::PartialEq for SDiff<'__daft, 'a, T, U> where T: Diffable + Eq + 'a, U: Diffable + 'a, as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, ::Diff<'__daft>: ::core::cmp::PartialEq, <&'a U as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, <&'a str as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d } } impl<'__daft, 'a: '__daft, T: '__daft, U: '__daft> ::core::cmp::Eq for SDiff<'__daft, 'a, T, U> where T: Diffable + Eq + 'a, U: Diffable + 'a, as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, ::Diff<'__daft>: ::core::cmp::Eq, <&'a U as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, <&'a str as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, {} impl<'a, T, U> ::daft::Diffable for S<'a, T, U> where T: Diffable + Eq + 'a, U: Diffable + 'a, { type Diff<'__daft> = SDiff<'__daft, 'a, T, U> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> SDiff<'__daft, 'a, T, U> { Self::Diff { a: ::daft::Diffable::diff(&self.a, &other.a), b: ::daft::Diffable::diff(&self.b, &other.b), c: ::daft::Diffable::diff(&self.c, &other.c), d: ::daft::Diffable::diff(&self.d, &other.d), } } } daft-derive-0.1.5/tests/fixtures/valid/output/generic-struct-leaf.output.rs000064400000000000000000000005631046102023000252470ustar 00000000000000impl<'d, 'e, T, U> ::daft::Diffable for StructWithGenerics<'d, 'e, T, U> where T: 'd + ?Sized, U: 'e + ?Sized, { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } daft-derive-0.1.5/tests/fixtures/valid/output/generic-struct.output.rs000064400000000000000000000050561046102023000243440ustar 00000000000000struct StructWithGenericsDiff<'__daft, 'd: '__daft, 'e: '__daft, T: '__daft, U: '__daft> where T: daft::Diffable + 'd + ?Sized, U: daft::Diffable + 'e + ?Sized, { b: ::Diff<'__daft>, c: <&'d T as ::daft::Diffable>::Diff<'__daft>, d: <&'e U as ::daft::Diffable>::Diff<'__daft>, } impl<'__daft, 'd: '__daft, 'e: '__daft, T: '__daft, U: '__daft> ::core::fmt::Debug for StructWithGenericsDiff<'__daft, 'd, 'e, T, U> where T: daft::Diffable + 'd + ?Sized, U: daft::Diffable + 'e + ?Sized, ::Diff<'__daft>: ::core::fmt::Debug, <&'d T as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, <&'e U as ::daft::Diffable>::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(StructWithGenericsDiff)) .field(stringify!(b), &self.b) .field(stringify!(c), &self.c) .field(stringify!(d), &self.d) .finish() } } impl<'__daft, 'd: '__daft, 'e: '__daft, T: '__daft, U: '__daft> ::core::cmp::PartialEq for StructWithGenericsDiff<'__daft, 'd, 'e, T, U> where T: daft::Diffable + 'd + ?Sized, U: daft::Diffable + 'e + ?Sized, ::Diff<'__daft>: ::core::cmp::PartialEq, <&'d T as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, <&'e U as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.b == other.b && self.c == other.c && self.d == other.d } } impl<'__daft, 'd: '__daft, 'e: '__daft, T: '__daft, U: '__daft> ::core::cmp::Eq for StructWithGenericsDiff<'__daft, 'd, 'e, T, U> where T: daft::Diffable + 'd + ?Sized, U: daft::Diffable + 'e + ?Sized, ::Diff<'__daft>: ::core::cmp::Eq, <&'d T as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, <&'e U as ::daft::Diffable>::Diff<'__daft>: ::core::cmp::Eq, {} impl<'d, 'e, T, U> ::daft::Diffable for StructWithGenerics<'d, 'e, T, U> where T: daft::Diffable + 'd + ?Sized, U: daft::Diffable + 'e + ?Sized, { type Diff<'__daft> = StructWithGenericsDiff<'__daft, 'd, 'e, T, U> where Self: '__daft; fn diff<'__daft>( &'__daft self, other: &'__daft Self, ) -> StructWithGenericsDiff<'__daft, 'd, 'e, T, U> { Self::Diff { b: ::daft::Diffable::diff(&self.b, &other.b), c: ::daft::Diffable::diff(&self.c, &other.c), d: ::daft::Diffable::diff(&self.d, &other.d), } } } daft-derive-0.1.5/tests/fixtures/valid/output/non-eq.output.rs000064400000000000000000000054121046102023000225770ustar 00000000000000struct InnerDiff<'__daft> { a: ::Diff<'__daft>, b: ::Diff<'__daft>, } impl<'__daft> ::core::fmt::Debug for InnerDiff<'__daft> where ::Diff<'__daft>: ::core::fmt::Debug, ::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(InnerDiff)) .field(stringify!(a), &self.a) .field(stringify!(b), &self.b) .finish() } } impl<'__daft> ::core::cmp::PartialEq for InnerDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::PartialEq, ::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.a == other.a && self.b == other.b } } impl<'__daft> ::core::cmp::Eq for InnerDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::Eq, ::Diff<'__daft>: ::core::cmp::Eq, {} impl ::daft::Diffable for Inner { type Diff<'__daft> = InnerDiff<'__daft> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> InnerDiff<'__daft> { Self::Diff { a: ::daft::Diffable::diff(&self.a, &other.a), b: ::daft::Diffable::diff(&self.b, &other.b), } } } struct OuterDiff<'__daft> { inner: ::Diff<'__daft>, c: ::Diff<'__daft>, } impl<'__daft> ::core::fmt::Debug for OuterDiff<'__daft> where ::Diff<'__daft>: ::core::fmt::Debug, ::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(OuterDiff)) .field(stringify!(inner), &self.inner) .field(stringify!(c), &self.c) .finish() } } impl<'__daft> ::core::cmp::PartialEq for OuterDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::PartialEq, ::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.inner == other.inner && self.c == other.c } } impl<'__daft> ::core::cmp::Eq for OuterDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::Eq, ::Diff<'__daft>: ::core::cmp::Eq, {} impl ::daft::Diffable for Outer { type Diff<'__daft> = OuterDiff<'__daft> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> OuterDiff<'__daft> { Self::Diff { inner: ::daft::Diffable::diff(&self.inner, &other.inner), c: ::daft::Diffable::diff(&self.c, &other.c), } } } daft-derive-0.1.5/tests/fixtures/valid/output/non-exhaustive.output.rs000064400000000000000000000034021046102023000243540ustar 00000000000000#[non_exhaustive] struct NonExhaustiveDiff<'__daft> { pub a: ::Diff<'__daft>, pub b: ::Diff<'__daft>, } impl<'__daft> ::core::fmt::Debug for NonExhaustiveDiff<'__daft> where ::Diff<'__daft>: ::core::fmt::Debug, ::Diff<'__daft>: ::core::fmt::Debug, { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { f.debug_struct(stringify!(NonExhaustiveDiff)) .field(stringify!(a), &self.a) .field(stringify!(b), &self.b) .finish_non_exhaustive() } } impl<'__daft> ::core::cmp::PartialEq for NonExhaustiveDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::PartialEq, ::Diff<'__daft>: ::core::cmp::PartialEq, { fn eq(&self, other: &Self) -> bool { self.a == other.a && self.b == other.b } } impl<'__daft> ::core::cmp::Eq for NonExhaustiveDiff<'__daft> where ::Diff<'__daft>: ::core::cmp::Eq, ::Diff<'__daft>: ::core::cmp::Eq, {} impl ::daft::Diffable for NonExhaustive { type Diff<'__daft> = NonExhaustiveDiff<'__daft> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> NonExhaustiveDiff<'__daft> { Self::Diff { a: ::daft::Diffable::diff(&self.a, &other.a), b: ::daft::Diffable::diff(&self.b, &other.b), } } } impl ::daft::Diffable for NonExhaustiveEnum { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } daft-derive-0.1.5/tests/fixtures/valid/output/union.output.rs000064400000000000000000000004341046102023000225310ustar 00000000000000impl ::daft::Diffable for Inner { type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft; fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> { ::daft::Leaf { before: self, after: other, } } } daft-derive-0.1.5/tests/fixtures/valid/union.rs000064400000000000000000000004651046102023000176360ustar 00000000000000use daft::{Diffable, Leaf}; #[derive(Diffable)] union Inner { a: i32, b: u32, } fn main() { let before = Inner { a: 1 }; let after = Inner { b: 2 }; let diff: Leaf<&Inner> = before.diff(&after); assert_eq!(unsafe { diff.before.b }, 1); assert_eq!(unsafe { diff.after.a }, 2); } daft-derive-0.1.5/tests/integration_test.rs000064400000000000000000000124021046102023000171120ustar 00000000000000use daft::{Diffable, Leaf}; use std::{ collections::{BTreeMap, BTreeSet}, fmt::Debug, }; use uuid::Uuid; #[derive(Debug, Eq, PartialEq, Diffable)] enum SomeEnum { A, B, C(u32), } #[derive(Debug, Eq, PartialEq, Diffable)] struct SomeStruct { a: i32, } #[derive(Debug, Eq, PartialEq, Diffable)] struct Large { a: i32, b: SomeEnum, c: BTreeMap>, d: SomeStruct, } #[derive(Debug, Eq, PartialEq, Diffable)] struct TupleStruct(String); #[test] fn test_basic() { let a = SomeEnum::A; let b = SomeEnum::B; // Enums are just `Leaf`s. We don't try to walk them. User code can do that // as necessary. let diff = a.diff(&b); let expected = Leaf { before: &SomeEnum::A, after: &SomeEnum::B }; assert_eq!(diff, expected); let a = SomeStruct { a: 0 }; let b = SomeStruct { a: 1 }; let diff = a.diff(&b); let expected = SomeStructDiff { a: Leaf { before: &0, after: &1 } }; assert_eq!(diff, expected); let shared_id = Uuid::new_v4(); let c1: BTreeMap> = [(shared_id, [1, 2, 3, 4, 5].into_iter().collect())] .into_iter() .collect(); let mut c2 = c1.clone(); c2.get_mut(&shared_id).unwrap().remove(&3); c2.get_mut(&shared_id).unwrap().insert(6); c2.insert(Uuid::new_v4(), [9].into_iter().collect()); let a = Large { a: 0, b: SomeEnum::C(4), c: c1, d: SomeStruct { a: 0 } }; let b = Large { a: 0, b: SomeEnum::B, c: c2, d: SomeStruct { a: 1 } }; let diff = a.diff(&b); println!("{diff:#?}"); assert_eq!(diff.a.before, diff.a.after); assert_eq!(diff.b.before, &SomeEnum::C(4)); assert_eq!(diff.b.after, &SomeEnum::B); assert_eq!(diff.c.unchanged().count(), 0); assert_eq!(diff.c.added.len(), 1); assert_eq!(diff.c.removed.len(), 0); assert_eq!(diff.c.modified().count(), 1); let set_diff = &diff.c.modified_diff().next().unwrap().1; assert_eq!(set_diff.common, [&1, &2, &4, &5].into_iter().collect()); assert_eq!(set_diff.added, [&6].into_iter().collect()); assert_eq!(set_diff.removed, [&3].into_iter().collect()); assert_eq!(diff.d.a.before, &0); assert_eq!(diff.d.a.after, &1); let a = TupleStruct("oxide".into()); let b = TupleStruct("computer company".into()); let diff = a.diff(&b); assert_eq!(diff.0.before, &"oxide".to_string()); assert_eq!(diff.0.after, &"computer company".to_string()); println!("{diff:#?}"); } #[test] fn test_enum_with_generics() { #[derive(Debug, Eq, PartialEq, Diffable)] enum EnumWithGenerics<'a, T, U> { A(T), B(&'a U), } let x = 5usize; let y = 5u8; let a = EnumWithGenerics::A(x); let b = EnumWithGenerics::B(&y); let diff = a.diff(&b); assert_eq!(Leaf { before: &a, after: &b }, diff); } #[test] fn test_struct_with_generics() { #[derive(Debug, Eq, PartialEq, Diffable)] struct StructWithGenerics<'d, 'e, T, U> where T: Diffable + 'd, U: Diffable + 'e, { b: usize, c: &'d T, d: &'e U, } let x = StructWithGenerics { b: 6, c: &5, d: &6 }; let y = StructWithGenerics { b: 7, c: &5, d: &7 }; let diff = x.diff(&y); assert_eq!(diff.b, Leaf { before: &6, after: &7 }); assert_eq!(diff.c, Leaf { before: &5, after: &5 }); assert_eq!(diff.d, Leaf { before: &6, after: &7 }); println!("{diff:?}"); #[derive(Debug, Eq, PartialEq, Diffable)] struct S<'a, T, U> where T: Diffable + Eq + 'a, U: Diffable + 'a, { a: BTreeMap, b: usize, c: &'a U, d: &'a str, } let x = S { a: [(5, 2usize)].into_iter().collect(), b: 5, c: &6usize, d: "hello", }; let y = S { a: [(5, 1usize)].into_iter().collect(), b: 5, c: &6usize, d: "world", }; let diff = x.diff(&y); assert_eq!(diff.a.unchanged().count(), 0); assert_eq!(diff.a.modified().count(), 1); assert_eq!(diff.a.added.len(), 0); assert_eq!(diff.a.removed.len(), 0); assert_eq!(diff.b.before, diff.b.after); assert_eq!(diff.c.before, diff.c.after); assert_eq!(diff.d.before, "hello"); assert_eq!(diff.d.after, "world"); println!("{diff:#?}"); } #[test] fn diff_pair_lifetimes() { // Complex type to ensure lifetimes are correct. #[derive(Diffable)] struct Inner { a: u32, b: &'static str, } #[derive(Diffable)] struct Outer { #[daft(leaf)] inner: Inner, } let owned: Leaf = { let before = Outer { inner: Inner { a: 5, b: "hello" } }; let after = Outer { inner: Inner { a: 6, b: "world" } }; let diff = before.diff(&after); let inner_diff = { let inner: Leaf<&Inner> = diff.inner; // Ensure that inner.diff_pair outlives inner. inner.diff_pair() }; assert_eq!(*inner_diff.a.before, 5); assert_eq!(*inner_diff.a.after, 6); assert_eq!(inner_diff.b.before, "hello"); assert_eq!(inner_diff.b.after, "world"); // The return value of this will outlive before and after as well. inner_diff.b.map(str::to_owned) }; assert_eq!(owned.before, "hello"); assert_eq!(owned.after, "world"); } daft-derive-0.1.5/tests/snapshot_test.rs000064400000000000000000000067231046102023000164370ustar 00000000000000use datatest_stable::Utf8Path; use quote::ToTokens; use syn::{parse_quote, DeriveInput}; // We need access to the proc-macro's internals for this test. An alternative // would be to make this a unit test, but the integration test harness gives us // automatic discovery of tests in the `fixtures/` directory, along with // separate reporting for each test. Those are nice benefits. #[path = "../src/internals/mod.rs"] mod internals; datatest_stable::harness! { // The pattern matches all .rs files that aren't .output.rs files. { test = daft_snapshot, root = "tests/fixtures/valid", pattern = r"^.*(? datatest_stable::Result<()> { let data = syn::parse_str::(&input)?; let output = run_derive_macro(&data); assert_derive_output(path, output); Ok(()) } /// Snapshot tests for invalid inputs. fn daft_snapshot_invalid( path: &Utf8Path, input: String, ) -> datatest_stable::Result<()> { let data = syn::parse_str::(&input)?; let output = run_derive_macro(&data).map(|output| { // Drop the errors for snapshot tests -- only use the output. output.out }); assert_derive_output(path, output); Ok(()) } fn run_derive_macro( data: &syn::File, ) -> impl Iterator + '_ { // Look for structs and enums in the input -- give them to the derive macro. let items = data.items.iter().filter_map(|item| match item { syn::Item::Struct(item) => { has_derive_diffable(&item.attrs).then(|| item.to_token_stream()) } syn::Item::Enum(item) => { has_derive_diffable(&item.attrs).then(|| item.to_token_stream()) } syn::Item::Union(item) => { has_derive_diffable(&item.attrs).then(|| item.to_token_stream()) } _ => None, }); // Turn each item into a `syn::DeriveInput` and run the derive macro on it. items.enumerate().map(|(i, item)| { let data = syn::parse2::(item).unwrap_or_else(|err| { panic!("failed to parse item {i}: {err}"); }); internals::derive_diffable(data) }) } fn has_derive_diffable(attrs: &[syn::Attribute]) -> bool { attrs.iter().any(|attr| { if !attr.path().is_ident("derive") { return false; } let mut is_diffable = false; attr.parse_nested_meta(|meta| { if meta.path.is_ident("Diffable") { is_diffable = true; } Ok(()) }) .expect("derive attributes parsed correctly"); is_diffable }) } fn assert_derive_output( path: &Utf8Path, output: impl IntoIterator, ) { // Read the output as a `syn::File`. let output = output.into_iter(); let file = parse_quote! { #(#output)* }; // Format the output. let output = prettyplease::unparse(&file); // Compare the output with the snapshot. The new filename is the same as the // input, but with ".output.rs" at the end. let mut output_path = path.parent().unwrap().to_owned(); output_path.push("output"); output_path.push(path.file_name().unwrap()); output_path.set_extension("output.rs"); expectorate::assert_contents(&output_path, &output); } daft-derive-0.1.5/tests/ui_test.rs000064400000000000000000000007421046102023000152100ustar 00000000000000//! UI tests. //! //! This is a separate binary from `integration_test.rs` because //! `integration_test.rs` actually uses the macro under consideration -- it //! might fail to compile, but we still want to see what the UI tests say. //! //! (It might make sense to move integration_test.rs to the daft crate in the //! future.) #[test] fn ui() { let t = trybuild::TestCases::new(); t.pass("tests/fixtures/valid/*.rs"); t.compile_fail("tests/fixtures/invalid/*.rs"); }