Update googletest to 0.13.0

Bug: 388473101
Test: Code compiles
Ignore-AOSP-First: Requires changes in internal-only projects
Change-Id: Ia6cc0fad1ca07e3b1d34f4c13e629055aa7e1056
diff --git a/crates/googletest/.android-checksum.json b/crates/googletest/.android-checksum.json
index 2db3741..774a9d6 100644
--- a/crates/googletest/.android-checksum.json
+++ b/crates/googletest/.android-checksum.json
@@ -1 +1 @@
-{"package":null,"files":{".cargo-checksum.json":"d6b2b0d30a03b5a480e0c9a54b655d8eb406a699a4d54a1b79f086264f813155","Android.bp":"26dbfa23b3d723fa6e4cff6247a4574d3de9e15abf7ea529443ea6279f723c08","Cargo.toml":"a5ea2564b9871a41486fa1e377e576e5f1f3f173de5812f14ac7cd6f0eff3dce","LICENSE":"7c6512d88b3127990067585f24881ba1f182c5c49a04cb1975b226b7be95709e","METADATA":"699e61a9efcc1e3a7534f11530d9486333cc82b7bbe820d66aba3d6fc4d41a6e","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"07d4f57eac87d9661107bd8ae50f13f05e63ab60a22a5d6e84159a446412f658","cargo_embargo.json":"2b7db5752ae086bd42bc615742f3fe1183fff050dd0fe67aea0c4519d4b592d3","crate_docs.md":"22353450101e1ea34aebd2263b5c9f6b0fc2dca5d876d2a755b52fa9c0a570b0","src/assertions.rs":"dd45066e3462691b73cf78ea08d86bc6106c9d8b3292ea67de80f7c65d5425ab","src/description.rs":"f342abc02a9808cd6ac8efbb0dc5653cf75960fe0e6b65c604a02eb33d18f078","src/internal/description_renderer.rs":"ad2cfa43baa63ec7c33b73cfb66f16fe7fad6379576bd896ab22a1ec418255f0","src/internal/mod.rs":"13cf778b7e517506ee21cce6c347c409ff476a805b76874a320e350a7f5f86de","src/internal/source_location.rs":"2a0bfa8a6556301f4b469711568741d601f3cc35bd46efa48887d123e1ad6cf4","src/internal/test_outcome.rs":"bd48ed72e39f7cb48ab8591ee0786d4aa810a49877e4a300a949dde27fc28f00","src/lib.rs":"e79ac41262f17c185c57c6993ac2fd3aad1f2c127f160451fdfe40f9c2dd6570","src/matcher.rs":"6c4f8bb7c1869c5a4e4bfe4a6fa88ea253256fceacd7d11a71299f17b044a4fb","src/matcher_support/count_elements.rs":"7487aa09ddfd68e7786943bc68ba97fb54857441e9fb7160f5eac1785a1d2176","src/matcher_support/edit_distance.rs":"0cf896f82ccaed727c0a1c7e2578fd1430d812fe52168e17b08e53b185385c81","src/matcher_support/mod.rs":"9e594fb5d2ae79a34c451f21beb1912cf9c05646156a8bcb482dccf55adece03","src/matcher_support/summarize_diff.rs":"7fedfdc6228307cce6da7ff3519be8d2c516c9e2f5fbdbc05ce679e476877024","src/matcher_support/zipped_iterator.rs":"2c022b163bb1defda1522df9ff6824c0db0044e9314cdd45dfe39e2e1e335b96","src/matchers/all_matcher.rs":"f58ad8690c1237eb53c7d745ef9df667f6c38dc19e02d1a0641d563392feb6f3","src/matchers/any_matcher.rs":"d5c4d03d9f515bed370ca538013b6d6d8d62c57309fef9decd3c4b684a73e4a9","src/matchers/anything_matcher.rs":"664c706c76d7603664a81f043589f5ab6cf1e9585bc307ab07a16df4d75cad32","src/matchers/char_count_matcher.rs":"2707f530252e29c45b953e4d5fb9c86e0ff62041b07ce6331cb9cf7db9858e2a","src/matchers/conjunction_matcher.rs":"8cb736a15d2be8405e200d6599e2c6d8e86b79c27822a3bde2361fdd3c9d6a2d","src/matchers/container_eq_matcher.rs":"97eded933a75fc0a42905c455c53a31bea88b5f65cb7a072214313db72c97d84","src/matchers/contains_matcher.rs":"297cdbcf152caca7593f809fb805bedc25c5448157f351c63cbaa97e10304c20","src/matchers/contains_regex_matcher.rs":"d818d0aac0302fb9aaa805aa72cbec240c1303b59e59b85a070a983796a068aa","src/matchers/disjunction_matcher.rs":"a0e72b4c6aaf33c468f74ef9d276006e800ad675a8e572c9310271a4cb2b0d0e","src/matchers/display_matcher.rs":"2a73d326a2e547abbebc58c401128649187ec57aafaf3a71cde58ec0611646b7","src/matchers/each_matcher.rs":"b0e0d70598601135f31715823cbeb2c1709900b11d07c1d9305e37f31adff61a","src/matchers/elements_are_matcher.rs":"16e10c4bf6755c26ec72f6343aa1b363c8260dd387561c9ab2595e3dec84b46e","src/matchers/empty_matcher.rs":"6d29920215cb48e880a1fa0519727467e83ab74cccd3472b9aa2bae016b7d35c","src/matchers/eq_deref_of_matcher.rs":"9d1fe8c2094a3649ace379731af601b6c4abb1aed412a718d25dcd191f1c9496","src/matchers/eq_matcher.rs":"e9b985a9cc3bbd471aead0cd7100b0725edd4faea0d35713f43385ee19ca3af7","src/matchers/err_matcher.rs":"0da1c872fded683fd515786c5b8aab8ee99c3bd8d8ba35ae74ac354473393447","src/matchers/field_matcher.rs":"50b4589bac6222e3e7a3aa1c140fda70a259fde39b538b7513e3305362c675e3","src/matchers/ge_matcher.rs":"af4641c64a43fa29c9d3878443a62dca64620c311e1957609277ea707fcf5a7a","src/matchers/gt_matcher.rs":"d9bf9d216f61335e067a39f421ef1e3baff2871776f6287541f06711c23a2733","src/matchers/has_entry_matcher.rs":"f2ec364e57853468c941f52329dab2251b581a7c2deca69e953b4b94be509e63","src/matchers/is_encoded_string_matcher.rs":"f95f3fed1b0e161829983fc50077dd931f5cc16e7fedfec2de088a7083d926c4","src/matchers/is_matcher.rs":"6a2a68665a079e21406da1454408d606e62c5e21ee07ae94e7eeb4335ea3f044","src/matchers/is_nan_matcher.rs":"33a179908c1f0ab95351c6ec623d5d0dc494bfb64cd8df2ff4244f01916395e7","src/matchers/le_matcher.rs":"c2c6818514773564ac578ffe86e5e2b9bff58785ddab0b37697c4bb80bea38dd","src/matchers/len_matcher.rs":"015b86c053595e3fbc7ede581ab03b5e168369b6f8cd133f3b479c181f474001","src/matchers/lt_matcher.rs":"c937c756416f7ba5f5ea907f9ae5539ad9520c33227346c4abd481c8e70330f1","src/matchers/matches_pattern.rs":"f17968108e733459a06fbb0709ed7b76ce8245e183925c06d8575545f5c23071","src/matchers/matches_regex_matcher.rs":"3d95e01bdb64b1081cfccb11465edb94dfde8566ea3950d03fefb75eab854189","src/matchers/mod.rs":"09235b20fb2166d2d5c72316a9b3ecb736344b7a9636855bd9d94bb1fb5b4831","src/matchers/near_matcher.rs":"645e70df5f2f4c1d3e3b89d377296e21a30cb90d34426069f5aae36fe29206cb","src/matchers/none_matcher.rs":"d1a13d3de32e7ba5781accf9d01104cc54d0a9e6df3a38cd00768ea2f6eeb18e","src/matchers/not_matcher.rs":"43ec462558eec8021ef238a72541433210fe9915be235a5845cbc9217e8f0f23","src/matchers/ok_matcher.rs":"f358885ba1be7f8b24ad658788c9c1673f03950fda6b166d2eecd8eb1899efce","src/matchers/points_to_matcher.rs":"30f88451c8806aee81d0f9925583f15531773399089e54ad2fe4b81544b45fb8","src/matchers/pointwise_matcher.rs":"8dd05061cb3a86cde777c16f4b9d84dab6469084e8878dabfe4f34748555a96d","src/matchers/predicate_matcher.rs":"e18e614fdb2a4ce28ae92b33fd605641b9c9720391e0e9d067f90b7060b62958","src/matchers/property_matcher.rs":"8507ec831853e9947f57fece53bf7e79b1c902290ae1cf55284186b8f06b354b","src/matchers/some_matcher.rs":"c643fe7aae9fac6565894b83080a352c3f843c785e44e27ad3053eccee141403","src/matchers/str_matcher.rs":"37657e56b32530124d04903ec7622a35881cbb39fed0b719a24c1362b2ab8574","src/matchers/subset_of_matcher.rs":"1bf4fee1617e65744b3ec9cc18721783804ed84fd27d7d7f253b5fc82979b6bc","src/matchers/superset_of_matcher.rs":"d1a8dbd21113d22eb1fef9fcf45d136a388a6ce4622f8244344b0b81d2856144","src/matchers/tuple_matcher.rs":"9e08b6b4e7bb5cce0f47047ca89a34d058d634eeeb13357c3c8140962f20a1cd","src/matchers/unordered_elements_are_matcher.rs":"802cad45924cdfcf1d1a72b83aa01a0c06d7e6b01a219f76638af3cacae69056","tests/all_matcher_test.rs":"91a95c6aca516f2cedf7ecb297280ae52b5cf96e25eafe29cd0b4bf40493b5be","tests/any_matcher_test.rs":"e8aae6ac19e3a8501cd0101cda2cc0c5fd49ce05bf81651cec925e2f01eaedfb","tests/colorized_diff_test.rs":"9632e5d8460f67331df2edda7848db3b79bcefa043cd44d8aab7eafc90945dae","tests/composition_test.rs":"dfe726b38d357ff8d547eeddbdca539b8bf70f6681125f063c88db6140c8bf65","tests/elements_are_matcher_test.rs":"5ccaafb93fec5d9790edefb2d06ed5376f898e8e971d9663614bffcc939a96e0","tests/field_matcher_test.rs":"b3e7f0f6d403d4dc768d282128ae6eda68a96fcf1cd3127c107cf68f423a0bf5","tests/lib.rs":"d48d840a933a9a9e1076865eb6e443b538d4f37d94b45b7110333511f9a50d9d","tests/matches_pattern_test.rs":"35101434bbb3dea2e3054dfc55381a886d2055002156ebb2fa1575fef6386a63","tests/no_color_test.rs":"13795788bd9045f25f040067cb359e4d55505ddf6a1524922db23f3aeff570af","tests/pointwise_matcher_test.rs":"e0c14a1e030f83c3ebfae00d73c49af60d5958836aa8264ce4a3374330196f5f","tests/property_matcher_test.rs":"57da661e975d2af939ffd3bbd5fac7d11b2d344fa62d709a78080a68053370f4","tests/proptest_integration_test.rs":"0f75081bd6bfd89b8a5e430238a9da78a2f13ce6ccc4e105e32705596e9c3a7f","tests/tuple_matcher_test.rs":"b16ce00f9857206f9ebaf18175c4d2df5de739fe85873fb0f30b1c69e794ffe3","tests/unordered_elements_are_matcher_test.rs":"2d3402327bf2915cc79a3fce01f939e4454d45dc8f53826211add79d389f3c29"}}
\ No newline at end of file
+{"package":null,"files":{".cargo-checksum.json":"410493270e72d4760c1e835f510b65d50a78811d6946a3f93170a161f8b9d815","Android.bp":"31cf3dbb287b6b5c5fd4dd46be662c4b64ca88577b495dc9436f8d5db5707bb0","Cargo.toml":"a194180b19517aeb9c05048610d5f7422c6e50113ebc55b5f381f06b22414b3d","LICENSE":"7c6512d88b3127990067585f24881ba1f182c5c49a04cb1975b226b7be95709e","METADATA":"8e573ebeca353ef9a3892bf4ba8ae4c0b0f781d737b2716ce2b791903a85540d","MODULE_LICENSE_APACHE2":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"440fe5145aa23165197219e0378cbb71cd7ca336fb1dc0fe53a3d5a2e3d4471d","cargo_embargo.json":"2b7db5752ae086bd42bc615742f3fe1183fff050dd0fe67aea0c4519d4b592d3","crate_docs.md":"86974c308ad2e035d0368179b32191c32672353273cfe5ea970687a97849b016","src/assertions.rs":"3f9defd623a7006b23d3963caffdf701b78c8cf0696a94ead1541e43698d3866","src/description.rs":"7bf3fec806182d8a011b46ca0dd7f14adcd17ece7fe81dc7770a232ecb21b21f","src/fixtures.rs":"b8ebce97930de9822eed6fa6e1d0aadf9e8eda61c989ba27644878444babe143","src/fmt.rs":"f6e89ce1eac6215301c185762f0ca5214efeda1fb431a9adfa29dafec6bc238e","src/internal/description_renderer.rs":"22f0dafd9d02a37483bbd689409f01b001184d30c095459b21c61cf90df071dd","src/internal/mod.rs":"bfaca36e81794979c6f7976e96a6ac8f7b09d0181ac8f44538d40a2e40d8453d","src/internal/test_outcome.rs":"e8a39aa3bc29d79e64ad42da4f22a18452b76171d28d14be3cbb0b822f517299","src/lib.rs":"109c5e2b09705cb4bd11330e10c69daf2523b01422f103db6c10353823f6fccb","src/matcher.rs":"e80fadb4a9939d190e1fe94570e9f50ed2359842505d7862e34136cd8f6ac55d","src/matcher_support/auto_eq.rs":"5a6d9607a884b9a21e0ec29a8b75a78e741448ac858b618506521eb67a2d255f","src/matcher_support/count_elements.rs":"0973e4f0f73ea1d92b8cf6559aa696d84ae27179765f93fa03acfbd239a447ca","src/matcher_support/edit_distance.rs":"83aadc058939cf5338038650b9edb85fdf2ecf6d90ac35656eda69d7f4715102","src/matcher_support/mod.rs":"fc213e3f665b23bf34f639dae133920fd17db0a5c673d4957f9cbb3d4e706d71","src/matcher_support/summarize_diff.rs":"6aafcc3b42872ce9a07e0d422816f4f9e62c470b028e36bcd577c140d5017888","src/matcher_support/zipped_iterator.rs":"2c022b163bb1defda1522df9ff6824c0db0044e9314cdd45dfe39e2e1e335b96","src/matchers/all_matcher.rs":"b9534e5d1657791b341b411989b5ceba03a48ad625afc208a4290c04a5a3c3a7","src/matchers/any_matcher.rs":"1b082cd64719aad9f01b3862ff87b20cb41ccd64c268f18ab67e9a5207f6ed0c","src/matchers/anything_matcher.rs":"1bcde76add015ff9edb69b6ea55eafd8d3e34b61f56efd146fad748652d974f3","src/matchers/bool_matcher.rs":"abe9fd9f0afa6b0276e62e45d19e6c030a3e9fe4e162506ad77a3a815062d3d0","src/matchers/char_count_matcher.rs":"93ffefefa301e1968cd0cb166e451fba1662d684a682f66229cebb3c01e78c16","src/matchers/conjunction_matcher.rs":"15761c0a4cbb2f97935088f58fc00b659f1a2c12f36a22958ac96c203e16e5f1","src/matchers/container_eq_matcher.rs":"03efddf8e882415f9734721c6fb4b507f60d376088594be98c684cb913caca0a","src/matchers/contains_matcher.rs":"012416f5634b0d1c72fb529983fc9a7d42f70d652bc786402853ec40f1675845","src/matchers/contains_regex_matcher.rs":"04aa3ec505c57ed5cebbcbd5ae8341d3e45ed0dd567ba401dc8e63f1c65aab8d","src/matchers/derefs_to_matcher.rs":"3d2f6870fcdc52c4619914a04dcf4d4bf94e28f23287f06091088e4a00512670","src/matchers/disjunction_matcher.rs":"193b85d9ba177af4592e40be36cc67bdb4d2d4ce561d9f9bdc8f8e196a11cc05","src/matchers/display_matcher.rs":"f6b7216ec2c6f6200c4493e874d73c19a921b65381f9dbf147c689454ed5c87d","src/matchers/each_matcher.rs":"5cd5d03983475db8c93ef89781e3ab3e68fad81fefd829eeedc96be94bbae4e9","src/matchers/elements_are_matcher.rs":"6e593c19c7ae1c60f5e8a811ac2a5a48edd21d72e788af69fe588fbfd6caf110","src/matchers/empty_matcher.rs":"e5dc9e0e7b2799b14590b2d93ffee056339b0befa9acaf4a17aa15799e8d5716","src/matchers/eq_matcher.rs":"59f3839dc3ba5928c784fbc72c79d90d41a23ac14b27de6d8f3d50eaa2cec866","src/matchers/err_matcher.rs":"eef9b9bdbe342903c4545d7696e52d7b06df6677a91a59274fc16999ee5f658e","src/matchers/field_matcher.rs":"db9c32306aad1010dfe9c6acc96acf867a22ff8324bf560ace44f680e07d174b","src/matchers/ge_matcher.rs":"6fb61cbfb8f3e81f71900df9b0420ae155c0a19591cc95ecb024481d9047299f","src/matchers/gt_matcher.rs":"9555f0c294def104eb738de55c63f012267375e4db269cf5ca60ff5ea8d56275","src/matchers/has_entry_matcher.rs":"20bf4c271ff1d3673393d6f8c00ccce4d1e0f1604a16055f0c46bc0e5b793ddd","src/matchers/is_encoded_string_matcher.rs":"f4b60009696d1396029d36ae187fcc3528a661e1b5c38479fac9f4e9e416dd4a","src/matchers/is_matcher.rs":"df8fc55cec747b9764bae05595a403dac253514a21fccd98ea7c46a83e541999","src/matchers/is_nan_matcher.rs":"111cf9e8aca5d709942909e41fa0f6578418bc890dfeba52f9102038c5633283","src/matchers/le_matcher.rs":"3e151e3d13f944d81620aca4311dd15b382dc575266638df09eeb0e66cc674e0","src/matchers/len_matcher.rs":"24adda42e1750d8bb49ffe12a3f431c6c173c27c313d973b7eea31dd616a1642","src/matchers/lt_matcher.rs":"ff7ce1397b713955d643debc6200dc0bd5bfc4f8252433ea1650f105886ae8ef","src/matchers/matches_pattern.rs":"5c36c3f0eecded409b7fb336013a84db00176f861b65f07dc82f207570feadba","src/matchers/matches_regex_matcher.rs":"ebd8e88cfeedf394bc2550137d67dc0e15759565d49f4e3ce2e7f59c9f24808d","src/matchers/mod.rs":"fa62f807cc57cc5ee784f630e75b7447079ff5ae7513e2f15086dd061428f2ad","src/matchers/near_matcher.rs":"1e009423fc9326a984558db4efaee53d5de4acb820ef475c72c4696ed074a99b","src/matchers/none_matcher.rs":"fa403c8c7868fb41005042dfd874d5d096c52590bdd252ec5be990225f36b6ff","src/matchers/not_matcher.rs":"c98ce0362a9d7ca308b3bed4b7853d7320b22478185d777cc09fd0c627010ea0","src/matchers/ok_matcher.rs":"cadab709d5c52f2219bf59118a0a29dba8614532ead56847490e489634e5d147","src/matchers/points_to_matcher.rs":"7e845a3fa699be23e917dd90bafe4d68bbdc8d7c3fc042ba689277e3f7c8ec4a","src/matchers/pointwise_matcher.rs":"ecccadc3baa9afeacc6242e41501b27cb1581dd1502aeb127ff1fbf52cc62338","src/matchers/predicate_matcher.rs":"b9d64d86e7ef292d57aa2a62bab7ccc64b0fec262fe0bd73d08924e203d784f5","src/matchers/property_matcher.rs":"1f4fda841361381145c2c96c56cc2d50f4af008c169bfec6615b77e4b6886722","src/matchers/result_of_matcher.rs":"0d0f66f4f5d4e76062e0d427e6f7349cceb7a574d3097eb5ac982f16c311f848","src/matchers/some_matcher.rs":"6179779b798ee60e4fca6ded4330206a398798656f3a6ecb00f44cb7e81d39d0","src/matchers/str_matcher.rs":"1aedc67db3a0d0197a32f52f583e40bc89a95cca1dd70513fadecc24a7733346","src/matchers/subset_of_matcher.rs":"1a463f7c277f31e7f07fb6ef3901ad4e6d3907cb8725f2d8ec4647a4e5a8ffd8","src/matchers/superset_of_matcher.rs":"5b40ed602c8aabd66136f932aac1f5c031b99e1d3c0adcf81a50b998e1bcfde7","src/matchers/tuple_matcher.rs":"6dc905a4ccf5748f855868d2f5819dd3b92d5a4934d2639a2a3e3f6e40050b70","src/matchers/unordered_elements_are_matcher.rs":"1b5508b3aacc164ad9276834579d75baa241504f26d591995c04e51959daad01","tests/all_matcher_test.rs":"a1347ab53409098f3ea78068a2523e2f6885c22d988d50131e32e1c21f96f7a9","tests/any_matcher_test.rs":"709ca1a20c82fcaf6be821d4b328506f17855e5ffbe21996f27d67c3ae96af04","tests/assertions_test.rs":"c6e952cfed6998b6ecc7d4260d7f6c3b3a29f031856e6e4683a223a0cdf392b4","tests/colorized_diff_test.rs":"a55aa6e001df9fdc8684136a59555bf0ec27ae84848aa4c9a3a31842934b30f7","tests/composition_test.rs":"51ff2e05d3b4dd06e246eb9e4cfb3c1997369ca9cbb34ca2a7d1d5599a9900c0","tests/elements_are_matcher_test.rs":"c98dd588a184b118afd71767b3f07dfc8299ad8a9147e0835e33906a43a41552","tests/field_matcher_test.rs":"634fe967a801bc077f477ccb38649580011c2957b0f37e06a73f5654b46a7211","tests/fmt_test.rs":"67c0032bc3b3d2e07aa74c87bc583c85cba477840f1782358776f5aa33c0e3f4","tests/lib.rs":"357bbd54eb3dc3af000e2f3eaecafdc0a59a1fca30445773b64872c050870657","tests/matches_pattern_test.rs":"390038894798d08feed6dd2209427d8729dd9029ab95dd685190bc24de28364a","tests/no_color_test.rs":"f7472284fc864d4654d4677fa44274825f9286f696228c59175ee6525a8a5343","tests/pointwise_matcher_test.rs":"159bc32c50b792e9c96327c970ea44ae895e842a5f92fe817ca4d8f1e344bbc2","tests/property_matcher_test.rs":"6f2afd05c0a55624c3ef6e0f30398cb49188690956351c9a2f2e6f428874f381","tests/proptest_integration_test.rs":"0f75081bd6bfd89b8a5e430238a9da78a2f13ce6ccc4e105e32705596e9c3a7f","tests/tuple_matcher_test.rs":"3cf3a362ec753ba2e0f48db6716f32d31521335ed66a2d27aef69a271f5a902a","tests/unordered_elements_are_matcher_test.rs":"38c4f8711a056284afa0d3af3ada3a216d1b58ace71b3d1d4b844277fca45217"}}
\ No newline at end of file
diff --git a/crates/googletest/.cargo-checksum.json b/crates/googletest/.cargo-checksum.json
index 4b4a4f0..9ceb8e9 100644
--- a/crates/googletest/.cargo-checksum.json
+++ b/crates/googletest/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"81f8a9a3e6798d1747bcbdd240617b84f26d5a5c88ab748152f6a7ce792e3ef0","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"15ead96c81651817d7b9d02c697aaedf0909a80dba2d0acb5c173c9d1d98d3e3","crate_docs.md":"4fbb126bcf704aec6e587348c5683030f28516baf1924e37f0eb4908e09a79ee","src/assertions.rs":"6bc4c890ce36a54838049eb39b35807009fc103ed2f07980e76606c8f0a417b3","src/description.rs":"b51af6bfe83fe8d41837fea2d6a8eb9efd0966df8384228aa86cccd444fd688b","src/internal/description_renderer.rs":"df583f7096cacd4e63eb720e18bf17c7f5e45eb81c57bfcffc04711abce5add8","src/internal/mod.rs":"bb5bb3dd31ccd33f893c79f81e4f629186d1047935036d773a2d5cee3feee959","src/internal/source_location.rs":"ae5014cfea179d3a619714a64810bb8feeb7e8c9267cc8c9066cc52620762b46","src/internal/test_outcome.rs":"9081c258ba3bad2f1222a006a0cfc6268b6c06fdd998e8d51f1ee6c2079900e1","src/lib.rs":"523c79fb0da7a59b0146456c919db2c20cfddda5bb03c7494fb70dd454d67390","src/matcher.rs":"6eaeec6b6d90b4ae74d298a861c03e985147f194c0c6ac296948b479d4721414","src/matcher_support/count_elements.rs":"9e9b1c238c84fb65319981267842c794f406a696895cfd84da463e050e768c23","src/matcher_support/edit_distance.rs":"72c03abebc181da092c40853e7a7e6a9d78a80074faca188bdfd3f80ef5715c2","src/matcher_support/mod.rs":"acdd182e13ecbdaa55f66526bd18ca4be826e3fa2ab9ea593d10d4a867aa12eb","src/matcher_support/summarize_diff.rs":"a27afa050f0e0b38a5813cd109f0a56152ac1552cd7400866de27f4622ba153d","src/matcher_support/zipped_iterator.rs":"ac1a1a54f866f977255403a4f7e7613a4116af163326029c54b65ca1ac57b538","src/matchers/all_matcher.rs":"b3cdaec8ffa2bb842ec8b2a9ae37890f88b00d48708c0d37584293d5d5f7ad36","src/matchers/any_matcher.rs":"c08c104699a7e7b0ad3788c1e786b15626253707de33671908cadef34f8b43e8","src/matchers/anything_matcher.rs":"d0244d3338bb8a6b9c677b1c5bcb56b56d6736f762b68110e14317f3b67c273f","src/matchers/char_count_matcher.rs":"eb89c497c73b7ef94d2cc433da0f1bdb6fd97e79fb137e7b2e3c9fd6758899ba","src/matchers/conjunction_matcher.rs":"fa7bacd6ef0b1b5fd858bb8ab48de82d09a3d4bfba1a314e5c00e35ee858e46a","src/matchers/container_eq_matcher.rs":"9b74345b3e244a574048928a3547ea00ae9dd75622feb3d5a7139c13d2c8e60b","src/matchers/contains_matcher.rs":"418c2da2366ea315bf75e610323faedf2ab6dc0d9d424cd650be691f811a384d","src/matchers/contains_regex_matcher.rs":"d6defb887ef498f4d7a9958a313927375aed996d78629e7213dffe07e2719b1c","src/matchers/disjunction_matcher.rs":"18d1918f30d58c19a9991caa0ec0cb43f55d196824373e80735a7c50ef6781c8","src/matchers/display_matcher.rs":"6ab9ddcb28173f5959d5c82dea9cb9f779f260cae2995e5f318972775317dacd","src/matchers/each_matcher.rs":"218eeb263cb1683c6a20ce80d0f127a1659a6f5da3f74bb1e3d810ab259b80c9","src/matchers/elements_are_matcher.rs":"55c890a72026eb8bc717bb0d5039b98e7f8be09da1a3c46b5a7505f63a76bb2f","src/matchers/empty_matcher.rs":"a6accac5537e29f313356b46d344354ceddd89ab9857a52febc8005b0fb5fb21","src/matchers/eq_deref_of_matcher.rs":"762038bd3e8912fe064504ca173b988bb65e3792b9d935f086cbcfba67ce346f","src/matchers/eq_matcher.rs":"fa03d1a053c6d5b0bdecfc9515e354037d9fef64cd6d2c96dc04d2ef7eb64d71","src/matchers/err_matcher.rs":"4aef1b1a5fc33825d39e4ff052dfeef7996d02eda5f931c59114125ec40ebc62","src/matchers/field_matcher.rs":"f18cc28b683beb179bbf3956ffc86852402fae96ff3fa0936ba89ba8c5f7ea65","src/matchers/ge_matcher.rs":"4c67bbdb9e4acb95f3b2b38dec4d6793781330eeb0895f3edb305215d2bcf4a1","src/matchers/gt_matcher.rs":"d557a138e30b47c9cc65d26739df3d9698ad180898cabbfa18d9a0db6474c53e","src/matchers/has_entry_matcher.rs":"a39375c7a7a12daf5080980a07564f4eaf39abe143d2bc40f64f5942b89223da","src/matchers/is_encoded_string_matcher.rs":"91f1c2e89377722248346c9cb3e87cec96e9bdec66f1a391332263ec86f955cf","src/matchers/is_matcher.rs":"6026f6f7dc9c08e65c498cbd73ea47613e65ed3e13a8dcaa0b303c54ef4bbf3a","src/matchers/is_nan_matcher.rs":"4c0d2b507e9a61ccdaaa342698cf48ed31e3d62a14b2eaa07afb95de4afe074f","src/matchers/le_matcher.rs":"6a168eca823bac8e7bb82f9d5392774fd1e0d9616cedd43c67fcdda46250a964","src/matchers/len_matcher.rs":"b77b7a4685e81ff79fceea5f382d9274e2cb8bae2abaf4f2f69ca6af4a0ceb00","src/matchers/lt_matcher.rs":"12535f0c0edad7098869fa343c225aaeac8417d97c665ff58ae917fe8497c5fe","src/matchers/matches_pattern.rs":"7d655dd989035ecdadf6cd8d59f3057bc1f115ffb162517423d6588c56ff20a8","src/matchers/matches_regex_matcher.rs":"edb52ef557ced3af81f38908917417eb08c917c166bf6fe59ab8223b53de0050","src/matchers/mod.rs":"1213c95b199519d0b978198cbfbe3239d02ade145cc6ab18a5bb91c7141b4fc1","src/matchers/near_matcher.rs":"127cfe0cc9157079a28025dd0ceceb7dea8329566e46995f4b8d1de19bc92a5e","src/matchers/none_matcher.rs":"2d9908719fcc59e281207e69c3528c8133380661b361bd159cb25e28917789ca","src/matchers/not_matcher.rs":"bf2057c6cf7b21964de766ea16d8902e6f0174793ecb602c26d39cdae5761e8e","src/matchers/ok_matcher.rs":"a05c8eb9addfb3af57a9b0b8fd56f4a966ce927be5be265b8978e19c240e145b","src/matchers/points_to_matcher.rs":"5cf3f776756b904d66847ddd49b455681266ae32c37de7eb3de729a66e1055a9","src/matchers/pointwise_matcher.rs":"0d8f9ddeacc13dcc6f34b0a4fdb7c0a5ff54f3b4b5e85f061c7907b9a2390f9b","src/matchers/predicate_matcher.rs":"d23b67acecbdd5a3bb410c8444f376947ceada2c45fd2d5e775c2e6cdcab407d","src/matchers/property_matcher.rs":"21ac721ad28ed02bc21c7d86b8fde371e1dc0606c5449b6e9aeb2c20cb0aa47f","src/matchers/some_matcher.rs":"654478b0966b9c39d5b07367b595925065cce2580c8bfec0789d5d01eb44fa41","src/matchers/str_matcher.rs":"9e24f276cc060d5174a78b862ceba65452669810cbb64505382c13395e289c10","src/matchers/subset_of_matcher.rs":"6c5f875784ae05d26adfb7532ee5d089d3de6e6369abca6b1a84f6c4aa5977a9","src/matchers/superset_of_matcher.rs":"05e6b4f965f033071fb5feec2e0d93058461b273d4613f338bd4124d59635cb7","src/matchers/tuple_matcher.rs":"d028f7e2b54264256eebc05f54891798f769d06be72572672292d77c2b6a2726","src/matchers/unordered_elements_are_matcher.rs":"ad0cc9f229fd97d689fce3b93f809260f568487d1ba17c4c8c4aa0640ede9000","tests/all_matcher_test.rs":"4b0690e97dfb426f336266bb2b09f19dd3f86504f400e89f5821a888a71e41d1","tests/any_matcher_test.rs":"064343665458ee48502697a46b14059b1971f972bcb9e92db09638b5f053505d","tests/colorized_diff_test.rs":"39227cb13b2914c14231a998bba4243309645e8f029c3c62f2a2969d699ab9a7","tests/composition_test.rs":"729dd849a7a423a000324d308874aa89558b0be6027bf4f608224a63a90322b2","tests/elements_are_matcher_test.rs":"9b2926f2f6efcd0a96f13f1f370e040c7307b2da3006f3c68a160776c5057729","tests/field_matcher_test.rs":"bc34936df7c3c4b36e1b9998565c8363967f7eeb5bae0afe4001cc0fbc36f5e9","tests/lib.rs":"506b8b37c82a7ee08ef9e8c29437b98c46097d96ae52bf75ba3c82ac24096996","tests/matches_pattern_test.rs":"8372b8823edb0028f3ed38fc9b669fcc3ad36bfa153e7671e3f6cbc8bd7798da","tests/no_color_test.rs":"3e248b14597b2b6c2b60a52f7457d822b8a19e8f5604704aa0175fd0e21069cc","tests/pointwise_matcher_test.rs":"5078a462bafe11ed27501ba789d73e4e910c2e128197c0069e1aa790cdeb2684","tests/property_matcher_test.rs":"674217ce981e7be12f569fe78279abd89a3accfa81753f58aa535814887bec09","tests/proptest_integration_test.rs":"948f4d59b7f325faa522e53f3c8a4542be349f368cb790a39c157eb6c7b47014","tests/tuple_matcher_test.rs":"2f87305c29a4692f25a481f2a30e79a765579fd538872f57669b48ca576204f6","tests/unordered_elements_are_matcher_test.rs":"1026cefc59daa8fe2aa249b87800238699d2352224c04ac4edc648b7052a13ef"},"package":"ee44a233e2e661240ef77ed5de92ea9ecf70d4832963a8582a6681e1517f3673"}
\ No newline at end of file
+{"files":{"Cargo.toml":"e00cc51a8d859b2a8fd95e199c13db5e16ed79837573b9f445e086e255d43893","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"12cf77cf9d98dab80416f8135448cae5d0bb532e9b69c63b951d49861d8d649a","crate_docs.md":"b25c57c437bd7974921b9f7172e868d3efd3b1551addc8c47f8ff6a4fc5d8ee1","src/assertions.rs":"43883536abf5f4bb9c2a746593ad1f4cba811574838f700daa703f5b952b2c41","src/description.rs":"f9fb18581c36db85a7415ffa5c9f646dfafaa7594a0a4d00ab66729de5a3f3ad","src/fixtures.rs":"528672a95a3535b2f18d28b29c2ed0a9262462738984d94af74d7cda0e4cbb86","src/fmt.rs":"986f1d796eb585999dc0614c5aed3c94230c0ba19893d2b2cf8eec90e20a38c8","src/internal/description_renderer.rs":"c7d685ed7df27e8670ec77ba7265dd220da84056e467fb62e8faf3f5e0898e8b","src/internal/mod.rs":"b07f41cae5b2b78806be89fc48da938fbe41277c37456d79891496a26e2c921f","src/internal/test_outcome.rs":"40f26fdde8a101242d376a4ffa1157fe177a017d0d4659bc747eae93762f83f3","src/lib.rs":"07bb924c81b725635a2df75b0283a3d581a92cf544923a6d6a869fce491cb4b4","src/matcher.rs":"a07acfabdc658cf23df089763c9faec77ab586cc9e153c01178cd0c9853628c6","src/matcher_support/auto_eq.rs":"e7a95ffb7ebe4f23986920e494e89ac254c596c43382bdb730a17eda02b83d87","src/matcher_support/count_elements.rs":"34ac45d3fedef1e9ff9ea46144e450fc2972e17e3d266699c61fdf68cd5ed2b1","src/matcher_support/edit_distance.rs":"e91a22eb46f1000a0ef2efac547ab1a05a18612d1c5024400800a0413ea8c74e","src/matcher_support/mod.rs":"df976626c666df50f9a12ab4486fb64c327ef9b7ee3b497d89e9a7aada889c1e","src/matcher_support/summarize_diff.rs":"82700a07cb45c20d6375227928f32e17422486373bc10377d4110537bfb271a0","src/matcher_support/zipped_iterator.rs":"ac1a1a54f866f977255403a4f7e7613a4116af163326029c54b65ca1ac57b538","src/matchers/all_matcher.rs":"a12ea32a2872ba6e0194c4b294182157ea1fcd8dd8800005c45f9faad81aa6ba","src/matchers/any_matcher.rs":"2d2b1db30790c7dadbd7e1b77e1c796b71e3770480d21e15bce7033eeae0ecb2","src/matchers/anything_matcher.rs":"5905d9ae3e01274ec514cb5f09518dc7bfd416fc0bd57b02ee10d3ead04ce7bf","src/matchers/bool_matcher.rs":"245a72604474071a00f6a4231a00d1c984aca035cc9d79c0aba090eb46d686b1","src/matchers/char_count_matcher.rs":"fe013c27c9e3a7e8b627472c272dc38fa0ab0674186384bc53ce64130821ae38","src/matchers/conjunction_matcher.rs":"687e6f1c5c8d33cec539440626790c99fb9048ca95b3e5d80f9fa531caa8674f","src/matchers/container_eq_matcher.rs":"b502076dde050afd270848c9669b0818f8f749e5afabc81441f800defdc94562","src/matchers/contains_matcher.rs":"f79b8f816a265ddb96a769e9ac48f8a6b175f127a4b1d8b24e8f4d76fca239c0","src/matchers/contains_regex_matcher.rs":"4b9e13c36ef4314ee7adbbc46e5138ebdb1fbc41f231bc9cdaad8efdb3f8cc5e","src/matchers/derefs_to_matcher.rs":"0f91f73cd0fcdb580be617f11b96b93d1055e8871554f745c76175b035e20621","src/matchers/disjunction_matcher.rs":"45f1c1fb5192f6cfd062eb05e77135b566763292589d8fe29048aaa01b357698","src/matchers/display_matcher.rs":"040296c9ad47f0dab694a7c3b3b24beecd4e02d2de011e52d432309ba97e7e02","src/matchers/each_matcher.rs":"61802a11497447a8f8144eb7be97b7600cc04fa55ed884728c4d7c14d0ca2455","src/matchers/elements_are_matcher.rs":"feccfb18fa552d94d25ca051bd9b4fe69d65004604b2ec317699f9c1bb4127ef","src/matchers/empty_matcher.rs":"7d68972d24e7d81dea6bdc77a8193d0d8c9b1988aab737ca3721b75e134b8e50","src/matchers/eq_matcher.rs":"8ea401d1e4ad5ff2f96a7178640c7d7e3b416a43e4d88086460ac4fba23e7044","src/matchers/err_matcher.rs":"0f8c9e47b76973393817d760c1b3833e4f81fd4a1cbe0bdf1237947b18c64902","src/matchers/field_matcher.rs":"01c95cca86e69266146a4331f00e2d393f88856a5aa44c2163ae9cc5e1ab348d","src/matchers/ge_matcher.rs":"cc45fae8414095959f5da830589495b0a1623666410953b027324863f8883fb0","src/matchers/gt_matcher.rs":"4c1fd646ac87f7525b3d080e78c6abf935bed50221e4dfd4339e8b75935af115","src/matchers/has_entry_matcher.rs":"3b43e0e6a24890a94910be35f0fd0c25fac602fa660d44303d769f7bd00145be","src/matchers/is_encoded_string_matcher.rs":"6519057f21db928c6dbb4d62eb7d695e992df1d660a16dbabd0c7bb73fb65113","src/matchers/is_matcher.rs":"4e842d665eb710540fbf7b274755d665727ff01f51bee57e9b2697f6aec90cd7","src/matchers/is_nan_matcher.rs":"9972b43fd35c47b89755d8ec176631f76b6cfec725d8972caed277369fc74493","src/matchers/le_matcher.rs":"108581b0fb4d9141e5aa0ec3abb640bd2828b5e39b0f3793bd767cba4eca3afb","src/matchers/len_matcher.rs":"f7312f738fc644ba942a15b017285cfc67a2458c815d5ce29e56cca307b6f357","src/matchers/lt_matcher.rs":"5966f449669160e2905acc0da5db5487d6da580bc96a6e77fb320eb8d4546990","src/matchers/matches_pattern.rs":"9895407b21823da2608be95086605f6bd508510bc987f1a840a495025b574921","src/matchers/matches_regex_matcher.rs":"5fca7eaddbe064c5053a0ebbd9532f8e00ab263101afb3948716fad4aaa0c38f","src/matchers/mod.rs":"0c0d9ca73488df9f9bed475da9d0b60ca69a5d16daf534fef77dd04d40d0290b","src/matchers/near_matcher.rs":"3ec423d88e9d52b518c9892b8271e76789971160c1f28534bce8adc250be5701","src/matchers/none_matcher.rs":"d422658c824f07afe870003383d42b090d9a7a72d539450e7903252a859352b1","src/matchers/not_matcher.rs":"140e0959a25cca75fd3aa41fad0dd71d50753b6b38220ff4a4960f2ef7d295e0","src/matchers/ok_matcher.rs":"2aae736e349bddc84b4cee5699b2e6d21817facdc49a28415a8ff919adea63bb","src/matchers/points_to_matcher.rs":"a1f55e8d9813a3651cc24307923b461f398f761b4a040d00faac623bfffeef82","src/matchers/pointwise_matcher.rs":"3b2ed83dcd216c82063697e03bad998e9c6f2d93f0c18c8edb847b1ceeea2ff4","src/matchers/predicate_matcher.rs":"825896ee6839f9b6a39f971529fc3e33d47b6f4abece86eaf911aff2af2e795e","src/matchers/property_matcher.rs":"d65d1bd8059cead41ce81db7c080ec639cf89e8d5846939b34687a1611494b24","src/matchers/result_of_matcher.rs":"fbcb266f7a65921fa799795fef21ab684706cf6b4ab79c2eb09c10c225497b8f","src/matchers/some_matcher.rs":"9ee7282180400476c39e7f43d5f028e93442423142665ecd23c397e5bd40c935","src/matchers/str_matcher.rs":"a10443574eec5c5e33c93e6208651a5f0b865a9a200517bf2e4d1f12c792a424","src/matchers/subset_of_matcher.rs":"e0966351bff9623aa63aaf7ae9403e05e6aabcdd8f4bb9074b19069cb0adff6b","src/matchers/superset_of_matcher.rs":"fd5af81f7eb390e6b6fc1c61b79963d3220d6505615171737b566e06eb441e9e","src/matchers/tuple_matcher.rs":"d00eb6fecd1d5671418e3bbe62c67f422b6a945ee1276e16edc1402c8e4f2edb","src/matchers/unordered_elements_are_matcher.rs":"fed9b464ee1597737a1ed86cd5fa0aeeb566fbd0ef3b00cc839988c3c2eb3dbc","tests/all_matcher_test.rs":"1808617e4f59b9e7ad001c45d5653d5389e761347ae4194f221767e5e6b5b7ab","tests/any_matcher_test.rs":"0ce6aa6de318e0e1f0976a04b1581f012001a9afdc1474c3a460e844e8b4f97e","tests/assertions_test.rs":"3425e5fc54a13034069305a9c30ee5fe7b9c5766a2a75d5dca721a3456b08211","tests/colorized_diff_test.rs":"01e9b2fe99aced6aad0281ba18f2442cf036e654b5fbf6c937dd957572e3ab95","tests/composition_test.rs":"bda4157c7a68001eddaabba788c72ce2db86645225cf47a105661799346eced7","tests/elements_are_matcher_test.rs":"decdfa0388dc76703ef2105fceea2bb70cc1e01c04a27208f8e68e8d6fc069af","tests/field_matcher_test.rs":"f82c36f3662e8798b7eaa7dec04b936fac2e74692cdbb90c305ae7ae41347254","tests/fmt_test.rs":"56796a45c9666bc08c7a88e62bdab9ed98b6f1d7adf0727e85c9c5bf2ebd7c31","tests/lib.rs":"e783f3e4908cb080721bdaf72ab4b6e1fb2165b5f4fb0f4baa179ad5c06dfe0f","tests/matches_pattern_test.rs":"bd5dfe2019828ae1df891f88d487bc64bb1a8ccf086fa05b28d4ddd2a785cfb5","tests/no_color_test.rs":"1bbca449ae5bdc261c96879bf5298e60b589947634bc6f8b9bdcbefdd13241a3","tests/pointwise_matcher_test.rs":"cf3e0c13c32a5e891fa47fe765e744a8d1652acc783cac9b4f0e501562df0877","tests/property_matcher_test.rs":"4461d54abaaa5135e371c516ce9b22c4b1bd187d25fea18d96562adaaf8a2839","tests/proptest_integration_test.rs":"948f4d59b7f325faa522e53f3c8a4542be349f368cb790a39c157eb6c7b47014","tests/tuple_matcher_test.rs":"cfa703ef99a2cafedb5cec8d8920fe2d146f17b0e9e1d894d473083d9d408d65","tests/unordered_elements_are_matcher_test.rs":"2fa8dbdd170567b8d02f46427b1ad5533a3f1737e0adb4fe6340b3f3dba110c7"},"package":"dce026f84cdd339bf71be01b24fe67470ee634282f68c1c4b563d00a9f002b05"}
\ No newline at end of file
diff --git a/crates/googletest/Android.bp b/crates/googletest/Android.bp
index bd6d8f8..4ebc3a8 100644
--- a/crates/googletest/Android.bp
+++ b/crates/googletest/Android.bp
@@ -18,7 +18,7 @@
     host_supported: true,
     crate_name: "googletest",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.11.0",
+    cargo_pkg_version: "0.13.0",
     crate_root: "src/lib.rs",
     edition: "2021",
     rustlibs: [
diff --git a/crates/googletest/Cargo.toml b/crates/googletest/Cargo.toml
index ed9d01c..b1d26ae 100644
--- a/crates/googletest/Cargo.toml
+++ b/crates/googletest/Cargo.toml
@@ -11,15 +11,20 @@
 
 [package]
 edition = "2021"
-rust-version = "1.66.0"
+rust-version = "1.70.0"
 name = "googletest"
-version = "0.11.0"
+version = "0.13.0"
 authors = [
     "Bradford Hovinen <hovinen@google.com>",
     "Bastien Jacot-Guillarmod <bjacotg@google.com>",
     "Maciej Pietrzak <mpi@google.com>",
     "Martin Geisler <mgeisler@google.com>",
 ]
+build = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
 description = "A rich assertion and matcher library inspired by GoogleTest for C++"
 readme = "README.md"
 keywords = [
@@ -35,12 +40,80 @@
 license = "Apache-2.0"
 repository = "https://github.com/google/googletest-rust"
 
+[lib]
+name = "googletest"
+path = "src/lib.rs"
+
+[[test]]
+name = "all_matcher_test"
+path = "tests/all_matcher_test.rs"
+
+[[test]]
+name = "any_matcher_test"
+path = "tests/any_matcher_test.rs"
+
+[[test]]
+name = "assertions_test"
+path = "tests/assertions_test.rs"
+
+[[test]]
+name = "colorized_diff_test"
+path = "tests/colorized_diff_test.rs"
+
+[[test]]
+name = "composition_test"
+path = "tests/composition_test.rs"
+
+[[test]]
+name = "elements_are_matcher_test"
+path = "tests/elements_are_matcher_test.rs"
+
+[[test]]
+name = "field_matcher_test"
+path = "tests/field_matcher_test.rs"
+
+[[test]]
+name = "fmt_test"
+path = "tests/fmt_test.rs"
+
+[[test]]
+name = "lib"
+path = "tests/lib.rs"
+
+[[test]]
+name = "matches_pattern_test"
+path = "tests/matches_pattern_test.rs"
+
+[[test]]
+name = "no_color_test"
+path = "tests/no_color_test.rs"
+
+[[test]]
+name = "pointwise_matcher_test"
+path = "tests/pointwise_matcher_test.rs"
+
+[[test]]
+name = "property_matcher_test"
+path = "tests/property_matcher_test.rs"
+
+[[test]]
+name = "proptest_integration_test"
+path = "tests/proptest_integration_test.rs"
+
+[[test]]
+name = "tuple_matcher_test"
+path = "tests/tuple_matcher_test.rs"
+
+[[test]]
+name = "unordered_elements_are_matcher_test"
+path = "tests/unordered_elements_are_matcher_test.rs"
+
 [dependencies.anyhow]
 version = "1"
 optional = true
 
 [dependencies.googletest_macro]
-version = "0.11.0"
+version = "0.13.0"
 
 [dependencies.num-traits]
 version = "0.2.17"
@@ -60,6 +133,3 @@
 
 [dev-dependencies.quickcheck]
 version = "1.0.3"
-
-[dev-dependencies.serial_test]
-version = "2.0.0"
diff --git a/crates/googletest/METADATA b/crates/googletest/METADATA
index 8b0b3e2..4b1ad07 100644
--- a/crates/googletest/METADATA
+++ b/crates/googletest/METADATA
@@ -1,17 +1,17 @@
 name: "googletest"
 description: "A rich assertion and matcher library inspired by GoogleTest for C++"
 third_party {
-  version: "0.11.0"
+  version: "0.13.0"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2024
-    month: 2
-    day: 2
+    year: 2025
+    month: 1
+    day: 3
   }
   homepage: "https://crates.io/crates/googletest"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/googletest/googletest-0.11.0.crate"
-    version: "0.11.0"
+    value: "https://static.crates.io/crates/googletest/googletest-0.13.0.crate"
+    version: "0.13.0"
   }
 }
diff --git a/crates/googletest/README.md b/crates/googletest/README.md
index d442770..c611e79 100644
--- a/crates/googletest/README.md
+++ b/crates/googletest/README.md
@@ -25,7 +25,7 @@
  * A new set of assertion macros offering similar functionality to those of
    [GoogleTest](https://google.github.io/googletest/primer.html#assertions).
 
-**The minimum supported Rust version is 1.66**.
+**The minimum supported Rust version is 1.70**.
 
 > :warning: The API is not fully stable and may still be changed until we
 > publish version 1.0.
@@ -34,6 +34,15 @@
 > not be used directly. Those items or modules are only for internal uses and
 > their API may change without a major version update.
 
+## Learning resources
+
+If you're just getting started with `googletest`, consider going through
+the first chapter of
+["Advanced testing for Rust applications"](https://github.com/mainmatter/rust-advanced-testing-workshop),
+a self-guided Rust course: it provides a guided introduction to the library,
+with exercises to help you get comfortable with `googletest` macros,
+its matchers and its overall philosophy.
+
 ## Assertions and matchers
 
 The core of GoogleTest is its *matchers*. Matchers indicate what aspect of an
@@ -45,7 +54,7 @@
  * [`assert_that!`] panics if the assertion fails, aborting the test.
  * [`expect_that!`] logs an assertion failure, marking the test as having
    failed, but allows the test to continue running (called a _non-fatal
-   assertion_). It requires the use of the [`googletest::test`] attribute macro
+   assertion_). It requires the use of the [`gtest`] attribute macro
    on the test itself.
  * [`verify_that!`] has no side effects and evaluates to a [`Result<()>`] whose
    `Err` variant describes the assertion failure, if there is one. In
@@ -65,7 +74,7 @@
     assert_that!(value, eq(4));
 }
 
-#[googletest::test]
+#[gtest]
 fn two_logged_failures() {
     let value = 2;
     expect_that!(value, eq(4)); // Test now failed, but continues executing.
@@ -98,7 +107,7 @@
 ```rust
 use googletest::prelude::*;
 
-#[googletest::test]
+#[gtest]
 fn contains_at_least_one_item_at_least_3() {
     let value = vec![1, 2, 3];
     expect_that!(value, contains(ge(3)));
@@ -110,7 +119,7 @@
 ```rust
 use googletest::prelude::*;
 
-#[googletest::test]
+#[gtest]
 fn strictly_between_9_and_11() {
     let value = 10;
     expect_that!(value, gt(9).and(not(ge(11))));
@@ -156,11 +165,9 @@
     expected: T,
 }
 
-impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
-    type ActualT = T;
-
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
-         (self.expected == *actual).into()
+impl<T: PartialEq + Debug + Copy> Matcher<T> for MyEqMatcher<T> {
+    fn matches(&self, actual: T) -> MatcherResult {
+         (self.expected == actual).into()
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> String {
@@ -179,7 +186,7 @@
 It is recommended to expose a function which constructs the matcher:
 
 ```rust
-pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<ActualT = T> {
+pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<T> {
     MyEqMatcher { expected }
 }
 ```
@@ -187,7 +194,7 @@
 The new matcher can then be used in the assertion macros:
 
 ```rust
-#[googletest::test]
+#[gtest]
 fn should_be_equal_by_my_definition() {
     expect_that!(10, eq_my_way(10));
 }
@@ -202,12 +209,12 @@
 This is analogous to the `EXPECT_*` family of macros in GoogleTest.
 
 To make a non-fatal assertion, use the macro [`expect_that!`]. The test must
-also be marked with [`googletest::test`] instead of the Rust-standard `#[test]`.
+also be marked with [`gtest`] instead of the Rust-standard `#[test]`.
 
 ```rust
 use googletest::prelude::*;
 
-#[googletest::test]
+#[gtest]
 fn three_non_fatal_assertions() {
     let value = 2;
     expect_that!(value, eq(2));  // Passes; test still considered passing.
@@ -222,7 +229,7 @@
 ```rust
 use googletest::prelude::*;
 
-#[googletest::test]
+#[gtest]
 fn failing_non_fatal_assertion() -> Result<()> {
     let value = 2;
     expect_that!(value, eq(3));  // Just marks the test as having failed.
@@ -235,7 +242,7 @@
 ```rust
 use googletest::prelude::*;
 
-#[googletest::test]
+#[gtest]
 fn failing_fatal_assertion_after_non_fatal_assertion() -> Result<()> {
     let value = 2;
     verify_that!(value, eq(3))?; // Fails and aborts the test.
@@ -246,12 +253,12 @@
 
 ### Interoperability
 
-You can use the `#[googletest::test]` macro together with many other libraries
+You can use the `#[gtest]` macro together with many other libraries
 such as [rstest](https://crates.io/crates/rstest). Just apply both attribute
 macros to the test:
 
 ```rust
-#[googletest::test]
+#[gtest]
 #[rstest]
 #[case(1)]
 #[case(2)]
@@ -261,16 +268,16 @@
 }
 ```
 
-Make sure to put `#[googletest::test]` *before* `#[rstest]`. Otherwise the
+Make sure to put `#[gtest]` *before* `#[rstest]`. Otherwise the
 annotated test will run twice, since both macros will attempt to register a test
 with the Rust test harness.
 
 The macro also works together with
-[async tests with Tokio](https://docs.rs/tokio/latest/tokio/attr.test.html) in
+[async tests with Tokio](https://docs.rs/tokio/latest/tokio/attr.gtest.html) in
 the same way:
 
 ```rust
-#[googletest::test]
+#[gtest]
 #[tokio::test]
 async fn should_work_with_tokio() -> Result<()> {
     verify_that!(3, gt(0))
@@ -348,7 +355,7 @@
 [`expect_pred!`]: https://docs.rs/googletest/*/googletest/macro.expect_pred.html
 [`expect_that!`]: https://docs.rs/googletest/*/googletest/macro.expect_that.html
 [`fail!`]: https://docs.rs/googletest/*/googletest/macro.fail.html
-[`googletest::test`]: https://docs.rs/googletest/*/googletest/attr.test.html
+[`gtest`]: https://docs.rs/googletest/*/googletest/attr.gtest.html
 [`matches_pattern!`]: https://docs.rs/googletest/*/googletest/macro.matches_pattern.html
 [`verify_pred!`]: https://docs.rs/googletest/*/googletest/macro.verify_pred.html
 [`verify_that!`]: https://docs.rs/googletest/*/googletest/macro.verify_that.html
diff --git a/crates/googletest/crate_docs.md b/crates/googletest/crate_docs.md
index 8c8b47c..3a6b037 100644
--- a/crates/googletest/crate_docs.md
+++ b/crates/googletest/crate_docs.md
@@ -6,6 +6,14 @@
    range of assertions on data,
  * A rich set of matchers, and
  * A new set of test assertion macros.
+## Learning resources
+
+If you're just getting started with `googletest`, consider going through
+the first chapter of
+["Advanced testing for Rust applications"](https://github.com/mainmatter/rust-advanced-testing-workshop),
+a self-guided Rust course: it provides a guided introduction to the library,
+with exercises to help you get comfortable with `googletest` macros,
+its matchers and its overall philosophy.
 
 ## Assertions and matchers
 
@@ -18,7 +26,7 @@
  * [`assert_that!`] panics if the assertion fails, aborting the test.
  * [`expect_that!`] logs an assertion failure, marking the test as having
    failed, but allows the test to continue running (called a _non-fatal
-   assertion_). It requires the use of the [`googletest::test`][crate::test]
+   assertion_). It requires the use of the [`gtest`]
    attribute macro on the test itself.
  * [`verify_that!`] has no side effects and evaluates to a [`Result`] whose
    `Err` variant describes the assertion failure, if there is one. In
@@ -41,7 +49,7 @@
 }
 
 # /* The attribute macro would prevent the function from being compiled in a doctest.
-#[googletest::test]
+#[gtest]
 # */
 fn two_logged_failures() {
     let value = 2;
@@ -74,25 +82,25 @@
 use googletest::prelude::*;
 
 # /* The attribute macro would prevent the function from being compiled in a doctest.
-#[googletest::test]
+#[gtest]
 # */
 fn contains_at_least_one_item_at_least_3() {
 # googletest::internal::test_outcome::TestOutcome::init_current_test_outcome();
     let value = vec![1, 2, 3];
-    expect_that!(value, contains(ge(3)));
+    expect_that!(value, contains(ge(&3)));
 # googletest::internal::test_outcome::TestOutcome::close_current_test_outcome::<&str>(Ok(()))
 #     .unwrap();
 }
 # contains_at_least_one_item_at_least_3();
 ```
 
-They can also be logically combined:
+They can also be logically combined, with methods from [`MatcherBase`]:
 
 ```
 use googletest::prelude::*;
 
 # /* The attribute macro would prevent the function from being compiled in a doctest.
-#[googletest::test]
+#[gtest]
 # */
 fn strictly_between_9_and_11() {
 # googletest::internal::test_outcome::TestOutcome::init_current_test_outcome();
@@ -120,13 +128,13 @@
 | [`contains_each!`]   | A container containing distinct elements each of the arguments match.    |
 | [`contains_regex`]   | A string containing a substring matching the given regular expression.   |
 | [`contains_substring`] | A string containing the given substring.                               |
+| [`derefs_to`]        | A [`Deref`] which `deref()`s to a value that the argument matches.       |
 | [`displays_as`]      | A [`Display`] value whose formatted string is matched by the argument.   |
 | [`each`]             | A container all of whose elements the given argument matches.            |
 | [`elements_are!`]    | A container whose elements the arguments match, in order.                |
 | [`empty`]            | An empty collection.                                                     |
 | [`ends_with`]        | A string ending with the given suffix.                                   |
 | [`eq`]               | A value equal to the argument, in the sense of the [`PartialEq`] trait.  |
-| [`eq_deref_of`]      | A value equal to the dereferenced value of the argument.                 |
 | [`err`]              | A [`Result`][std::result::Result] containing an `Err` variant the argument matches. |
 | [`field!`]           | A struct or enum with a given field whose value the argument matches.    |
 | [`ge`]               | A [`PartialOrd`] value greater than or equal to the given value.         |
@@ -144,7 +152,7 @@
 | [`not`]              | Any value the argument does not match.                                   |
 | [`ok`]               | A [`Result`][std::result::Result] containing an `Ok` variant the argument matches. |
 | [`pat!`]             | Alias for [`matches_pattern!`].                                          |
-| [`points_to`]        | Any [`Deref`] such as `&`, `Rc`, etc. whose value the argument matches.  |
+| [`points_to`]        | A reference `&` which points to a value that the argument matches.       |
 | [`pointwise!`]       | A container whose contents the arguments match in a pointwise fashion.   |
 | [`predicate`]        | A value on which the given predicate returns true.                       |
 | [`some`]             | An [`Option`] containing `Some` whose value the argument matches.        |
@@ -164,12 +172,12 @@
 [`contains_regex`]: matchers::contains_regex
 [`contains_substring`]: matchers::contains_substring
 [`displays_as`]: matchers::displays_as
+[`derefs_to`]: matchers::derefs_to
 [`each`]: matchers::each
 [`elements_are!`]: matchers::elements_are
 [`empty`]: matchers::empty
 [`ends_with`]: matchers::ends_with
 [`eq`]: matchers::eq
-[`eq_deref_of`]: matchers::eq_deref_of
 [`err`]: matchers::err
 [`field!`]: matchers::field
 [`ge`]: matchers::ge
@@ -205,22 +213,21 @@
 ## Writing matchers
 
 One can extend the library by writing additional matchers. To do so, create
-a struct holding the matcher's data and have it implement the trait
-[`Matcher`]:
+a struct holding the matcher's data and have it implement the traits
+[`Matcher`] and  [`MatcherBase`]:
 
 ```no_run
-use googletest::{description::Description, matcher::{Matcher, MatcherResult}};
+use googletest::{description::Description, matcher::{Matcher, MatcherBase, MatcherResult}};
 use std::fmt::Debug;
 
+#[derive(MatcherBase)]
 struct MyEqMatcher<T> {
     expected: T,
 }
 
-impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
-    type ActualT = T;
-
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
-        if self.expected == *actual {
+impl<T: PartialEq + Debug + Copy> Matcher<T> for MyEqMatcher<T> {
+    fn matches(&self, actual: T) -> MatcherResult {
+        if self.expected == actual {
             MatcherResult::Match
         } else {
             MatcherResult::NoMatch
@@ -243,18 +250,16 @@
  It is recommended to expose a function which constructs the matcher:
 
  ```no_run
- # use googletest::{description::Description, matcher::{Matcher, MatcherResult}};
+ # use googletest::{description::Description, matcher::{Matcher, MatcherBase, MatcherResult}};
  # use std::fmt::Debug;
- #
+ # #[derive(MatcherBase)]
  # struct MyEqMatcher<T> {
  #    expected: T,
  # }
  #
- # impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
- #    type ActualT = T;
- #
- #    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
- #        if self.expected == *actual {
+ # impl<T: PartialEq + Debug + Copy> Matcher<T> for MyEqMatcher<T> {
+ #    fn matches(&self, actual: T) -> MatcherResult {
+ #        if self.expected == actual {
  #            MatcherResult::Match
  #        } else {
  #            MatcherResult::NoMatch
@@ -273,7 +278,7 @@
  #    }
  # }
  #
- pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<ActualT = T> {
+ pub fn eq_my_way<T: PartialEq + Debug + Copy>(expected: T) -> impl Matcher<T> {
     MyEqMatcher { expected }
  }
  ```
@@ -282,18 +287,16 @@
 
 ```
 # use googletest::prelude::*;
-# use googletest::{description::Description, matcher::{Matcher, MatcherResult}};
+# use googletest::{description::Description, matcher::{Matcher, MatcherBase, MatcherResult}};
 # use std::fmt::Debug;
-#
+# #[derive(MatcherBase)]
 # struct MyEqMatcher<T> {
 #    expected: T,
 # }
 #
-# impl<T: PartialEq + Debug> Matcher for MyEqMatcher<T> {
-#    type ActualT = T;
-#
-#    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
-#        if self.expected == *actual {
+# impl<T: PartialEq + Debug + Copy> Matcher<T> for MyEqMatcher<T> {
+#    fn matches(&self, actual: T) -> MatcherResult {
+#        if self.expected == actual {
 #            MatcherResult::Match
 #        } else {
 #            MatcherResult::NoMatch
@@ -312,11 +315,11 @@
 #    }
 # }
 #
-# pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<ActualT = T> {
+# pub fn eq_my_way<T: PartialEq + Debug + Copy>(expected: T) -> impl Matcher<T> {
 #    MyEqMatcher { expected }
 # }
 # /* The attribute macro would prevent the function from being compiled in a doctest.
-#[googletest::test]
+#[gtest]
 # */
 fn should_be_equal_by_my_definition() {
 # googletest::internal::test_outcome::TestOutcome::init_current_test_outcome();
@@ -335,13 +338,12 @@
 aborts.
 
 To make a non-fatal assertion, use the macro [`expect_that!`]. The test must
-also be marked with [`googletest::test`][crate::test] instead of the
-Rust-standard `#[test]`.
+also be marked with [`gtest`] instead of the Rust-standard `#[test]`.
 
 ```no_run
 use googletest::prelude::*;
 
-#[googletest::test]
+#[gtest]
 fn three_non_fatal_assertions() {
     let value = 2;
     expect_that!(value, eq(2));  // Passes; test still considered passing.
@@ -357,7 +359,7 @@
 use googletest::prelude::*;
 
 # /* Make sure this also compiles as a doctest.
-#[googletest::test]
+#[gtest]
 # */
 fn failing_non_fatal_assertion() -> Result<()> {
     let value = 2;
@@ -371,7 +373,7 @@
 ```no_run
 use googletest::prelude::*;
 
-#[googletest::test]
+#[gtest]
 fn failing_fatal_assertion_after_non_fatal_assertion() -> Result<()> {
     let value = 2;
     expect_that!(value, eq(2));  // Passes; test still considered passing.
@@ -434,62 +436,98 @@
 # always_fails().unwrap_err();
 ```
 
+## Conversion from `Result::Err` and `Option::None`
+
+To simplify error management during a test arrangement, [`Result<T>`]
+provides a few conversion utilities.
+
+If your setup function returns `std::result::Result<T, E>` where `E: std::error::Error`,
+the `std::result::Result<T, E>` can simply be handled with the `?` operator. If an `Err(e)`
+is returned, the test will report a failure at the line where the `?` operator has been
+applied (or the lowest caller without `#[track_caller]`).
+
+```
+# use googletest::prelude::*;
+struct PngImage { h: i32, w: i32 /* ... */ }
+impl PngImage {
+  fn new_from_file(file_name: &str) -> std::result::Result<Self, std::io::Error> {
+    Err(std::io::Error::new(std::io::ErrorKind::Other, "oh no!"))
+
+   }
+  fn rotate(&mut self) { std::mem::swap(&mut self.h, &mut self.w);}
+  fn dimensions(&self) -> (i32, i32) { (self.h, self.w)}
+}
+
+fn test_png_image_dimensions() -> googletest::Result<()> {
+  // Arrange
+  let mut png = PngImage::new_from_file("example.png")?;
+  verify_eq!(png.dimensions(), (128, 64))?;
+
+  // Act
+  png.rotate();
+
+  // Assert
+  expect_eq!(png.dimensions(), (64, 128));
+  Ok(())
+}
+
+# test_png_image_dimensions().unwrap_err();
+```
+
+If your setup function returns `Option<T>` or `std::result::Result<T, E>` where
+`E: !std::error::Error`, then you can convert these types with `into_test_result()`
+from the `IntoTestResult` extension trait.
+
+```
+# use googletest::prelude::*;
+# struct PngImage;
+# static PNG_BINARY: [u8;0] = [];
+
+impl PngImage {
+  fn new_from_binary(bin: &[u8]) -> std::result::Result<Self, String> {
+    Err("Parsing failed".into())
+  }
+}
+
+# /* The attribute macro would prevent the function from being compiled in a doctest.
+#[gtest]
+# */
+fn test_png_image_binary() -> googletest::Result<()> {
+  // Arrange
+  let png_image = PngImage::new_from_binary(&PNG_BINARY).into_test_result()?;
+  /* ... */
+  # Ok(())
+}
+# test_png_image_binary().unwrap_err();
+
+impl PngImage {
+  fn new_from_cache(key: u64) -> Option<Self> {
+    None
+  }
+}
+
+# /* The attribute macro would prevent the function from being compiled in a doctest.
+#[gtest]
+# */
+fn test_png_from_cache() -> googletest::Result<()> {
+  // Arrange
+  let png_image = PngImage::new_from_cache(123).into_test_result()?;
+  /* ... */
+  # Ok(())
+}
+# test_png_from_cache().unwrap_err();
+```
+
+
 ## Integrations with other crates
 
 GoogleTest Rust includes integrations with the
-[Anyhow](https://crates.io/crates/anyhow) and
 [Proptest](https://crates.io/crates/proptest) crates to simplify turning
-errors from those crates into test failures.
-
-To use this, activate the `anyhow`, respectively `proptest` feature in
-GoogleTest Rust and invoke the extension method [`into_test_result()`] on a
-`Result` value in your test. For example:
-
-```
-# use googletest::prelude::*;
-# #[cfg(feature = "anyhow")]
-# use anyhow::anyhow;
-# #[cfg(feature = "anyhow")]
-# /* The attribute macro would prevent the function from being compiled in a doctest.
-#[test]
-# */
-fn has_anyhow_failure() -> Result<()> {
-    Ok(just_return_error().into_test_result()?)
-}
-
-# #[cfg(feature = "anyhow")]
-fn just_return_error() -> anyhow::Result<()> {
-    anyhow::Result::Err(anyhow!("This is an error"))
-}
-# #[cfg(feature = "anyhow")]
-# has_anyhow_failure().unwrap_err();
-```
-
-One can convert Proptest test failures into GoogleTest test failures when the
-test is invoked with
-[`TestRunner::run`](https://docs.rs/proptest/latest/proptest/test_runner/struct.TestRunner.html#method.run):
-
-```
-# use googletest::prelude::*;
-# #[cfg(feature = "proptest")]
-# use proptest::test_runner::{Config, TestRunner};
-# #[cfg(feature = "proptest")]
-# /* The attribute macro would prevent the function from being compiled in a doctest.
-#[test]
-# */
-fn numbers_are_greater_than_zero() -> Result<()> {
-    let mut runner = TestRunner::new(Config::default());
-    runner.run(&(1..100i32), |v| Ok(verify_that!(v, gt(0))?)).into_test_result()
-}
-# #[cfg(feature = "proptest")]
-# numbers_are_greater_than_zero().unwrap();
-```
-
-Similarly, when the `proptest` feature is enabled, GoogleTest assertion failures
-can automatically be converted into Proptest
+GoogleTest assertion failures into Proptest
 [`TestCaseError`](https://docs.rs/proptest/latest/proptest/test_runner/enum.TestCaseError.html)
-through the `?` operator as the example above shows.
+through the `?` operator.
 
 [`and_log_failure()`]: GoogleTestSupport::and_log_failure
 [`into_test_result()`]: IntoTestResult::into_test_result
 [`Matcher`]: matcher::Matcher
+[`MatcherBase`]: matcher::MatcherBase
diff --git a/crates/googletest/src/assertions.rs b/crates/googletest/src/assertions.rs
index 2668028..ac5177e 100644
--- a/crates/googletest/src/assertions.rs
+++ b/crates/googletest/src/assertions.rs
@@ -120,29 +120,37 @@
 /// not supported; see [Rust by Example](https://doc.rust-lang.org/rust-by-example/primitives/tuples.html#tuples).
 #[macro_export]
 macro_rules! verify_that {
+    // specialized to sequences:
     ($actual:expr, [$($expecteds:expr),+ $(,)?]) => {
-        $crate::assertions::internal::check_matcher(
-            &$actual,
-            $crate::matchers::elements_are![$($expecteds),+],
-            stringify!($actual),
-            $crate::internal::source_location::SourceLocation::new(file!(), line!(), column!()),
-        )
+        {
+            use $crate::assertions::internal::Subject as _;
+            $actual.check(
+                $crate::matchers::elements_are![$($expecteds),+],
+                stringify!($actual),
+            )
+        }
     };
+
+    // specialized to unordered sequences:
     ($actual:expr, {$($expecteds:expr),+ $(,)?}) => {
-        $crate::assertions::internal::check_matcher(
-            &$actual,
-            $crate::matchers::unordered_elements_are![$($expecteds),+],
-            stringify!($actual),
-            $crate::internal::source_location::SourceLocation::new(file!(), line!(), column!()),
-        )
+        {
+            use $crate::assertions::internal::Subject as  _;
+            $actual.check(
+                $crate::matchers::unordered_elements_are![$($expecteds),+],
+                stringify!($actual),
+            )
+        }
     };
+
+    // general case:
     ($actual:expr, $expected:expr $(,)?) => {
-        $crate::assertions::internal::check_matcher(
-            &$actual,
-            $expected,
-            stringify!($actual),
-            $crate::internal::source_location::SourceLocation::new(file!(), line!(), column!()),
-        )
+        {
+            use $crate::assertions::internal::Subject as  _;
+            $actual.check(
+                $expected,
+                stringify!($actual),
+            )
+        }
     };
 }
 
@@ -165,30 +173,25 @@
 /// # */
 /// fn test() -> Result<()> {
 ///     let a = 1;
-///     let b = 7;
-///     let n = 5;
-///     verify_pred!(equals_modulo(a, b, n))?;
+///     fn b(_x: i32) -> i32 { 7 }
+///     verify_pred!(equals_modulo(a, b(b(2)), 2 + 3))?;
 ///     Ok(())
 /// }
 /// # verify_that!(
 /// #     test(),
-/// #     err(displays_as(contains_substring("equals_modulo(a, b, n) was false with")))
+/// #     err(displays_as(contains_substring("equals_modulo(a, b(b(2)), 2 + 3) was false with")))
 /// # ).unwrap();
 /// ```
 ///
 /// This results in the following message:
 ///
 /// ```text
-/// equals_modulo(a, b, n) was false with
+/// equals_modulo(a, b(b(2)), 2 + 3) was false with
 ///   a = 1,
-///   b = 7,
-///   n = 5
+///   b(b(2)) = 7,
+///   2 + 3 = 5,
 /// ```
 ///
-/// The function passed to this macro must return `bool`. Each of the arguments
-/// must evaluate to a type implementing [`std::fmt::Debug`]. The debug output
-/// is used to construct the failure message.
-///
 /// The predicate can also be a method on a struct, e.g.:
 ///
 /// ```ignore
@@ -201,42 +204,45 @@
 /// verify_pred!((AStruct {}).equals_modulo(a, b, n))?;
 /// ```
 ///
-/// **Warning:** This macro assumes that the arguments passed to the predicate
-/// are either *variables* or *calls to pure functions*. If two subsequent
-/// invocations to any of the expresssions passed as arguments result in
-/// different values, then the output message of a test failure will deviate
-/// from the values actually passed to the predicate. For this reason, *always
-/// assign the outputs of non-pure functions to variables before using them in
-/// this macro. For example:
+/// The expression passed to this macro must return `bool`. In the most general
+/// case, it prints out each of the `.`-separated parts of the expression and
+/// the arguments of all top-level method calls as long as they implement
+/// `Debug`. It evaluates every value (including the method receivers) exactly
+/// once. Effectively, for `verify_pred!((a + 1).b.c(x + y, &mut z, 2))`, it
+/// generates code analogous to the following, which allows printing accurate
+/// intermediate values even if they are subsequently consumed (moved out) or
+/// mutated in-place by the expression:
 ///
 /// ```ignore
-/// let output = generate_random_number();  // Assigned outside of verify_pred.
-/// verify_pred!(is_sufficiently_random(output))?;
+/// let mut error_message = "(a + 1).b.c(x + y, 2) was false with".to_string();
+/// let mut x1 = (a + 1);
+/// write!(error_message, "\n  (a + 1) = {:?},", x1);
+/// write!(error_message, "\n  (a + 1).b = {:?},", x1.b);
+/// let mut x2 = x + y;
+/// write!(error_message, "\n  x + y = {:?},", x2);
+/// let mut x3 = &mut z;
+/// write!(error_message, "\n  & mut z = {:?},", x3);
+/// let mut x4 = x1.b.c(x2, x3, 2);
+/// if (x4) {
+///   Ok(())
+/// } else {
+///   Err(error_message)
+/// }
 /// ```
+///
+/// Wrapping the passed-in expression in parens or curly braces will prevent the
+/// detailed printing of the expression.
+///
+/// ```ignore
+/// verify_pred!((a.foo()).bar())?;
+/// ```
+///
+/// would not print `a`, but would print `(a.foo())` and `(a.foo()).bar()` on
+/// error.
 #[macro_export]
 macro_rules! verify_pred {
-    ([$($predicate:tt)*]($($arg:tt),* $(,)?)) => {
-        if !$($predicate)*($($arg),*) {
-            $crate::assertions::internal::report_failed_predicate(
-                concat!(stringify!($($predicate)*), stringify!(($($arg),*))),
-                vec![$((format!(concat!(stringify!($arg), " = {:?}"), $arg))),*],
-                $crate::internal::source_location::SourceLocation::new(
-                    file!(),
-                    line!(),
-                    column!(),
-                ),
-            )
-        } else {
-            Ok(())
-        }
-    };
-
-    ([$($predicate:tt)*] $first:tt $($rest:tt)*) => {
-        $crate::verify_pred!([$($predicate)* $first] $($rest)*)
-    };
-
-    ($first:tt $($rest:tt)*) => {
-        $crate::verify_pred!([$first] $($rest)*)
+    ($expr:expr $(,)?) => {
+        $crate::assertions::internal::__googletest_macro_verify_pred!($expr)
     };
 }
 
@@ -285,27 +291,978 @@
 /// [`and_log_failure`](crate::GoogleTestSupport::and_log_failure).
 #[macro_export]
 macro_rules! fail {
-    ($($message:expr),+) => {{
-        // We wrap this in a function so that we can annotate it with the must_use attribute.
-        // must_use on expressions is still experimental.
-        #[must_use = "The assertion result must be evaluated to affect the test result."]
-        fn create_fail_result(message: String) -> $crate::Result<()> {
-            Err($crate::internal::test_outcome::TestAssertionFailure::create(format!(
-                "{}\n{}",
-                message,
-                $crate::internal::source_location::SourceLocation::new(
-                    file!(),
-                    line!(),
-                    column!(),
-                ),
-            )))
-        }
-        create_fail_result(format!($($message),*))
+    ($($message:expr),+ $(,)?) => {{
+        $crate::assertions::internal::create_fail_result(
+            format!($($message),*),
+        )
     }};
 
     () => { fail!("Test failed") };
 }
 
+/// Generates a success. This **does not** make the overall test succeed. A test
+/// is only considered successful if none of its assertions fail during its
+/// execution.
+///
+/// The succeed!() assertion is purely documentary. The only user visible output
+/// is a stdout with information on where the success was generated from.
+///
+/// ```ignore
+/// fn test_to_be_implemented() {
+///     succeed!();
+/// }
+/// ```
+///
+/// One may include formatted arguments in the success message:
+///
+/// ```ignore
+/// fn test_to_be_implemented() {
+///     succeed!("I am just a fake test: {}", "a fake test indeed");
+/// }
+/// ```
+#[macro_export]
+macro_rules! succeed {
+    ($($message:expr),+ $(,)?) => {{
+        println!(
+            "{}\n at {}:{}:{}",
+            format!($($message),*),
+            file!(), line!(), column!()
+        );
+    }};
+
+    () => {
+        succeed!("Success")
+    };
+}
+
+/// Generates a failure marking the test as failed but continue execution.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail_but_not_abort() {
+///     add_failure!();
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail_but_not_abort() {
+///     add_failure!("I am just a fake test: {}", "a fake test indeed");
+/// }
+/// ```
+#[macro_export]
+macro_rules! add_failure {
+    ($($message:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        $crate::assertions::internal::create_fail_result(
+            format!($($message),*),
+        ).and_log_failure();
+    }};
+
+    () => {
+        add_failure!("Failed")
+    };
+}
+
+/// Generates a failure at specified location marking the test as failed but
+/// continue execution.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail_but_not_abort() {
+///     add_failure_at!("src/my_file.rs", 32, 12);
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail_but_not_abort() {
+///     add_failure_at!(
+///         "src/my_file.rs",
+///         32,
+///         12,
+///         "I am just a fake test: {}", "a fake test indeed",
+///     );
+/// }
+/// ```
+#[macro_export]
+macro_rules! add_failure_at {
+    ($file:expr, $line:expr, $column:expr, $($message:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        $crate::assertions::internal::create_fail_result(
+            format!($($message),*),
+        ).map_err(|e| e.with_fake_location($file, $line, $column)).and_log_failure();
+    }};
+
+    ($file:expr, $line:expr, $column:expr $(,)?) => {
+        add_failure_at!($file, $line, $column, "Failed")
+    };
+}
+
+/// Verify if the condition evaluates to true and returns `Result`.
+///
+/// Evaluates to `Result::Ok(())` if the condition is true and
+/// `Result::Err(TestAssertionFailure)` if it evaluates to false. The caller
+/// must then decide how to handle the `Err` variant. It has a few options:
+///   * Abort the current function with the `?` operator. This requires that the
+///     function return a suitable `Result`.
+///   * Log the failure and continue by calling the method `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_true!(2 + 2 == 5)
+/// }
+/// ```
+#[macro_export]
+macro_rules! verify_true {
+    ($condition:expr) => {{
+        use $crate::assertions::internal::Subject as _;
+        ($condition).check($crate::matchers::eq(true), stringify!($condition))
+    }};
+}
+
+/// Marks test as failed and continue execution if the expression evaluates to
+/// false.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_true!(2 + 2 == 5);
+///     println!("This will print");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_true {
+    ($condition:expr) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_true!($condition).and_log_failure()
+    }};
+}
+
+/// Verify if the condition evaluates to false and returns `Result`.
+///
+/// Evaluates to `Result::Ok(())` if the condition is false and
+/// `Result::Err(TestAssertionFailure)` if it evaluates to true. The caller
+/// must then decide how to handle the `Err` variant. It has a few options:
+///   * Abort the current function with the `?` operator. This requires that the
+///     function return a suitable `Result`.
+///   * Log the failure and continue by calling the method `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_false!(2 + 2 == 4)
+/// }
+/// ```
+#[macro_export]
+macro_rules! verify_false {
+    ($condition:expr) => {{
+        use $crate::assertions::internal::Subject as _;
+        ($condition).check($crate::matchers::eq(false), stringify!($condition))
+    }};
+}
+
+/// Marks test as failed and continue execution if the expression evaluates to
+/// true.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_false!(2 + 2 == 4);
+///     println!("This will print");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_false {
+    ($condition:expr) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_false!($condition).and_log_failure()
+    }};
+}
+
+/// Checks whether the second argument is equal to the first argument.
+///
+/// Evaluates to `Result::Ok(())` if they are equal and
+/// `Result::Err(TestAssertionFailure)` if they are not. The caller must then
+/// decide how to handle the `Err` variant. It has a few options:
+///  * Abort the current function with the `?` operator. This requires that the
+///    function return a suitable `Result`.
+///  * Log the test failure and continue by calling the method
+///    `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_eq!(2, 1)
+/// }
+/// ```
+///
+/// This macro has special support for matching against container. Namely:
+///  * `verify_eq!(actual, [e1, e2, ...])` is equivalent to
+///    `verify_that!(actual, elements_are![eq(e1), eq(e2), ...])`
+///  * `verify_eq!(actual, {e1, e2, ...})` is equivalent to
+///    `verify_that!(actual, unordered_elements_are![eq(e1), eq(e2), ...])`
+#[macro_export]
+macro_rules! verify_eq {
+    // Specialization for ordered sequences of tuples:
+    ($actual:expr, [ $( ( $($tuple_elt:expr),* ) ),+ $(,)? ] $(,)?) => {
+        verify_that!(&$actual, [
+            $(
+                // tuple matching
+                (
+                    $(
+                        $crate::matchers::eq(&$tuple_elt)
+                    ),*
+                )
+            ),*
+        ])
+    };
+
+    // Specialization for unordered sequences of tuples:
+    ($actual:expr, { $( ( $($tuple_elt:expr),* ) ),+ $(,)?} $(,)?) => {
+        verify_that!(&$actual, {
+            $(
+                // tuple matching
+                (
+                    $(
+                        $crate::matchers::eq(&$tuple_elt)
+                    ),*
+                )
+            ),*
+        })
+    };
+
+    // Ordered sequences:
+    ($actual:expr, [$($expected:expr),+ $(,)?] $(,)?) => {
+        verify_that!(&$actual, [$($crate::matchers::eq(&$expected)),*])
+    };
+
+    // Unordered sequences:
+    ($actual:expr, {$($expected:expr),+ $(,)?} $(,)?) => {
+        verify_that!(&$actual, {$($crate::matchers::eq(&$expected)),*})
+    };
+
+    // General case:
+    ($actual:expr, $expected:expr $(,)?) => {
+        verify_that!(&$actual, $crate::matchers::eq(&$expected))
+    };
+}
+
+/// Marks test as failed and continues execution if the second argument is not
+/// equal to first argument.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_eq!(2, 1);
+///     println!("This will print!");
+/// }
+/// ```
+///
+/// This macro has special support for matching against container. Namely:
+///  * `expect_eq!(actual, [e1, e2, ...])` for checking actual contains "e1, e2,
+///    ..." in order.
+///  * `expect_eq!(actual, {e1, e2, ...})` for checking actual contains "e1, e2,
+///    ..." in any order.
+///
+/// One may include formatted arguments in the failure message:
+///```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     let argument = "argument"
+///     expect_eq!(2, 1, "custom failure message: {argument}");
+///     println!("This will print!");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_eq {
+    ($actual:expr, [$($expected:expr),+ $(,)?] $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_eq!($actual, [$($expected),*]).and_log_failure();
+    }};
+    ($actual:expr, [$($expected:expr),+ $(,)?], $($format_args:expr),* $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_eq!($actual, [$($expected),*])
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, {$($expected:expr),+ $(,)?} $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_eq!($actual, {$($expected),*}).and_log_failure();
+    }};
+    ($actual:expr, {$($expected:expr),+ $(,)?}, $($format_args:expr),* $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_eq!($actual, {$($expected),*})
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, $expected:expr $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_eq!($actual, $expected).and_log_failure();
+    }};
+    ($actual:expr, $expected:expr, $($format_args:expr),* $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_eq!($actual, $expected)
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+}
+
+/// Checks whether the second argument is not equal to the first argument.
+///
+/// Evaluates to `Result::Ok(())` if they are not equal and
+/// `Result::Err(TestAssertionFailure)` if they are equal. The caller must then
+/// decide how to handle the `Err` variant. It has a few options:
+///  * Abort the current function with the `?` operator. This requires that the
+///    function return a suitable `Result`.
+///  * Log the test failure and continue by calling the method
+///    `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_ne!(1, 1)
+/// }
+/// ```
+#[macro_export]
+macro_rules! verify_ne {
+    ($actual:expr, $expected:expr $(,)?) => {
+        verify_that!(&$actual, $crate::matchers::not($crate::matchers::eq(&$expected)))
+    };
+}
+
+/// Marks test as failed and continues execution if the second argument is
+/// equal to first argument.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_ne!(1, 1);
+///     println!("This will print!");
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     let argument = "argument"
+///     expect_ne!(1, 1, "custom failure message: {argument}");
+///     println!("This will print!");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_ne {
+    ($actual:expr, $expected:expr, $($format_args:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_ne!($actual, $expected)
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, $expected:expr $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_ne!($actual, $expected).and_log_failure();
+    }};
+}
+
+/// Checks whether the first argument is less than second argument.
+///
+/// Evaluates to `Result::Ok(())` if the first argument is less than the second
+/// and `Result::Err(TestAssertionFailure)` if it is greater or equal. The
+/// caller must then decide how to handle the `Err` variant. It has a few
+/// options:
+///  * Abort the current function with the `?` operator. This requires that the
+///    function return a suitable `Result`.
+///  * Log the test failure and continue by calling the method
+///    `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_lt!(2, 1)
+/// }
+#[macro_export]
+macro_rules! verify_lt {
+    ($actual:expr, $expected:expr $(,)?) => {
+        verify_that!($actual, $crate::matchers::lt($expected))
+    };
+}
+
+/// Marks test as failed and continues execution if the first argument is
+/// greater or equal to second argument.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_lt!(2, 1);
+///     println!("This will print!");
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     let argument = "argument"
+///     expect_lt!(1, 1, "custom failure message: {argument}");
+///     println!("This will print!");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_lt {
+    ($actual:expr, $expected:expr, $($format_args:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_lt!($actual, $expected)
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, $expected:expr $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_lt!($actual, $expected).and_log_failure();
+    }};
+}
+
+/// Checks whether the first argument is less than or equal to the second
+/// argument.
+///
+/// Evaluates to `Result::Ok(())` if the first argument is less than or equal to
+/// the second and `Result::Err(TestAssertionFailure)` if it is greater. The
+/// caller must then decide how to handle the `Err` variant. It has a few
+/// options:
+///  * Abort the current function with the `?` operator. This requires that the
+///    function return a suitable `Result`.
+///  * Log the test failure and continue by calling the method
+///    `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_le!(2, 1)
+/// }
+#[macro_export]
+macro_rules! verify_le {
+    ($actual:expr, $expected:expr $(,)?) => {
+        verify_that!($actual, $crate::matchers::le($expected))
+    };
+}
+
+/// Marks test as failed and continues execution if the first argument is
+/// greater than the second argument.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_le!(2, 1);
+///     println!("This will print!");
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     let argument = "argument"
+///     expect_le!(2, 1, "custom failure message: {argument}");
+///     println!("This will print!");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_le {
+    ($actual:expr, $expected:expr, $($format_args:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_le!($actual, $expected)
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, $expected:expr $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_le!($actual, $expected).and_log_failure();
+    }};
+}
+
+/// Checks whether the first argument is greater than the second argument.
+///
+/// Evaluates to `Result::Ok(())` if the first argument is greater than
+/// the second and `Result::Err(TestAssertionFailure)` if it is not. The
+/// caller must then decide how to handle the `Err` variant. It has a few
+/// options:
+///  * Abort the current function with the `?` operator. This requires that the
+///    function return a suitable `Result`.
+///  * Log the test failure and continue by calling the method
+///    `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_gt!(1, 2)
+/// }
+#[macro_export]
+macro_rules! verify_gt {
+    ($actual:expr, $expected:expr $(,)?) => {
+        verify_that!($actual, $crate::matchers::gt($expected))
+    };
+}
+
+/// Marks test as failed and continues execution if the first argument is
+/// not greater than the second argument.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_gt!(1, 2);
+///     println!("This will print!");
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     let argument = "argument"
+///     expect_gt!(1, 2, "custom failure message: {argument}");
+///     println!("This will print!");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_gt {
+    ($actual:expr, $expected:expr, $($format_args:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_gt!($actual, $expected)
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, $expected:expr $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_gt!($actual, $expected).and_log_failure();
+    }};
+}
+
+/// Checks whether the first argument is greater than or equal to the second
+/// argument.
+///
+/// Evaluates to `Result::Ok(())` if the first argument is greater than or equal
+/// to the second and `Result::Err(TestAssertionFailure)` if it is not. The
+/// caller must then decide how to handle the `Err` variant. It has a few
+/// options:
+///  * Abort the current function with the `?` operator. This requires that the
+///    function return a suitable `Result`.
+///  * Log the test failure and continue by calling the method
+///    `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_ge!(1, 2)
+/// }
+/// ```
+#[macro_export]
+macro_rules! verify_ge {
+    ($actual:expr, $expected:expr $(,)?) => {
+        verify_that!($actual, $crate::matchers::ge($expected))
+    };
+}
+
+/// Marks test as failed and continues execution if the first argument is
+/// not greater than or equal to the second argument.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_ge!(1, 2);
+///     println!("This will print!");
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     let argument = "argument"
+///     expect_ge!(1, 2, "custom failure message: {argument}");
+///     println!("This will print!");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_ge {
+    ($actual:expr, $expected:expr, $($format_args:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_ge!($actual, $expected)
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, $expected:expr $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_ge!($actual, $expected).and_log_failure();
+    }};
+}
+
+/// Checks whether the float given by first argument is approximately
+/// equal to second argument.
+///
+/// This automatically computes a tolerance from the magnitude of `expected` and
+/// matches any actual value within this tolerance of the expected value. The
+/// tolerance is chosen to account for the inaccuracies in most ordinary
+/// floating point calculations. To see details of how the tolerance is
+/// calculated look at the implementation of
+/// [`googletest::approx_eq`][crate::matchers::approx_eq].
+///
+/// Evaluates to `Result::Ok(())` if the first argument is approximately equal
+/// to the second and `Result::Err(TestAssertionFailure)` if it is not. The
+/// caller must then decide how to handle the `Err` variant. It has a few
+/// options:
+///  * Abort the current function with the `?` operator. This requires that the
+///    function return a suitable `Result`.
+///  * Log the test failure and continue by calling the method
+///    `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_float_eq!(1.0, 2.0)
+/// }
+/// ```
+#[macro_export]
+macro_rules! verify_float_eq {
+    ($actual:expr, $expected:expr $(,)?) => {
+        verify_that!($actual, $crate::matchers::approx_eq($expected))
+    };
+}
+
+/// Marks test as failed and continues execution if the float given by the first
+/// argument is not approximately equal to the float given by the second
+/// argument.
+///
+/// This automatically computes a tolerance from the magnitude of `expected` and
+/// matches any actual value within this tolerance of the expected value. The
+/// tolerance is chosen to account for the inaccuracies in most ordinary
+/// floating point calculations. To see details of how the tolerance is
+/// calculated look at the implementation of
+/// [`googletest::approx_eq`][crate::matchers::approx_eq].
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_float_eq!(1.0, 2.0);
+///     println!("This will print!");
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     let argument = "argument"
+///     expect_float_eq!(1.0, 2.0, "custom failure message: {argument}");
+///     println!("This will print!");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_float_eq {
+    ($actual:expr, $expected:expr, $($format_args:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_float_eq!($actual, $expected)
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, $expected:expr $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_float_eq!($actual, $expected).and_log_failure();
+    }};
+}
+
+/// Checks whether the float given by first argument is equal to second argument
+/// with error tolerance of max_abs_error.
+///
+/// Evaluates to `Result::Ok(())` if the first argument is approximately equal
+/// to the second and `Result::Err(TestAssertionFailure)` if it is not. The
+/// caller must then decide how to handle the `Err` variant. It has a few
+/// options:
+///  * Abort the current function with the `?` operator. This requires that the
+///    function return a suitable `Result`.
+///  * Log the test failure and continue by calling the method
+///    `and_log_failure`.
+///
+/// Of course, one can also use all other standard methods on `Result`.
+///
+/// **Invoking this macro by itself does not cause a test failure to be recorded
+/// or output.** The resulting `Result` must be handled as described above to
+/// cause the test to be recorded as a failure.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[test]
+/// fn should_fail() -> Result<()> {
+///     verify_near!(1.12345, 1.12346, 1e-6)
+/// }
+/// ```
+#[macro_export]
+macro_rules! verify_near {
+    ($actual:expr, $expected:expr, $max_abs_error:expr $(,)?) => {
+        verify_that!($actual, $crate::matchers::near($expected, $max_abs_error))
+    };
+}
+
+/// Marks the test as failed and continues execution if the float given by first
+/// argument is not equal to second argument with error tolerance of
+/// max_abs_error.
+///
+/// This is a **not-fatal** failure. The test continues execution even after the
+/// macro execution.
+///
+/// This can only be invoked inside tests with the
+/// [`gtest`][crate::gtest] attribute. The failure must be generated
+/// in the same thread as that running the test itself.
+///
+/// Example:
+/// ```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     expect_near!(1.12345, 1.12346, 1e-6);
+///     println!("This will print!");
+/// }
+/// ```
+///
+/// One may include formatted arguments in the failure message:
+///```ignore
+/// use googletest::prelude::*;
+///
+/// #[gtest]
+/// fn should_fail() {
+///     let argument = "argument"
+///     expect_near!(1.12345, 1.12346, 1e-6, "custom failure message: {argument}");
+///     println!("This will print!");
+/// }
+/// ```
+#[macro_export]
+macro_rules! expect_near {
+    ($actual:expr, $expected:expr, $max_abs_error:expr, $($format_args:expr),+ $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_near!($actual, $expected, $max_abs_error)
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure();
+    }};
+    ($actual:expr, $expected:expr, $max_abs_error:expr $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        verify_near!($actual, $expected, $max_abs_error).and_log_failure();
+    }};
+}
+
 /// Matches the given value against the given matcher, panicking if it does not
 /// match.
 ///
@@ -351,6 +1308,59 @@
 /// equivalent to `ASSERT_THAT`, use [`verify_that!`] with the `?` operator.
 #[macro_export]
 macro_rules! assert_that {
+    // specialized to sequence:
+    ($actual:expr, [ $($expected:expr),* ] $(,)?) => {
+        match $crate::verify_that!($actual, [ $($expected),* ]) {
+            Ok(_) => {}
+            Err(e) => {
+                // The extra newline before the assertion failure message makes the failure a
+                // bit easier to read when there's some generic boilerplate from the panic.
+                panic!("\n{}", e);
+            }
+        }
+    };
+
+    // specialized to unordered sequence
+    ($actual:expr, { $($expected:expr),* } $(,)?) => {
+        match $crate::verify_that!($actual, { $($expected),* }) {
+            Ok(_) => {}
+            Err(e) => {
+                // The extra newline before the assertion failure message makes the failure a
+                // bit easier to read when there's some generic boilerplate from the panic.
+                panic!("\n{}", e);
+            }
+        }
+    };
+
+    // w/ format args, specialized to sequence:
+    ($actual:expr, [ $($expected:expr),* ], $($format_args:expr),* $(,)?) => {
+        match $crate::verify_that!($actual, [ $($expected),* ])
+            .with_failure_message(|| format!($($format_args),*))
+        {
+            Ok(_) => {}
+            Err(e) => {
+                // The extra newline before the assertion failure message makes the failure a
+                // bit easier to read when there's some generic boilerplate from the panic.
+                panic!("\n{}", e);
+            }
+        }
+    };
+
+    // w/ format args, specialized to unordered sequence:
+    ($actual:expr, { $($expected:expr),* }, $($format_args:expr),* $(,)?) => {
+        match $crate::verify_that!($actual, { $($expected),* })
+            .with_failure_message(|| format!($($format_args),*))
+        {
+            Ok(_) => {}
+            Err(e) => {
+                // The extra newline before the assertion failure message makes the failure a
+                // bit easier to read when there's some generic boilerplate from the panic.
+                panic!("\n{}", e);
+            }
+        }
+    };
+
+    // general case:
     ($actual:expr, $expected:expr $(,)?) => {
         match $crate::verify_that!($actual, $expected) {
             Ok(_) => {}
@@ -362,6 +1372,7 @@
         }
     };
 
+    // w/ format args, general case:
     ($actual:expr, $expected:expr, $($format_args:expr),* $(,)?) => {
         match $crate::verify_that!($actual, $expected)
             .with_failure_message(|| format!($($format_args),*))
@@ -405,7 +1416,7 @@
 /// execution in the event of assertion failure.
 ///
 /// This can only be invoked inside tests with the
-/// [`googletest::test`][crate::test] attribute. The assertion must
+/// [`gtest`][crate::gtest] attribute. The assertion must
 /// occur in the same thread as that running the test itself.
 ///
 /// Invoking this macro is equivalent to using
@@ -442,12 +1453,43 @@
 /// ```
 #[macro_export]
 macro_rules! expect_that {
+    // specialized to sequence:
+    ($actual:expr, [$($expected:expr),*] $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        $crate::verify_that!($actual, [$($expected),*]).and_log_failure();
+    }};
+
+    // specialized to unordered sequence:
+    ($actual:expr, {$($expected:expr),*} $(,)?) => {{
+        use $crate::GoogleTestSupport as _;
+        $crate::verify_that!($actual, {$($expected),*}).and_log_failure();
+    }};
+
+    // w/ format args, specialized to sequence:
+    ($actual:expr, [$($expected:expr),*], $($format_args:expr),* $(,)?) => {
+        use $crate::GoogleTestSupport as _;
+        $crate::verify_that!($actual, [$($expected),*])
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure()
+    };
+
+    // w/ format args, specialized to unordered sequence:
+    ($actual:expr, {$($expected:expr),*}, $($format_args:expr),* $(,)?) => {
+        use $crate::GoogleTestSupport as _;
+        $crate::verify_that!($actual, {$($expected),*})
+            .with_failure_message(|| format!($($format_args),*))
+            .and_log_failure()
+    };
+
+    // general case:
     ($actual:expr, $expected:expr $(,)?) => {{
-        use $crate::GoogleTestSupport;
+        use $crate::GoogleTestSupport as _;
         $crate::verify_that!($actual, $expected).and_log_failure();
     }};
 
+    // w/ format args, general case:
     ($actual:expr, $expected:expr, $($format_args:expr),* $(,)?) => {
+        use $crate::GoogleTestSupport as _;
         $crate::verify_that!($actual, $expected)
             .with_failure_message(|| format!($($format_args),*))
             .and_log_failure()
@@ -461,7 +1503,7 @@
 /// continues execution in the event of assertion failure.
 ///
 /// This can only be invoked inside tests with the
-/// [`googletest::test`][crate::test] attribute. The assertion must
+/// [`gtest`][crate::gtest] attribute. The assertion must
 /// occur in the same thread as that running the test itself.
 ///
 /// Invoking this macro is equivalent to using
@@ -473,7 +1515,7 @@
 #[macro_export]
 macro_rules! expect_pred {
     ($($content:tt)*) => {{
-        use $crate::GoogleTestSupport;
+        use $crate::GoogleTestSupport as _;
         $crate::verify_pred!($($content)*).and_log_failure();
     }};
 }
@@ -484,50 +1526,142 @@
 #[doc(hidden)]
 pub mod internal {
     use crate::{
-        internal::{source_location::SourceLocation, test_outcome::TestAssertionFailure},
+        internal::test_outcome::TestAssertionFailure,
         matcher::{create_assertion_failure, Matcher, MatcherResult},
     };
     use std::fmt::Debug;
 
-    /// Checks whether the matcher `expected` matches the value `actual`, adding
-    /// a test failure report if it does not match.
-    ///
-    /// Returns `Ok(())` if the value matches and `Err(())` if it does not
-    /// match.
-    ///
-    /// **For internal use only. API stablility is not guaranteed!**
-    #[must_use = "The assertion result must be evaluated to affect the test result."]
-    pub fn check_matcher<T: Debug + ?Sized>(
-        actual: &T,
-        expected: impl Matcher<ActualT = T>,
-        actual_expr: &'static str,
-        source_location: SourceLocation,
-    ) -> Result<(), TestAssertionFailure> {
-        match expected.matches(actual) {
-            MatcherResult::Match => Ok(()),
-            MatcherResult::NoMatch => {
-                Err(create_assertion_failure(&expected, actual, actual_expr, source_location))
+    pub use ::googletest_macro::__googletest_macro_verify_pred;
+
+    /// Extension trait to perform autoref through method lookup in the
+    /// assertion macros. With this trait, the subject can be either a value
+    /// or a reference. For example, this trait makes the following code
+    /// compile and work:
+    /// ```
+    /// # use googletest::prelude::*;
+    /// # fn would_not_compile_without_autoref() -> Result<()> {
+    /// let not_copyable = vec![1,2,3];
+    /// verify_that!(not_copyable, empty())?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    /// See [Method Lookup](https://rustc-dev-guide.rust-lang.org/method-lookup.html)
+    pub trait Subject: Copy + Debug {
+        /// Checks whether the matcher `expected` matches the `Subject `self`,
+        /// adding a test failure report if it does not match.
+        ///
+        /// Returns `Ok(())` if the value matches and `Err(_)` if it does not
+        /// match.
+        ///
+        /// **For internal use only. API stablility is not guaranteed!**
+        #[must_use = "The assertion result must be evaluated to affect the test result."]
+        #[track_caller]
+        fn check(
+            self,
+            expected: impl Matcher<Self>,
+            actual_expr: &'static str,
+        ) -> Result<(), TestAssertionFailure> {
+            match expected.matches(self) {
+                MatcherResult::Match => Ok(()),
+                MatcherResult::NoMatch => {
+                    Err(create_assertion_failure(&expected, self, actual_expr))
+                }
             }
         }
     }
 
-    /// Constructs a `Result::Err(TestAssertionFailure)` for a predicate failure
-    /// as produced by the macro [`crate::verify_pred`].
+    impl<T: Copy + Debug> Subject for T {}
+
+    /// Creates a failure at specified location.
     ///
-    /// This intended only for use by the macro [`crate::verify_pred`].
-    ///
-    /// **For internal use only. API stablility is not guaranteed!**
+    /// **For internal use only. API stability is not guaranteed!**
     #[must_use = "The assertion result must be evaluated to affect the test result."]
-    pub fn report_failed_predicate(
-        actual_expr: &'static str,
-        formatted_arguments: Vec<String>,
-        source_location: SourceLocation,
-    ) -> Result<(), TestAssertionFailure> {
-        Err(TestAssertionFailure::create(format!(
-            "{} was false with\n  {}\n{}",
-            actual_expr,
-            formatted_arguments.join(",\n  "),
-            source_location,
-        )))
+    #[track_caller]
+    pub fn create_fail_result(message: String) -> crate::Result<()> {
+        Err(crate::internal::test_outcome::TestAssertionFailure::create(message))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::prelude::*;
+
+    #[test]
+    fn verify_of_hash_maps_with_str_string_matching() -> Result<()> {
+        let hash_map: std::collections::HashMap<String, String> =
+            std::collections::HashMap::from([("a".into(), "A".into()), ("b".into(), "B".into())]);
+        verify_eq!(hash_map, {("a", "A"), ("b", "B")})
+    }
+
+    #[test]
+    fn verify_of_hash_maps_with_ad_hoc_struct() -> Result<()> {
+        #[derive(PartialEq, Debug)]
+        struct Greek(String);
+
+        let hash_map: std::collections::HashMap<String, Greek> = std::collections::HashMap::from([
+            ("a".into(), Greek("Alpha".into())),
+            ("b".into(), Greek("Beta".into())),
+        ]);
+        verify_eq!(hash_map, {
+            ("b", Greek("Beta".into())),
+            ("a", Greek("Alpha".into())),
+        })
+    }
+
+    #[test]
+    fn verify_of_hash_maps_with_i32s() -> Result<()> {
+        let hash_map: std::collections::HashMap<i32, i32> =
+            std::collections::HashMap::from([(1, 1), (2, 4), (-1, 1), (-3, 9)]);
+        verify_eq!(hash_map, {
+            (-3, 9),
+            (-1, 1),
+            (1, 1),
+            (2, 4),
+        })
+    }
+
+    #[test]
+    fn verify_eq_of_unordered_pairs() -> Result<()> {
+        verify_eq!(vec![(1, 2), (2, 3)], {(1, 2), (2, 3)})?;
+        verify_eq!(vec![(1, 2), (2, 3)], {(2, 3), (1, 2)})
+    }
+
+    #[test]
+    fn verify_eq_of_unordered_structs() -> Result<()> {
+        #[derive(PartialEq, Debug)]
+        struct P(i32, i32);
+
+        verify_eq!(vec![P(1, 1), P(1, 2), P(3, 7)],
+                  {P(1, 1), P(1, 2), P(3, 7)})?;
+        verify_eq!(vec![P(1, 1), P(1, 2), P(3, 7)],
+                  {P(3,7), P(1, 1), P(1, 2)})
+    }
+
+    #[test]
+    fn verify_eq_of_ordered_pairs() -> Result<()> {
+        verify_eq!(vec![(1, 2), (2, 3)], [(1, 2), (2, 3)])
+    }
+
+    #[test]
+    fn verify_eq_of_ordered_structs() -> Result<()> {
+        #[derive(PartialEq, Debug)]
+        struct P(i32, i32);
+
+        verify_eq!(vec![P(1, 1), P(1, 2), P(3, 7)], [P(1, 1), P(1, 2), P(3, 7)])
+    }
+
+    #[test]
+    fn verify_eq_of_ordered_pairs_order_matters() -> Result<()> {
+        let result = verify_eq!(vec![(1, 2), (2, 3)], [(2, 3), (1, 2)]);
+        verify_that!(result, err(anything()))
+    }
+
+    #[test]
+    fn verify_eq_of_ordered_structs_order_matters() -> Result<()> {
+        #[derive(PartialEq, Debug)]
+        struct P(i32, i32);
+
+        let result = verify_eq!(vec![P(1, 1), P(1, 2), P(3, 7)], [P(3, 7), P(1, 1), P(1, 2)]);
+        verify_that!(result, err(anything()))
     }
 }
diff --git a/crates/googletest/src/description.rs b/crates/googletest/src/description.rs
index 9605559..e7339c1 100644
--- a/crates/googletest/src/description.rs
+++ b/crates/googletest/src/description.rs
@@ -89,6 +89,8 @@
 pub struct Description {
     elements: List,
     initial_indentation: usize,
+    is_conjunction: bool,
+    is_disjunction: bool,
 }
 
 impl Description {
@@ -199,6 +201,27 @@
     pub fn is_empty(&self) -> bool {
         self.elements.is_empty()
     }
+
+    pub(crate) fn push_in_last_nested(mut self, inner: Description) -> Self {
+        self.elements.push_at_end(inner.elements);
+        self
+    }
+
+    pub(crate) fn conjunction_description(self) -> Self {
+        Self { is_conjunction: true, ..self }
+    }
+
+    pub(crate) fn is_conjunction_description(&self) -> bool {
+        self.is_conjunction
+    }
+
+    pub(crate) fn disjunction_description(self) -> Self {
+        Self { is_disjunction: true, ..self }
+    }
+
+    pub(crate) fn is_disjunction_description(&self) -> bool {
+        self.is_disjunction
+    }
 }
 
 impl Display for Description {
@@ -359,4 +382,24 @@
             )))
         )
     }
+
+    #[test]
+    fn new_is_empty() -> Result<()> {
+        verify_that!(Description::new(), predicate(Description::is_empty))
+    }
+
+    #[test]
+    fn text_is_not_empty() -> Result<()> {
+        verify_that!(Description::new().text("something"), not(predicate(Description::is_empty)))
+    }
+
+    #[test]
+    fn new_zero_length() -> Result<()> {
+        verify_that!(Description::new().len(), eq(0))
+    }
+
+    #[test]
+    fn text_one_length() -> Result<()> {
+        verify_that!(Description::new().text("something").len(), eq(1))
+    }
 }
diff --git a/crates/googletest/src/fixtures.rs b/crates/googletest/src/fixtures.rs
new file mode 100644
index 0000000..27fc7c2
--- /dev/null
+++ b/crates/googletest/src/fixtures.rs
@@ -0,0 +1,261 @@
+// Copyright 2022 Google LLC
+//
+// 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.
+
+use std::{
+    any::{Any, TypeId},
+    collections::HashMap,
+    ops::{Deref, DerefMut},
+    sync::{Mutex, OnceLock},
+};
+
+/// Interface for structure to be set up and torn down as part of a test.
+/// Types implementing `Fixture` can be passed as a reference argument to a
+/// test function.
+///
+/// ```ignore
+/// strct MyFixture { ... }
+///
+/// impl Fixture for MyFixture { ... }
+///
+/// #[gtest]
+/// fn test_with_fixture(my_fixture: &MyFixture) {...}
+/// ```
+pub trait Fixture: Sized {
+    /// Factory method of the `Fixture`.
+    ///
+    /// This method is called by the test harness before the test case
+    /// If this method returns an `Err(...)`, then the test case is not
+    /// evaluated and only the fixtures previously set up are torn down.
+    fn set_up() -> crate::Result<Self>;
+
+    /// Clean up method for the fixture.
+    ///
+    /// This method is called by the test harness after the test case.
+    /// If the `Fixture` has been set up, the test harness will call this
+    /// method, even if the test case failed or panicked.
+    fn tear_down(self) -> crate::Result<()>;
+}
+
+/// Interface for structure to be set up before the test case.
+/// Types implementing `ConsumableFixture` can be passed by value to
+/// a test function.
+///
+/// ```ignore
+/// strct MyFixture { ... }
+///
+/// impl ConsumableFixture for MyFixture { ... }
+///
+/// #[gtest]
+/// fn test_with_fixture(my_fixture: MyFixture) {...}
+/// ```
+pub trait ConsumableFixture: Sized {
+    /// Factory method of the `ConsumableFixture`.
+    ///
+    /// This method is called by the test harness before the test case.
+    /// If this method returns an `Err(...)`, then the test case is not
+    /// evaluated.
+    fn set_up() -> crate::Result<Self>;
+}
+
+/// Generic adapter to implement `ConsumableFixture` on any type implementing
+/// `Default`.
+pub struct FixtureOf<T>(T);
+
+impl<T: Default> ConsumableFixture for FixtureOf<T> {
+    fn set_up() -> crate::Result<Self> {
+        Ok(Self(T::default()))
+    }
+}
+
+impl<T> Deref for FixtureOf<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for FixtureOf<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+/// Interface for structure to be set up only once before all tests.
+/// Types implementing `StaticFixture` can be passed as a double referenced
+/// argument to a test function.
+///
+/// ```ignore
+/// strct MyFixture{ ... }
+///
+/// impl StaticFixture for MyFixture { ... }
+///
+/// #[gtest]
+/// fn test_with_fixture(my_fixture: &&MyFixture){...}
+/// ```
+pub trait StaticFixture: Sized + Sync + Send {
+    /// Factory method of the `StaticFixture`.
+    ///
+    /// This method is called by the test harness before the first test case
+    /// using this fixture. If this method returns an `Err(...)`, then every
+    /// test cases using this fixture are not evaluated.
+    fn set_up_once() -> crate::Result<Self>;
+}
+
+impl<F: StaticFixture + 'static> Fixture for &'static F {
+    fn set_up() -> crate::Result<Self> {
+        static ONCE_FIXTURE_REPO: OnceLock<
+            Mutex<HashMap<TypeId, &'static (dyn Any + Sync + Send)>>,
+        > = OnceLock::new();
+        let mut map = ONCE_FIXTURE_REPO.get_or_init(|| Mutex::new(HashMap::new())).lock()?;
+        let any =
+            map.entry(TypeId::of::<F>()).or_insert_with(|| Box::leak(Box::new(F::set_up_once())));
+        match any.downcast_ref::<crate::Result<F>>() {
+            Some(Ok(ref fixture)) => Ok(fixture),
+            Some(Err(e)) => Err(e.clone()),
+            None => panic!("Downcast failed. This is a bug in GoogleTest Rust"),
+        }
+    }
+
+    // Note that this is `&F` being torn down, not `F`.
+    fn tear_down(self) -> crate::Result<()> {
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use std::sync::Once;
+
+    use super::FixtureOf;
+    use super::StaticFixture;
+    use crate as googletest;
+    use crate::prelude::*;
+    use crate::test;
+
+    #[test]
+    fn fixture_no_fixture() -> Result<()> {
+        Ok(())
+    }
+
+    struct AlwaysSucceed;
+
+    impl Fixture for AlwaysSucceed {
+        fn set_up() -> crate::Result<Self> {
+            Ok(Self)
+        }
+
+        fn tear_down(self) -> crate::Result<()> {
+            Ok(())
+        }
+    }
+
+    #[test]
+    fn fixture_one_fixture(_: &AlwaysSucceed) -> Result<()> {
+        Ok(())
+    }
+
+    #[test]
+    fn fixture_three_fixtures(
+        _: &AlwaysSucceed,
+        _: &AlwaysSucceed,
+        _: &AlwaysSucceed,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    struct NotAFixture {
+        a_field: i32,
+    }
+
+    impl Default for NotAFixture {
+        fn default() -> Self {
+            Self { a_field: 33 }
+        }
+    }
+
+    #[test]
+    fn fixture_of_non_fixture(not_a_fixture: FixtureOf<NotAFixture>) -> Result<()> {
+        verify_that!(not_a_fixture.a_field, eq(33))
+    }
+
+    #[test]
+    fn fixture_of_non_fixture_mut(mut not_a_fixture: FixtureOf<NotAFixture>) -> Result<()> {
+        not_a_fixture.a_field += 10;
+        verify_that!(not_a_fixture.a_field, eq(43))
+    }
+    struct PanickyFixture;
+
+    impl Fixture for PanickyFixture {
+        fn set_up() -> crate::Result<Self> {
+            Ok(Self)
+        }
+
+        fn tear_down(self) -> crate::Result<()> {
+            panic!("Whoooops");
+        }
+    }
+
+    #[test]
+    #[should_panic(expected = "Whoooops")]
+    fn fixture_teardown_called_even_if_test_fail(_: &PanickyFixture) {
+        panic!("Test failed");
+    }
+
+    struct FailingTearDown;
+
+    impl Fixture for FailingTearDown {
+        fn set_up() -> crate::Result<Self> {
+            Ok(Self)
+        }
+
+        fn tear_down(self) -> crate::Result<()> {
+            Err(googletest::TestAssertionFailure::create("It must fail!".into()))
+        }
+    }
+
+    struct OnlyOnce;
+
+    impl StaticFixture for OnlyOnce {
+        fn set_up_once() -> crate::Result<Self> {
+            static ONCE: Once = Once::new();
+            assert!(!ONCE.is_completed());
+            ONCE.call_once(|| {});
+            Ok(Self)
+        }
+    }
+
+    #[test]
+    fn static_fixture_works(_: &&OnlyOnce) {}
+
+    #[test]
+    fn static_fixture_same_static_fixture_twice(once: &&OnlyOnce, twice: &&OnlyOnce) {
+        // checks it points to the same memory address.
+        let once: *const OnlyOnce = *once;
+        let twice: *const OnlyOnce = *twice;
+        expect_eq!(once, twice);
+    }
+
+    struct AnotherStaticFixture;
+
+    impl StaticFixture for AnotherStaticFixture {
+        fn set_up_once() -> crate::Result<Self> {
+            Ok(Self)
+        }
+    }
+
+    #[test]
+    fn static_fixture_two_different_static_fixtures(_: &&OnlyOnce, _: &&AnotherStaticFixture) {}
+}
diff --git a/crates/googletest/src/fmt.rs b/crates/googletest/src/fmt.rs
new file mode 100644
index 0000000..267b127
--- /dev/null
+++ b/crates/googletest/src/fmt.rs
@@ -0,0 +1,67 @@
+// Copyright 2024 Google LLC
+//
+// 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.
+
+/// Functions for use only by the procedural macros in this module.
+///
+/// **For internal use only. API stablility is not guaranteed!**
+#[doc(hidden)]
+pub mod internal {
+    use std::fmt::{Debug, Write};
+
+    /// Wrapper to allow for inherent-method specialization based on whether a
+    /// type implements `Debug`.
+    pub struct FormatWrapper<'a, T: ?Sized>(pub &'a T);
+
+    /// Default implementation to render values that implement `Debug`.
+    ///
+    /// Used for autoref specialization to conditionally
+    /// render only values that implement `Debug`. See also
+    /// [`FormatNonDebugFallback`].
+    impl<'a, T: Debug + ?Sized> FormatWrapper<'a, T> {
+        #[track_caller]
+        pub fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str) {
+            write!(output, "\n  {} = {:?},", expr_label, self.0)
+                .expect("Formatting to String should never fail");
+        }
+    }
+
+    /// Fallback implementation for rendering values for non-`Debug` types..
+    ///
+    /// Used for inherent-method specialization to conditionally render only
+    /// values that implement `Debug`. See also the specialized inherent impl on
+    /// [`FormatWrapper`] above.
+    pub trait FormatNonDebugFallback {
+        fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str);
+    }
+
+    impl<'a, T: ?Sized> FormatNonDebugFallback for FormatWrapper<'a, T> {
+        #[track_caller]
+        fn __googletest_write_expr_value(&self, output: &mut dyn Write, expr_label: &str) {
+            write!(output, "\n  {} does not implement Debug,", expr_label)
+                .expect("Formatting to String should never fail");
+        }
+    }
+
+    #[macro_export]
+    macro_rules! __googletest__write_expr_value(
+        ($output:expr, $expr_str:expr, $value:expr $(,)?) => {
+            {
+                use $crate::fmt::internal::FormatNonDebugFallback as _;
+                $crate::fmt::internal::FormatWrapper(&$value)
+                    .__googletest_write_expr_value(&mut $output, $expr_str)
+            }
+        }
+    );
+    pub use __googletest__write_expr_value;
+}
diff --git a/crates/googletest/src/internal/description_renderer.rs b/crates/googletest/src/internal/description_renderer.rs
index 937f0d5..e84fabe 100644
--- a/crates/googletest/src/internal/description_renderer.rs
+++ b/crates/googletest/src/internal/description_renderer.rs
@@ -83,6 +83,17 @@
         self.0.is_empty()
     }
 
+    /// Append a new [`List`] in the last element which must be a
+    /// [`Block::Nested`]. Panic if `self` is empty or the last element is
+    /// not [`Block::Nested`].
+    pub(crate) fn push_at_end(&mut self, list: List) {
+        if let Some(Block::Nested(self_list)) = self.0.last_mut() {
+            self_list.push_nested(list);
+        } else {
+            panic!("pushing elements at the end of {self:#?} which last element is not Nested")
+        }
+    }
+
     fn render_with_prefix(
         &self,
         f: &mut dyn Write,
diff --git a/crates/googletest/src/internal/mod.rs b/crates/googletest/src/internal/mod.rs
index 9bccdc3..1269bc9 100644
--- a/crates/googletest/src/internal/mod.rs
+++ b/crates/googletest/src/internal/mod.rs
@@ -15,5 +15,4 @@
 #![doc(hidden)]
 
 pub(crate) mod description_renderer;
-pub mod source_location;
 pub mod test_outcome;
diff --git a/crates/googletest/src/internal/source_location.rs b/crates/googletest/src/internal/source_location.rs
deleted file mode 100644
index 4520c92..0000000
--- a/crates/googletest/src/internal/source_location.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2022 Google LLC
-//
-// 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.
-
-use std::fmt::{Display, Error, Formatter};
-
-/// Encapsulates a location in source code.
-///
-/// This is intended to report the location of an assertion which failed to
-/// stdout.
-///
-/// **For internal use only. API stablility is not guaranteed!**
-#[doc(hidden)]
-pub struct SourceLocation {
-    file: &'static str,
-    line: u32,
-    column: u32,
-}
-
-impl SourceLocation {
-    /// Constructs a new [`SourceLocation`].
-    ///
-    /// **For internal use only. API stablility is not guaranteed!**
-    #[doc(hidden)]
-    pub fn new(file: &'static str, line: u32, column: u32) -> Self {
-        Self { file, line, column }
-    }
-}
-
-impl Display for SourceLocation {
-    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
-        write!(f, "  at {}:{}:{}", self.file, self.line, self.column)
-    }
-}
diff --git a/crates/googletest/src/internal/test_outcome.rs b/crates/googletest/src/internal/test_outcome.rs
index 132ba99..edc8d2b 100644
--- a/crates/googletest/src/internal/test_outcome.rs
+++ b/crates/googletest/src/internal/test_outcome.rs
@@ -32,14 +32,13 @@
 }
 
 thread_local! {
-    static CURRENT_TEST_OUTCOME: RefCell<Option<TestOutcome>> = RefCell::new(None);
+    static CURRENT_TEST_OUTCOME: RefCell<Option<TestOutcome>> = const { RefCell::new(None) };
 }
 
 impl TestOutcome {
     /// Resets the current test's [`TestOutcome`].
     ///
-    /// This is intended only for use by the attribute macro
-    /// `#[googletest::test]`.
+    /// This is intended only for use by the attribute macro `#[gtest]`.
     ///
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
@@ -86,6 +85,7 @@
 
     /// Returns a `Result` corresponding to the outcome of the currently running
     /// test.
+    #[track_caller]
     pub(crate) fn get_current_test_outcome() -> Result<(), TestAssertionFailure> {
         TestOutcome::with_current_test_outcome(|mut outcome| {
             let outcome = outcome
@@ -117,12 +117,12 @@
     }
 
     /// Ensure that there is a test context present and panic if there is not.
-    pub(crate) fn ensure_text_context_present() {
+    pub(crate) fn ensure_test_context_present() {
         TestOutcome::with_current_test_outcome(|outcome| {
             outcome.as_ref().expect(
                 "
 No test context found.
- * Did you annotate the test with googletest::test?
+ * Did you annotate the test with gtest?
  * Is the assertion running in the original test thread?
 ",
             );
@@ -162,14 +162,50 @@
     /// A human-readable formatted string describing the error.
     pub description: String,
     pub custom_message: Option<String>,
+    location: Location,
+}
+
+/// A code location.
+///
+/// `std::panic::Location` does not provide a constructor, hence we cannot
+/// construct a fake value.
+///
+/// **For internal use only. API stablility is not guaranteed!**
+#[doc(hidden)]
+#[derive(Clone)]
+enum Location {
+    Real(&'static std::panic::Location<'static>),
+    Fake { file: &'static str, line: u32, column: u32 },
+}
+
+impl Display for Location {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Location::Real(l) => write!(f, "{}", l),
+            Location::Fake { file, line, column } => write!(f, "{}:{}:{}", file, line, column),
+        }
+    }
 }
 
 impl TestAssertionFailure {
     /// Creates a new instance with the given `description`.
     ///
     /// **For internal use only. API stablility is not guaranteed!**
+    #[track_caller]
     pub fn create(description: String) -> Self {
-        Self { description, custom_message: None }
+        Self {
+            description,
+            custom_message: None,
+            location: Location::Real(std::panic::Location::caller()),
+        }
+    }
+
+    /// Set `location`` to a fake value.
+    ///
+    /// **For internal use only. API stablility is not guaranteed!**
+    pub fn with_fake_location(mut self, file: &'static str, line: u32, column: u32) -> Self {
+        self.location = Location::Fake { file, line, column };
+        self
     }
 
     pub(crate) fn log(&self) {
@@ -184,7 +220,7 @@
         if let Some(custom_message) = &self.custom_message {
             writeln!(f, "{}", custom_message)?;
         }
-        Ok(())
+        writeln!(f, "  at {}", self.location)
     }
 }
 
@@ -198,6 +234,7 @@
 }
 
 impl<T: std::error::Error> From<T> for TestAssertionFailure {
+    #[track_caller]
     fn from(value: T) -> Self {
         TestAssertionFailure::create(format!("{value}"))
     }
diff --git a/crates/googletest/src/lib.rs b/crates/googletest/src/lib.rs
index 51b6345..3f59546 100644
--- a/crates/googletest/src/lib.rs
+++ b/crates/googletest/src/lib.rs
@@ -22,11 +22,16 @@
 #[macro_use]
 pub mod assertions;
 pub mod description;
+pub mod fixtures;
+#[macro_use]
+pub mod fmt;
 pub mod internal;
 pub mod matcher;
 pub mod matcher_support;
 pub mod matchers;
 
+pub use googletest_macro::{__abbreviated_stringify, __googletest_macro_verify_pred};
+
 /// Re-exports of the symbols in this crate which are most likely to be used.
 ///
 /// This includes:
@@ -42,16 +47,25 @@
 /// }
 /// ```
 pub mod prelude {
-    pub use super::matcher::Matcher;
+    pub use super::fixtures::{ConsumableFixture, Fixture, FixtureOf, StaticFixture};
+    pub use super::gtest;
+    pub use super::matcher::{Matcher, MatcherBase};
     pub use super::matchers::*;
     pub use super::verify_current_test_outcome;
     pub use super::GoogleTestSupport;
     pub use super::IntoTestResult;
     pub use super::Result;
     // Assert macros
-    pub use super::{assert_that, expect_pred, expect_that, fail, verify_pred, verify_that};
+    pub use super::{
+        add_failure, add_failure_at, assert_pred, assert_that, expect_eq, expect_false,
+        expect_float_eq, expect_ge, expect_gt, expect_le, expect_lt, expect_ne, expect_near,
+        expect_pred, expect_that, expect_true, fail, succeed, verify_eq, verify_false,
+        verify_float_eq, verify_ge, verify_gt, verify_le, verify_lt, verify_ne, verify_near,
+        verify_pred, verify_that, verify_true,
+    };
 }
 
+pub use googletest_macro::gtest;
 pub use googletest_macro::test;
 
 use internal::test_outcome::{TestAssertionFailure, TestOutcome};
@@ -89,13 +103,12 @@
 /// `?` operator to continue execution of the test conditionally on there not
 /// having been any failure yet.
 ///
-/// This requires the use of the [`#[googletest::test]`][crate::test] attribute
-/// macro.
+/// This requires the use of the [`#[gtest]`][crate::gtest] attribute macro.
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # /* Make sure this also compiles as a doctest.
-/// #[googletest::test]
+/// #[gtest]
 /// # */
 /// # fn foo() -> u32 { 1 }
 /// # fn bar() -> u32 { 2 }
@@ -108,6 +121,7 @@
 /// }
 /// # verify_that!(should_fail_and_not_execute_last_assertion(), err(displays_as(contains_substring("Test failed")))).unwrap();
 /// ```
+#[track_caller]
 pub fn verify_current_test_outcome() -> Result<()> {
     TestOutcome::get_current_test_outcome()
 }
@@ -203,7 +217,7 @@
 
 impl<T> GoogleTestSupport for std::result::Result<T, TestAssertionFailure> {
     fn and_log_failure(self) {
-        TestOutcome::ensure_text_context_present();
+        TestOutcome::ensure_test_context_present();
         if let Err(failure) = self {
             failure.log();
         }
@@ -229,44 +243,52 @@
 ///
 /// A type can implement this trait to provide an easy way to return immediately
 /// from a test in conjunction with the `?` operator. This is useful for
-/// [`Result`][std::result::Result] types whose `Result::Err` variant does not
-/// implement [`std::error::Error`].
+/// [`Option`] and [`Result`][std::result::Result] types whose `Result::Err`
+/// variant does not implement [`std::error::Error`].
 ///
-/// There is an implementation of this trait for [`anyhow::Error`] (which does
-/// not implement `std::error::Error`) when the `anyhow` feature is enabled.
-/// Importing this trait allows one to easily map [`anyhow::Error`] to a test
-/// failure:
+/// If `Result::Err` implements [`std::error::Error`] you can just use the `?`
+/// operator directly.
 ///
 /// ```ignore
 /// #[test]
-/// fn should_work() -> Result<()> {
+/// fn should_work() -> googletest::Result<()> {
 ///     let value = something_which_can_fail().into_test_result()?;
+///     let value = something_which_can_fail_with_option().into_test_result()?;
 ///     ...
 /// }
 ///
-/// fn something_which_can_fail() -> anyhow::Result<...> { ... }
+/// fn something_which_can_fail() -> std::result::Result<T, String> { ... }
+/// fn something_which_can_fail_with_option() -> Option<T> { ... }
 /// ```
 pub trait IntoTestResult<T> {
     /// Converts this instance into a [`Result`].
     ///
-    /// Typically, the `Self` type is itself a [`std::result::Result`]. This
-    /// method should then map the `Err` variant to a [`TestAssertionFailure`]
-    /// and leave the `Ok` variant unchanged.
+    /// Typically, the `Self` type is itself an implementation of the
+    /// [`std::ops::Try`] trait. This method should then map the `Residual`
+    /// variant to a [`TestAssertionFailure`] and leave the `Output` variant
+    /// unchanged.
     fn into_test_result(self) -> Result<T>;
 }
 
-#[cfg(feature = "anyhow")]
-impl<T> IntoTestResult<T> for std::result::Result<T, anyhow::Error> {
+impl<T, E: std::fmt::Debug> IntoTestResult<T> for std::result::Result<T, E> {
+    #[track_caller]
     fn into_test_result(self) -> std::result::Result<T, TestAssertionFailure> {
-        self.map_err(|e| TestAssertionFailure::create(format!("{e}")))
+        match self {
+            Ok(t) => Ok(t),
+            Err(e) => Err(TestAssertionFailure::create(format!("{e:?}"))),
+        }
     }
 }
 
-#[cfg(feature = "proptest")]
-impl<OkT, CaseT: std::fmt::Debug> IntoTestResult<OkT>
-    for std::result::Result<OkT, proptest::test_runner::TestError<CaseT>>
-{
-    fn into_test_result(self) -> std::result::Result<OkT, TestAssertionFailure> {
-        self.map_err(|e| TestAssertionFailure::create(format!("{e}")))
+impl<T> IntoTestResult<T> for Option<T> {
+    #[track_caller]
+    fn into_test_result(self) -> std::result::Result<T, TestAssertionFailure> {
+        match self {
+            Some(t) => Ok(t),
+            None => Err(TestAssertionFailure::create(format!(
+                "called `Option::into_test_result()` on a `Option::<{}>::None` value",
+                std::any::type_name::<T>()
+            ))),
+        }
     }
 }
diff --git a/crates/googletest/src/matcher.rs b/crates/googletest/src/matcher.rs
index 071b0d1..948ea41 100644
--- a/crates/googletest/src/matcher.rs
+++ b/crates/googletest/src/matcher.rs
@@ -15,24 +15,35 @@
 //! The components required to implement matchers.
 
 use crate::description::Description;
-use crate::internal::source_location::SourceLocation;
 use crate::internal::test_outcome::TestAssertionFailure;
 use crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher;
 use crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher;
+pub use googletest_macro::MatcherBase;
 use std::fmt::Debug;
 
 /// An interface for checking an arbitrary condition on a datum.
-pub trait Matcher {
-    /// The type against which this matcher matches.
-    type ActualT: Debug + ?Sized;
+///
+/// This trait is automatically implemented for a reference of any type
+/// implementing `Matcher`. This simplifies reusing a matcher in different
+/// assertions.
+///
+/// It is also implemented for tuple of `Matcher`. If `MatcherT: Matcher<T>` and
+/// `MatcherU: Matcher<U>`, then `(MatcherT, MatcherU): Matcher<(T, U)>`, and so
+/// on, up to 12 elements. Tuples longer than that do not automatically inherit
+/// the `Debug` trait from their members, so are generally not well-supported;
+/// see [Rust by Example](https://doc.rust-lang.org/rust-by-example/primitives/tuples.html#tuples).
 
+// `ActualT` requires `Copy` so that `actual` could be passed to `matches` and
+// if it fails passed to `explain_match`. We can relax this constraint later by
+// requiring only `Clone`.
+pub trait Matcher<ActualT: Debug + Copy>: MatcherBase {
     /// Returns whether the condition matches the datum `actual`.
     ///
     /// The trait implementation defines what it means to "match". Often the
     /// matching condition is based on data stored in the matcher. For example,
     /// `eq` matches when its stored expected value is equal (in the sense of
     /// the `==` operator) to the value `actual`.
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult;
+    fn matches(&self, actual: ActualT) -> MatcherResult;
 
     /// Returns a description of `self` or a negative description if
     /// `matcher_result` is `DoesNotMatch`.
@@ -117,8 +128,8 @@
     /// inner matcher and appears as follows:
     ///
     /// ```ignore
-    /// fn explain_match(&self, actual: &Self::ActualT) -> Description {
-    ///     self.expected.explain_match(actual.deref())
+    /// fn explain_match(&self, actual: &ActualT) -> Description {
+    ///     self.expected.explain_match(*actual)
     /// }
     /// ```
     ///
@@ -127,16 +138,30 @@
     /// inner matcher at a point where a relative clause would fit. For example:
     ///
     /// ```ignore
-    /// fn explain_match(&self, actual: &Self::ActualT) -> Description {
+    /// fn explain_match(&self, actual: ActualT) -> Description {
     ///     Description::new()
     ///         .text("which points to a value")
-    ///         .nested(self.expected.explain_match(actual.deref()))
+    ///         .nested(self.expected.explain_match(*actual))
     /// }
     /// ```
-    fn explain_match(&self, actual: &Self::ActualT) -> Description {
+    fn explain_match(&self, actual: ActualT) -> Description {
         format!("which {}", self.describe(self.matches(actual))).into()
     }
+}
 
+/// Base trait for matchers. Any type implementing `Matcher` must implement
+/// `MatcherBase`, but that should be done through the `#[derive(MatcherBase)]`
+/// macro.
+// The `and` and `or` functions cannot be part of the `Matcher` trait since it
+// can be implemented multiple times for a given matcher type. Consider that
+// `and` and `or` are part of the `Matcher` trait and `MyMatcher` implements
+// both `Matcher<A>` and `Matcher<B>`. Then `MyMatcher{...}.and(...)` can be
+// either:
+//   * `Matcher::<A>::and(MyMatcher{...}, ...)` or
+//   * `Matcher::<B>::and(MyMatcher{...}, ...)`.
+// Moving the `and` and `or` functions in a non-generic trait removes this
+// confusion by making `and` and `or` unique for a given type.
+pub trait MatcherBase {
     /// Constructs a matcher that matches both `self` and `right`.
     ///
     /// ```
@@ -160,10 +185,7 @@
     // TODO(b/264518763): Replace the return type with impl Matcher and reduce
     // visibility of ConjunctionMatcher once impl in return position in trait
     // methods is stable.
-    fn and<Right: Matcher<ActualT = Self::ActualT>>(
-        self,
-        right: Right,
-    ) -> ConjunctionMatcher<Self, Right>
+    fn and<Right>(self, right: Right) -> ConjunctionMatcher<Self, Right>
     where
         Self: Sized,
     {
@@ -190,10 +212,7 @@
     // TODO(b/264518763): Replace the return type with impl Matcher and reduce
     // visibility of DisjunctionMatcher once impl in return position in trait
     // methods is stable.
-    fn or<Right: Matcher<ActualT = Self::ActualT>>(
-        self,
-        right: Right,
-    ) -> DisjunctionMatcher<Self, Right>
+    fn or<Right>(self, right: Right) -> DisjunctionMatcher<Self, Right>
     where
         Self: Sized,
     {
@@ -210,11 +229,11 @@
 ///
 /// The parameter `actual_expr` contains the expression which was evaluated to
 /// obtain `actual`.
-pub(crate) fn create_assertion_failure<T: Debug + ?Sized>(
-    matcher: &impl Matcher<ActualT = T>,
-    actual: &T,
+#[track_caller]
+pub(crate) fn create_assertion_failure<T: Debug + Copy>(
+    matcher: &impl Matcher<T>,
+    actual: T,
     actual_expr: &'static str,
-    source_location: SourceLocation,
 ) -> TestAssertionFailure {
     let actual_formatted = format!("{actual:?}");
     let actual_formatted = if actual_formatted.len() > PRETTY_PRINT_LENGTH_THRESHOLD {
@@ -227,8 +246,7 @@
 Value of: {actual_expr}
 Expected: {}
 Actual: {actual_formatted},
-{}
-{source_location}",
+{}",
         matcher.describe(MatcherResult::Match),
         matcher.explain_match(actual).indent(),
     ))
@@ -245,7 +263,11 @@
 
 impl From<bool> for MatcherResult {
     fn from(b: bool) -> Self {
-        if b { MatcherResult::Match } else { MatcherResult::NoMatch }
+        if b {
+            MatcherResult::Match
+        } else {
+            MatcherResult::NoMatch
+        }
     }
 }
 
@@ -268,3 +290,39 @@
         matches!(self, MatcherResult::NoMatch)
     }
 }
+
+impl<M: ?Sized + MatcherBase> MatcherBase for &M {}
+
+impl<T: Debug + Copy, M: Matcher<T>> Matcher<T> for &M {
+    fn matches(&self, actual: T) -> MatcherResult {
+        (*self).matches(actual)
+    }
+
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        (*self).describe(matcher_result)
+    }
+
+    fn explain_match(&self, actual: T) -> Description {
+        (*self).explain_match(actual)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::prelude::*;
+
+    #[test]
+    fn ref_matchers_can_be_reused() -> Result<()> {
+        let matcher = eq(1);
+
+        verify_that!(1, &matcher)?;
+        verify_that!(1, &matcher)
+    }
+
+    #[test]
+    fn ref_matchers_as_inner_matcher() -> Result<()> {
+        let matcher = gt(1);
+
+        verify_that!([2, 3, 4, 5], [&matcher, &matcher, &matcher, &matcher])
+    }
+}
diff --git a/crates/googletest/src/matcher_support/auto_eq.rs b/crates/googletest/src/matcher_support/auto_eq.rs
new file mode 100644
index 0000000..16bfde3
--- /dev/null
+++ b/crates/googletest/src/matcher_support/auto_eq.rs
@@ -0,0 +1,106 @@
+// Copyright 2024 Google LLC
+//
+// 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.
+
+#![doc(hidden)]
+
+/// Macro that wraps the expression with `eq(...)` if the expression is
+/// not a matcher.
+///
+/// This is useful to let users pass expected value to macro matchers like
+/// `field!` and `property!`.
+///`
+/// **For internal use only. API stablility is not guaranteed!**
+/// If you are interested in using it in your matcher, please file an issue to
+/// stabilize this.
+#[macro_export]
+macro_rules! __auto_eq {
+    ($e:expr) => {{
+        #[allow(unused_imports)]
+        use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::ExpectedKind as _;
+        match $e {
+            expected => {
+                $crate::matcher_support::__internal_unstable_do_not_depend_on_these::Wrapper(
+                    &expected,
+                )
+                .kind()
+                .matcher(expected)
+            }
+        }
+    }};
+}
+
+// This reimplements the pattern presented in
+// https://github.com/dtolnay/case-studies/issues/14
+pub mod internal {
+    use crate::{
+        matcher::MatcherBase,
+        matchers::{eq, EqMatcher},
+    };
+
+    pub struct Wrapper<T>(pub T);
+
+    impl<'a, T: MatcherBase> Wrapper<&'a T> {
+        #[inline]
+        pub fn kind(&self) -> MatcherTag {
+            MatcherTag
+        }
+    }
+
+    pub trait ExpectedKind {
+        #[inline]
+        fn kind(&self) -> ExpectedTag {
+            ExpectedTag
+        }
+    }
+
+    impl<T> ExpectedKind for Wrapper<T> {}
+
+    pub struct MatcherTag;
+
+    impl MatcherTag {
+        #[inline]
+        pub fn matcher<M>(self, matcher: M) -> M {
+            matcher
+        }
+    }
+    pub struct ExpectedTag;
+
+    impl ExpectedTag {
+        #[inline]
+        pub fn matcher<T>(self, expected: T) -> EqMatcher<T> {
+            eq(expected)
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::prelude::*;
+
+    #[test]
+    fn auto_ref_matcher() -> Result<()> {
+        verify_that!(123, __auto_eq!(ge(9)))
+    }
+
+    #[test]
+    fn auto_ref_expected() -> Result<()> {
+        verify_that!(123, __auto_eq!(123))
+    }
+
+    #[test]
+    fn auto_ref_on_ref_matcher() -> Result<()> {
+        let matcher = eq(123);
+        verify_that!(123, __auto_eq!(&matcher))
+    }
+}
diff --git a/crates/googletest/src/matcher_support/count_elements.rs b/crates/googletest/src/matcher_support/count_elements.rs
index 662dcc9..6d6b8e6 100644
--- a/crates/googletest/src/matcher_support/count_elements.rs
+++ b/crates/googletest/src/matcher_support/count_elements.rs
@@ -18,10 +18,7 @@
 /// unambiguous answer, i.e., the upper bound exists and the lower and upper
 /// bounds agree. Otherwise it iterates through `value` and counts the
 /// elements.
-pub(crate) fn count_elements<ContainerT: ?Sized>(value: &ContainerT) -> usize
-where
-    for<'b> &'b ContainerT: IntoIterator,
-{
+pub(crate) fn count_elements<ContainerT: IntoIterator>(value: ContainerT) -> usize {
     let iterator = value.into_iter();
     if let (lower, Some(higher)) = iterator.size_hint() {
         if lower == higher {
@@ -30,3 +27,53 @@
     }
     iterator.count()
 }
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use crate::prelude::*;
+
+    #[test]
+    fn count_elements_vec() -> Result<()> {
+        verify_that!(count_elements(vec![1, 2, 3]), eq(3))
+    }
+
+    #[test]
+    fn count_elements_with_imprecise_hint() -> Result<()> {
+        struct FakeIterator;
+
+        impl Iterator for FakeIterator {
+            type Item = ();
+
+            fn next(&mut self) -> Option<Self::Item> {
+                None
+            }
+
+            fn size_hint(&self) -> (usize, Option<usize>) {
+                (0, Some(123))
+            }
+        }
+
+        verify_that!(count_elements(FakeIterator), eq(0))
+    }
+
+    #[test]
+    fn count_elements_with_no_hint() -> Result<()> {
+        struct FakeIterator;
+
+        impl Iterator for FakeIterator {
+            type Item = ();
+
+            fn next(&mut self) -> Option<Self::Item> {
+                None
+            }
+
+            fn size_hint(&self) -> (usize, Option<usize>) {
+                (0, None)
+            }
+        }
+
+        verify_that!(count_elements(FakeIterator), eq(0))
+    }
+}
diff --git a/crates/googletest/src/matcher_support/edit_distance.rs b/crates/googletest/src/matcher_support/edit_distance.rs
index 8847bc9..f5e1b9a 100644
--- a/crates/googletest/src/matcher_support/edit_distance.rs
+++ b/crates/googletest/src/matcher_support/edit_distance.rs
@@ -289,7 +289,7 @@
     #[test]
     fn returns_equal_when_strings_are_equal() -> Result<()> {
         let result = edit_list(["A string"], ["A string"], Mode::Exact);
-        verify_that!(result, matches_pattern!(Difference::Equal))
+        verify_that!(result, matches_pattern!(&Difference::Equal))
     }
 
     #[test]
@@ -299,7 +299,7 @@
             ["A string (1)", "A string (2)"],
             Mode::Exact,
         );
-        verify_that!(result, matches_pattern!(Difference::Equal))
+        verify_that!(result, matches_pattern!(&Difference::Equal))
     }
 
     #[test]
@@ -307,8 +307,8 @@
         let result = edit_list(["A string"], [], Mode::Exact);
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![matches_pattern!(
-                Edit::ExtraActual(eq("A string"))
+            matches_pattern!(&Difference::Editable(ref elements_are![matches_pattern!(
+                &Edit::ExtraActual(eq("A string"))
             )]))
         )
     }
@@ -318,8 +318,8 @@
         let result = edit_list([], ["A string"], Mode::Exact);
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![matches_pattern!(
-                Edit::ExtraExpected(eq("A string"))
+            matches_pattern!(&Difference::Editable(ref elements_are![matches_pattern!(
+                &Edit::ExtraExpected(eq("A string"))
             )]))
         )
     }
@@ -329,9 +329,9 @@
         let result = edit_list(["A string"], ["Another string"], Mode::Exact);
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::ExtraActual(eq("A string"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Another string"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::ExtraActual(eq("A string"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Another string"))),
             ]))
         )
     }
@@ -342,11 +342,11 @@
             edit_list(["A string", "A string"], ["Another string", "Another string"], Mode::Exact);
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::ExtraActual(eq("A string"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Another string"))),
-                matches_pattern!(Edit::ExtraActual(eq("A string"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Another string"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::ExtraActual(eq("A string"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Another string"))),
+                matches_pattern!(&Edit::ExtraActual(eq("A string"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Another string"))),
             ]))
         )
     }
@@ -360,10 +360,10 @@
         );
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::Both(eq("Common part"))),
-                matches_pattern!(Edit::ExtraActual(eq("Actual only"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::Both(eq("Common part"))),
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only"))),
             ]))
         )
     }
@@ -373,9 +373,9 @@
         let result = edit_list(["Common part", "Actual only"], ["Common part"], Mode::Exact);
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::Both(eq("Common part"))),
-                matches_pattern!(Edit::ExtraActual(eq("Actual only"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::Both(eq("Common part"))),
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only"))),
             ]))
         )
     }
@@ -385,9 +385,9 @@
         let result = edit_list(["Common part"], ["Common part", "Expected only"], Mode::Exact);
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::Both(eq("Common part"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::Both(eq("Common part"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only"))),
             ]))
         )
     }
@@ -401,10 +401,10 @@
         );
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::ExtraActual(eq("Actual only"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only"))),
-                matches_pattern!(Edit::Both(eq("Common part"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only"))),
+                matches_pattern!(&Edit::Both(eq("Common part"))),
             ]))
         )
     }
@@ -419,19 +419,19 @@
         );
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::ExtraActual(eq("Actual only (1)"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only (1)"))),
-                matches_pattern!(Edit::Both(eq("Common part"))),
-                matches_pattern!(Edit::ExtraActual(eq("Actual only (2)"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only (2)"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only (1)"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only (1)"))),
+                matches_pattern!(&Edit::Both(eq("Common part"))),
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only (2)"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only (2)"))),
             ]))
         )
     }
 
     #[test]
-    fn returns_common_part_plus_difference_plus_common_part_when_there_is_common_prefix_and_suffix()
-    -> Result<()> {
+    fn returns_common_part_plus_difference_plus_common_part_when_there_is_common_prefix_and_suffix(
+    ) -> Result<()> {
         let result = edit_list(
             ["Common part (1)", "Actual only", "Common part (2)"],
             ["Common part (1)", "Expected only", "Common part (2)"],
@@ -439,18 +439,18 @@
         );
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::Both(eq("Common part (1)"))),
-                matches_pattern!(Edit::ExtraActual(eq("Actual only"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only"))),
-                matches_pattern!(Edit::Both(eq("Common part (2)"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::Both(eq("Common part (1)"))),
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only"))),
+                matches_pattern!(&Edit::Both(eq("Common part (2)"))),
             ]))
         )
     }
 
     #[test]
-    fn returns_common_part_plus_extra_actual_plus_common_part_when_there_is_common_prefix_and_suffix()
-    -> Result<()> {
+    fn returns_common_part_plus_extra_actual_plus_common_part_when_there_is_common_prefix_and_suffix(
+    ) -> Result<()> {
         let result = edit_list(
             ["Common part (1)", "Actual only", "Common part (2)"],
             ["Common part (1)", "Common part (2)"],
@@ -458,17 +458,17 @@
         );
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::Both(eq("Common part (1)"))),
-                matches_pattern!(Edit::ExtraActual(eq("Actual only"))),
-                matches_pattern!(Edit::Both(eq("Common part (2)"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::Both(eq("Common part (1)"))),
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only"))),
+                matches_pattern!(&Edit::Both(eq("Common part (2)"))),
             ]))
         )
     }
 
     #[test]
-    fn returns_common_part_plus_extra_expected_plus_common_part_when_there_is_common_prefix_and_suffix()
-    -> Result<()> {
+    fn returns_common_part_plus_extra_expected_plus_common_part_when_there_is_common_prefix_and_suffix(
+    ) -> Result<()> {
         let result = edit_list(
             ["Common part (1)", "Common part (2)"],
             ["Common part (1)", "Expected only", "Common part (2)"],
@@ -476,10 +476,10 @@
         );
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::Both(eq("Common part (1)"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only"))),
-                matches_pattern!(Edit::Both(eq("Common part (2)"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::Both(eq("Common part (1)"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only"))),
+                matches_pattern!(&Edit::Both(eq("Common part (2)"))),
             ]))
         )
     }
@@ -493,15 +493,15 @@
         );
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(not(contains(matches_pattern!(
-                Edit::ExtraActual(eq("Actual only"))
+            matches_pattern!(&Difference::Editable(ref not(contains(matches_pattern!(
+                &Edit::ExtraActual(eq("Actual only"))
             )))))
         )
     }
 
     #[test]
-    fn does_not_skip_extra_parts_on_actual_in_prefix_mode_at_end_when_they_are_in_common()
-    -> Result<()> {
+    fn does_not_skip_extra_parts_on_actual_in_prefix_mode_at_end_when_they_are_in_common(
+    ) -> Result<()> {
         let result = edit_list(
             ["Actual only", "Common part"],
             ["Expected only", "Common part"],
@@ -509,24 +509,24 @@
         );
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::ExtraActual(eq("Actual only"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only"))),
-                matches_pattern!(Edit::Both(eq("Common part"))),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only"))),
+                matches_pattern!(&Edit::Both(eq("Common part"))),
             ]))
         )
     }
 
     #[test]
-    fn does_not_skip_corresponding_line_on_actual_when_actual_and_expected_differ_in_prefix_mode()
-    -> Result<()> {
+    fn does_not_skip_corresponding_line_on_actual_when_actual_and_expected_differ_in_prefix_mode(
+    ) -> Result<()> {
         let result = edit_list(["Actual only"], ["Expected only"], Mode::Prefix);
         verify_that!(
             result,
-            matches_pattern!(Difference::Editable(elements_are![
-                matches_pattern!(Edit::ExtraActual(eq("Actual only"))),
-                matches_pattern!(Edit::ExtraExpected(eq("Expected only"))),
-                matches_pattern!(Edit::AdditionalActual),
+            matches_pattern!(&Difference::Editable(ref elements_are![
+                matches_pattern!(&Edit::ExtraActual(eq("Actual only"))),
+                matches_pattern!(&Edit::ExtraExpected(eq("Expected only"))),
+                matches_pattern!(&Edit::AdditionalActual),
             ]))
         )
     }
@@ -534,7 +534,7 @@
     #[test]
     fn returns_unrelated_when_maximum_distance_exceeded() -> Result<()> {
         let result = edit_list(0..=50, 60..110, Mode::Exact);
-        verify_that!(result, matches_pattern!(Difference::Unrelated))
+        verify_that!(result, matches_pattern!(&Difference::Unrelated))
     }
 
     quickcheck! {
diff --git a/crates/googletest/src/matcher_support/mod.rs b/crates/googletest/src/matcher_support/mod.rs
index 8a72ba4..8e138a1 100644
--- a/crates/googletest/src/matcher_support/mod.rs
+++ b/crates/googletest/src/matcher_support/mod.rs
@@ -18,7 +18,13 @@
 //! these facilities could be useful to downstream users writing custom
 //! matchers.
 
+mod auto_eq;
 pub(crate) mod count_elements;
 pub(crate) mod edit_distance;
 pub(crate) mod summarize_diff;
 pub(crate) mod zipped_iterator;
+
+pub mod __internal_unstable_do_not_depend_on_these {
+    pub use super::auto_eq::internal::{ExpectedKind, Wrapper};
+    pub use crate::__auto_eq as auto_eq;
+}
diff --git a/crates/googletest/src/matcher_support/summarize_diff.rs b/crates/googletest/src/matcher_support/summarize_diff.rs
index cd4efa7..b7cf641 100644
--- a/crates/googletest/src/matcher_support/summarize_diff.rs
+++ b/crates/googletest/src/matcher_support/summarize_diff.rs
@@ -17,7 +17,7 @@
 use crate::matcher_support::edit_distance;
 #[rustversion::since(1.70)]
 use std::io::IsTerminal;
-use std::{borrow::Cow, fmt::Display};
+use std::{borrow::Cow, cell::Cell, fmt::Display};
 
 /// Returns a string describing how the expected and actual lines differ.
 ///
@@ -38,10 +38,29 @@
         // line-by-line diff.
         return "".into();
     }
+
     match edit_distance::edit_list(actual_debug.lines(), expected_debug.lines(), diff_mode) {
-        edit_distance::Difference::Equal => "No difference found between debug strings.".into(),
+        edit_distance::Difference::Equal => {
+            // str.lines() is oblivious to the last newline in a
+            // string, so we need to check this to make sure we don't spuriously
+            // claim that 'hello' and 'hello\n' are identical debug strings.
+            //
+            // Although we would have liked to resolve by replacing
+            // str::lines() with str::split('\n'), the potentially
+            // empty last element interferes with good diff output for
+            // "contains" checks.
+            let actual_newline_terminated = actual_debug.ends_with('\n');
+            let expected_newline_terminated = expected_debug.ends_with('\n');
+            if actual_newline_terminated && !expected_newline_terminated {
+                "Actual includes a terminating newline that is absent from expected.".into()
+            } else if !actual_newline_terminated && expected_newline_terminated {
+                "Actual omits a terminating newline that is present in expected.".into()
+            } else {
+                "No difference found between debug strings.".into()
+            }
+        }
         edit_distance::Difference::Editable(edit_list) => {
-            format!("\n{}{}", summary_header(), edit_list.into_iter().collect::<BufferedSummary>(),)
+            format!("{}{}", summary_header(), edit_list.into_iter().collect::<BufferedSummary>(),)
                 .into()
         }
         edit_distance::Difference::Unrelated => "".into(),
@@ -73,7 +92,7 @@
         edit_distance::Difference::Equal => "No difference found between debug strings.".into(),
         edit_distance::Difference::Editable(mut edit_list) => {
             edit_list.reverse();
-            format!("\n{}{}", summary_header(), edit_list.into_iter().collect::<BufferedSummary>(),)
+            format!("{}{}", summary_header(), edit_list.into_iter().collect::<BufferedSummary>(),)
                 .into()
         }
         edit_distance::Difference::Unrelated => "".into(),
@@ -81,9 +100,9 @@
 }
 
 // Produces the header, with or without coloring depending on
-// stdout_supports_color()
+// USE_COLOR
 fn summary_header() -> Cow<'static, str> {
-    if stdout_supports_color() {
+    if USE_COLOR.with(Cell::get) {
         format!(
             "Difference(-{ACTUAL_ONLY_STYLE}actual{RESET_ALL} / +{EXPECTED_ONLY_STYLE}expected{RESET_ALL}):"
         ).into()
@@ -105,11 +124,11 @@
 impl<'a> BufferedSummary<'a> {
     // Appends a new line which is common to both actual and expected.
     fn feed_common_lines(&mut self, common_line: &'a str) {
-        if let Buffer::CommonLineBuffer(ref mut common_lines) = self.buffer {
+        if let Buffer::CommonLines(ref mut common_lines) = self.buffer {
             common_lines.push(common_line);
         } else {
             self.flush_buffer();
-            self.buffer = Buffer::CommonLineBuffer(vec![common_line]);
+            self.buffer = Buffer::CommonLines(vec![common_line]);
         }
     }
 
@@ -229,7 +248,7 @@
 
 enum Buffer<'a> {
     Empty,
-    CommonLineBuffer(Vec<&'a str>),
+    CommonLines(Vec<&'a str>),
     ExtraActualLineChunk(&'a str),
     ExtraExpectedLineChunk(&'a str),
 }
@@ -238,7 +257,7 @@
     fn flush(&mut self, summary: &mut SummaryBuilder) {
         match self {
             Buffer::Empty => {}
-            Buffer::CommonLineBuffer(common_lines) => {
+            Buffer::CommonLines(common_lines) => {
                 Self::flush_common_lines(std::mem::take(common_lines), summary);
             }
             Buffer::ExtraActualLineChunk(extra_actual) => {
@@ -294,8 +313,13 @@
     }
 }
 
+thread_local! {
+  pub(crate) static USE_COLOR: Cell<bool> = Cell::new(stdout_supports_color());
+}
+
 #[rustversion::since(1.70)]
 fn stdout_supports_color() -> bool {
+    #[allow(clippy::incompatible_msrv)]
     match (is_env_var_set("NO_COLOR"), is_env_var_set("FORCE_COLOR")) {
         (true, _) => false,
         (false, true) => true,
@@ -305,7 +329,7 @@
 
 #[rustversion::not(since(1.70))]
 fn stdout_supports_color() -> bool {
-    is_env_var_set("FORCE_COLOR")
+    is_env_var_set("FORCE_COLOR") && !is_env_var_set("NO_COLOR")
 }
 
 fn is_env_var_set(var: &'static str) -> bool {
@@ -388,14 +412,14 @@
     }
 
     fn reset_ansi(&mut self) {
-        if !self.last_ansi_style.is_empty() && stdout_supports_color() {
+        if !self.last_ansi_style.is_empty() && USE_COLOR.with(Cell::get) {
             self.summary.push_str(RESET_ALL);
             self.last_ansi_style = "";
         }
     }
 
     fn set_ansi(&mut self, ansi_style: &'static str) {
-        if !stdout_supports_color() || self.last_ansi_style == ansi_style {
+        if !USE_COLOR.with(Cell::get) || self.last_ansi_style == ansi_style {
             return;
         }
         if !self.last_ansi_style.is_empty() {
@@ -411,7 +435,6 @@
     use super::*;
     use crate::{matcher_support::edit_distance::Mode, prelude::*};
     use indoc::indoc;
-    use serial_test::{parallel, serial};
     use std::fmt::Write;
 
     // Make a long text with each element of the iterator on one line.
@@ -427,13 +450,11 @@
     }
 
     #[test]
-    #[parallel]
     fn create_diff_smaller_than_one_line() -> Result<()> {
         verify_that!(create_diff("One", "Two", Mode::Exact), eq(""))
     }
 
     #[test]
-    #[parallel]
     fn create_diff_exact_same() -> Result<()> {
         let expected = indoc! {"
             One
@@ -450,7 +471,6 @@
     }
 
     #[test]
-    #[parallel]
     fn create_diff_multiline_diff() -> Result<()> {
         let expected = indoc! {"
             prefix
@@ -469,7 +489,6 @@
             create_diff(expected, actual, Mode::Exact),
             eq(indoc!(
                 "
-
                 Difference(-actual / +expected):
                  prefix
                 -Actual#1
@@ -483,19 +502,16 @@
     }
 
     #[test]
-    #[parallel]
     fn create_diff_exact_unrelated() -> Result<()> {
         verify_that!(create_diff(&build_text(1..500), &build_text(501..1000), Mode::Exact), eq(""))
     }
 
     #[test]
-    #[parallel]
     fn create_diff_exact_small_difference() -> Result<()> {
         verify_that!(
             create_diff(&build_text(1..50), &build_text(1..51), Mode::Exact),
             eq(indoc! {
                 "
-
                 Difference(-actual / +expected):
                  1
                  2
@@ -507,33 +523,14 @@
         )
     }
 
-    // Test with color enabled.
-
-    struct ForceColor;
-
-    fn force_color() -> ForceColor {
-        std::env::set_var("FORCE_COLOR", "1");
-        std::env::remove_var("NO_COLOR");
-        ForceColor
-    }
-
-    impl Drop for ForceColor {
-        fn drop(&mut self) {
-            std::env::remove_var("FORCE_COLOR");
-            std::env::set_var("NO_COLOR", "1");
-        }
-    }
-
     #[test]
-    #[serial]
     fn create_diff_exact_small_difference_with_color() -> Result<()> {
-        let _keep = force_color();
+        USE_COLOR.with(|cell| cell.set(true));
 
         verify_that!(
             create_diff(&build_text(1..50), &build_text(1..51), Mode::Exact),
             eq(indoc! {
                 "
-
                 Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m):
                  1
                  2
@@ -546,9 +543,9 @@
     }
 
     #[test]
-    #[serial]
     fn create_diff_exact_difference_with_inline_color() -> Result<()> {
-        let _keep = force_color();
+        USE_COLOR.with(|cell| cell.set(true));
+
         let actual = indoc!(
             "There is a home in Nouvelle Orleans
             They say, it is the rising sons
@@ -565,7 +562,6 @@
             create_diff(actual, expected, Mode::Exact),
             eq(indoc! {
                 "
-
                 Difference(-\x1B[1;31mactual\x1B[0m / +\x1B[1;32mexpected\x1B[0m):
                 -\x1B[31mThere is a ho\x1B[0m\x1B[1;31mm\x1B[0m\x1B[31me in N\x1B[0m\x1B[1;31mouv\x1B[0m\x1B[31me\x1B[0m\x1B[1;31mlle\x1B[0m\x1B[31m Orleans\x1B[0m
                 +\x1B[32mThere is a ho\x1B[0m\x1B[1;32mus\x1B[0m\x1B[32me \x1B[0m\x1B[1;32mway down \x1B[0m\x1B[32min Ne\x1B[0m\x1B[1;32mw\x1B[0m\x1B[32m Orleans\x1B[0m
@@ -576,4 +572,20 @@
             })
         )
     }
+
+    #[test]
+    fn create_diff_line_termination_diff() -> Result<()> {
+        verify_that!(
+            create_diff("1\n2\n3", "1\n2\n3\n", Mode::Exact),
+            eq("Actual omits a terminating newline that is present in expected.")
+        )?;
+        verify_that!(
+            create_diff("1\n2\n3\n", "1\n2\n3", Mode::Exact),
+            eq("Actual includes a terminating newline that is absent from expected.")
+        )?;
+        verify_that!(
+            create_diff("1\n2\n3\n", "1\n2\n3\n", Mode::Exact),
+            eq("No difference found between debug strings.")
+        )
+    }
 }
diff --git a/crates/googletest/src/matchers/all_matcher.rs b/crates/googletest/src/matchers/all_matcher.rs
index f2e6d06..d03e7d4 100644
--- a/crates/googletest/src/matchers/all_matcher.rs
+++ b/crates/googletest/src/matchers/all_matcher.rs
@@ -38,7 +38,7 @@
 /// ```
 ///
 /// Using this macro is equivalent to using the
-/// [`and`][crate::matcher::Matcher::and] method:
+/// [`and`][crate::matcher::MatcherBase::and] method:
 ///
 /// ```
 /// # use googletest::prelude::*;
@@ -50,109 +50,41 @@
 /// ```
 ///
 /// Assertion failure messages are not guaranteed to be identical, however.
+///
+///  If an inner matcher is `eq(...)`, it can be omitted:
+///
+/// ```
+/// # use googletest::prelude::*;
+///
+/// verify_that!(123, all![123, lt(1000), gt(100)])
+/// #     .unwrap();
+/// ```
 #[macro_export]
 #[doc(hidden)]
 macro_rules! __all {
-    ($($matcher:expr),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::AllMatcher;
-        AllMatcher::new([$(Box::new($matcher)),*])
+    ($(,)?) => {{
+        $crate::matchers::anything()
+    }} ;
+    ($matcher:expr $(,)?) => {{
+        use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
+        auto_eq!($matcher)
+    }};
+    ($head:expr, $head2:expr $(,)?) => {{
+        use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher::new(auto_eq!($head), auto_eq!($head2))
+    }};
+    ($head:expr, $head2:expr, $($tail:expr),+ $(,)?) => {{
+        use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
+        $crate::__all![
+            $crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher::new(auto_eq!($head), auto_eq!($head2)),
+            $($tail),+
+        ]
     }}
 }
 
-/// Functionality needed by the [`all`] macro.
-///
-/// For internal use only. API stablility is not guaranteed!
-#[doc(hidden)]
-pub mod internal {
-    use crate::description::Description;
-    use crate::matcher::{Matcher, MatcherResult};
-    use crate::matchers::anything;
-    use std::fmt::Debug;
-
-    /// A matcher which matches an input value matched by all matchers in the
-    /// array `components`.
-    ///
-    /// For internal use only. API stablility is not guaranteed!
-    #[doc(hidden)]
-    pub struct AllMatcher<'a, T: Debug + ?Sized, const N: usize> {
-        components: [Box<dyn Matcher<ActualT = T> + 'a>; N],
-    }
-
-    impl<'a, T: Debug + ?Sized, const N: usize> AllMatcher<'a, T, N> {
-        /// Constructs an [`AllMatcher`] with the given component matchers.
-        ///
-        /// Intended for use only by the [`all`] macro.
-        pub fn new(components: [Box<dyn Matcher<ActualT = T> + 'a>; N]) -> Self {
-            Self { components }
-        }
-    }
-
-    impl<'a, T: Debug + ?Sized, const N: usize> Matcher for AllMatcher<'a, T, N> {
-        type ActualT = T;
-
-        fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
-            for component in &self.components {
-                match component.matches(actual) {
-                    MatcherResult::NoMatch => {
-                        return MatcherResult::NoMatch;
-                    }
-                    MatcherResult::Match => {}
-                }
-            }
-            MatcherResult::Match
-        }
-
-        fn explain_match(&self, actual: &Self::ActualT) -> Description {
-            match N {
-                0 => anything::<T>().explain_match(actual),
-                1 => self.components[0].explain_match(actual),
-                _ => {
-                    let failures = self
-                        .components
-                        .iter()
-                        .filter(|component| component.matches(actual).is_no_match())
-                        .collect::<Vec<_>>();
-
-                    if failures.len() == 1 {
-                        failures[0].explain_match(actual)
-                    } else {
-                        Description::new()
-                            .collect(
-                                failures
-                                    .into_iter()
-                                    .map(|component| component.explain_match(actual)),
-                            )
-                            .bullet_list()
-                    }
-                }
-            }
-        }
-
-        fn describe(&self, matcher_result: MatcherResult) -> Description {
-            match N {
-                0 => anything::<T>().describe(matcher_result),
-                1 => self.components[0].describe(matcher_result),
-                _ => {
-                    let header = if matcher_result.into() {
-                        "has all the following properties:"
-                    } else {
-                        "has at least one of the following properties:"
-                    };
-                    Description::new().text(header).nested(
-                        Description::new()
-                            .bullet_list()
-                            .collect(self.components.iter().map(|m| m.describe(matcher_result))),
-                    )
-                }
-            }
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
-    use super::internal;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
 
@@ -160,10 +92,10 @@
     fn description_shows_more_than_one_matcher() -> Result<()> {
         let first_matcher = starts_with("A");
         let second_matcher = ends_with("string");
-        let matcher: internal::AllMatcher<String, 2> = all!(first_matcher, second_matcher);
+        let matcher = all!(first_matcher, second_matcher);
 
         verify_that!(
-            matcher.describe(MatcherResult::Match),
+            Matcher::<&String>::describe(&matcher, MatcherResult::Match),
             displays_as(eq(indoc!(
                 "
                 has all the following properties:
@@ -176,10 +108,10 @@
     #[test]
     fn description_shows_one_matcher_directly() -> Result<()> {
         let first_matcher = starts_with("A");
-        let matcher: internal::AllMatcher<String, 1> = all!(first_matcher);
+        let matcher = all!(first_matcher);
 
         verify_that!(
-            matcher.describe(MatcherResult::Match),
+            Matcher::<&String>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("starts with prefix \"A\""))
         )
     }
@@ -189,7 +121,7 @@
     {
         let first_matcher = starts_with("Another");
         let second_matcher = ends_with("string");
-        let matcher: internal::AllMatcher<str, 2> = all!(first_matcher, second_matcher);
+        let matcher = all!(first_matcher, second_matcher);
 
         verify_that!(
             matcher.explain_match("A string"),
@@ -200,11 +132,16 @@
     #[test]
     fn mismatch_description_is_simple_when_only_one_consistuent() -> Result<()> {
         let first_matcher = starts_with("Another");
-        let matcher: internal::AllMatcher<str, 1> = all!(first_matcher);
+        let matcher = all!(first_matcher);
 
         verify_that!(
             matcher.explain_match("A string"),
             displays_as(eq("which does not start with \"Another\""))
         )
     }
+
+    #[test]
+    fn all_with_auto_eq() -> Result<()> {
+        verify_that!(42, all![eq(42), 42, lt(100)])
+    }
 }
diff --git a/crates/googletest/src/matchers/any_matcher.rs b/crates/googletest/src/matchers/any_matcher.rs
index 95d53fe..6f988c8 100644
--- a/crates/googletest/src/matchers/any_matcher.rs
+++ b/crates/googletest/src/matchers/any_matcher.rs
@@ -40,7 +40,7 @@
 /// ```
 ///
 /// Using this macro is equivalent to using the
-/// [`or`][crate::matcher::Matcher::or] method:
+/// [`or`][crate::matcher::MatcherBase::or] method:
 ///
 /// ```
 /// # use googletest::prelude::*;
@@ -52,107 +52,41 @@
 /// ```
 ///
 /// Assertion failure messages are not guaranteed to be identical, however.
+///
+///  If an inner matcher is `eq(...)`, it can be omitted:
+///
+/// ```
+/// # use googletest::prelude::*;
+///
+/// verify_that!(123, any![lt(1), 123, gt(1000)])
+/// #     .unwrap();
+/// ```
 #[macro_export]
 #[doc(hidden)]
 macro_rules! __any {
-    ($($matcher:expr),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::AnyMatcher;
-        AnyMatcher::new([$(Box::new($matcher)),*])
+    ($(,)?) => {{
+        $crate::matchers::not($crate::matchers::anything())
+    }} ;
+    ($matcher:expr $(,)?) => {{
+        use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
+        auto_eq!($matcher)
+    }};
+    ($head:expr, $head2:expr $(,)?) => {{
+        use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher::new(auto_eq!($head), auto_eq!($head2))
+    }};
+    ($head:expr, $head2:expr, $($tail:expr),+ $(,)?) => {{
+        use $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq;
+        $crate::__any![
+            $crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher::new(auto_eq!($head), auto_eq!($head2)),
+            $($tail),+
+        ]
     }}
 }
 
-/// Functionality needed by the [`any`] macro.
-///
-/// For internal use only. API stablility is not guaranteed!
-#[doc(hidden)]
-pub mod internal {
-    use crate::description::Description;
-    use crate::matcher::{Matcher, MatcherResult};
-    use crate::matchers::anything;
-    use std::fmt::Debug;
-
-    /// A matcher which matches an input value matched by all matchers in the
-    /// array `components`.
-    ///
-    /// For internal use only. API stablility is not guaranteed!
-    #[doc(hidden)]
-    pub struct AnyMatcher<'a, T: Debug + ?Sized, const N: usize> {
-        components: [Box<dyn Matcher<ActualT = T> + 'a>; N],
-    }
-
-    impl<'a, T: Debug + ?Sized, const N: usize> AnyMatcher<'a, T, N> {
-        /// Constructs an [`AnyMatcher`] with the given component matchers.
-        ///
-        /// Intended for use only by the [`all`] macro.
-        pub fn new(components: [Box<dyn Matcher<ActualT = T> + 'a>; N]) -> Self {
-            Self { components }
-        }
-    }
-
-    impl<'a, T: Debug + ?Sized, const N: usize> Matcher for AnyMatcher<'a, T, N> {
-        type ActualT = T;
-
-        fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
-            MatcherResult::from(self.components.iter().any(|c| c.matches(actual).is_match()))
-        }
-
-        fn explain_match(&self, actual: &Self::ActualT) -> Description {
-            match N {
-                0 => format!("which {}", anything::<T>().describe(MatcherResult::NoMatch)).into(),
-                1 => self.components[0].explain_match(actual),
-                _ => {
-                    let failures = self
-                        .components
-                        .iter()
-                        .filter(|component| component.matches(actual).is_no_match())
-                        .collect::<Vec<_>>();
-
-                    if failures.len() == 1 {
-                        failures[0].explain_match(actual)
-                    } else {
-                        Description::new()
-                            .collect(
-                                failures
-                                    .into_iter()
-                                    .map(|component| component.explain_match(actual)),
-                            )
-                            .bullet_list()
-                    }
-                }
-            }
-        }
-
-        fn describe(&self, matcher_result: MatcherResult) -> Description {
-            match N {
-                0 => anything::<T>().describe(matcher_result),
-                1 => self.components[0].describe(matcher_result),
-                _ => {
-                    let properties = self
-                        .components
-                        .iter()
-                        .map(|m| m.describe(matcher_result))
-                        .collect::<Description>()
-                        .bullet_list()
-                        .indent();
-                    format!(
-                        "{}:\n{properties}",
-                        if matcher_result.into() {
-                            "has at least one of the following properties"
-                        } else {
-                            "has none of the following properties"
-                        }
-                    )
-                    .into()
-                }
-            }
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
-    use super::internal;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
 
@@ -160,10 +94,10 @@
     fn description_shows_more_than_one_matcher() -> Result<()> {
         let first_matcher = starts_with("A");
         let second_matcher = ends_with("string");
-        let matcher: internal::AnyMatcher<String, 2> = any!(first_matcher, second_matcher);
+        let matcher = any!(first_matcher, second_matcher);
 
         verify_that!(
-            matcher.describe(MatcherResult::Match),
+            Matcher::<&String>::describe(&matcher, MatcherResult::Match),
             displays_as(eq(indoc!(
                 "
                 has at least one of the following properties:
@@ -176,10 +110,10 @@
     #[test]
     fn description_shows_one_matcher_directly() -> Result<()> {
         let first_matcher = starts_with("A");
-        let matcher: internal::AnyMatcher<String, 1> = any!(first_matcher);
+        let matcher = any!(first_matcher);
 
         verify_that!(
-            matcher.describe(MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("starts with prefix \"A\""))
         )
     }
@@ -189,7 +123,7 @@
     {
         let first_matcher = starts_with("Another");
         let second_matcher = ends_with("string");
-        let matcher: internal::AnyMatcher<str, 2> = any!(first_matcher, second_matcher);
+        let matcher = any!(first_matcher, second_matcher);
 
         verify_that!(
             matcher.explain_match("A string"),
@@ -200,11 +134,21 @@
     #[test]
     fn mismatch_description_is_simple_when_only_one_constituent() -> Result<()> {
         let first_matcher = starts_with("Another");
-        let matcher: internal::AnyMatcher<str, 1> = any!(first_matcher);
+        let matcher = any!(first_matcher);
 
         verify_that!(
             matcher.explain_match("A string"),
             displays_as(eq("which does not start with \"Another\""))
         )
     }
+
+    #[test]
+    fn empty_any_matcher_never_matches() -> Result<()> {
+        verify_that!(123, not(any![]))
+    }
+
+    #[test]
+    fn any_with_auto_eq() -> Result<()> {
+        verify_that!(42, any![1, 2, 42, gt(123)])
+    }
 }
diff --git a/crates/googletest/src/matchers/anything_matcher.rs b/crates/googletest/src/matchers/anything_matcher.rs
index 36be478..a920974 100644
--- a/crates/googletest/src/matchers/anything_matcher.rs
+++ b/crates/googletest/src/matchers/anything_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches anything. This matcher always succeeds.
 ///
@@ -32,16 +32,15 @@
 /// # }
 /// # should_pass().unwrap();
 /// ```
-pub fn anything<T: Debug + ?Sized>() -> impl Matcher<ActualT = T> {
-    Anything::<T>(Default::default())
+pub fn anything() -> Anything {
+    Anything
 }
 
-struct Anything<T: ?Sized>(PhantomData<T>);
+#[derive(MatcherBase)]
+pub struct Anything;
 
-impl<T: Debug + ?Sized> Matcher for Anything<T> {
-    type ActualT = T;
-
-    fn matches(&self, _: &T) -> MatcherResult {
+impl<T: Debug + Copy> Matcher<T> for Anything {
+    fn matches(&self, _: T) -> MatcherResult {
         MatcherResult::Match
     }
 
@@ -55,7 +54,6 @@
 
 #[cfg(test)]
 mod tests {
-    use super::anything;
     use crate::prelude::*;
 
     #[test]
diff --git a/crates/googletest/src/matchers/bool_matcher.rs b/crates/googletest/src/matchers/bool_matcher.rs
new file mode 100644
index 0000000..380e011
--- /dev/null
+++ b/crates/googletest/src/matchers/bool_matcher.rs
@@ -0,0 +1,99 @@
+// Copyright 2024 Google LLC
+//
+// 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.
+
+use crate::{
+    description::Description,
+    matcher::{Matcher, MatcherBase, MatcherResult},
+};
+
+/// Matches boolean value `true`.
+pub fn is_true() -> BoolMatcher {
+    BoolMatcher { expected: true }
+}
+
+/// Matches boolean value `false`.
+pub fn is_false() -> BoolMatcher {
+    BoolMatcher { expected: false }
+}
+
+/// Matches a bool value or bool reference.
+#[derive(MatcherBase)]
+pub struct BoolMatcher {
+    expected: bool,
+}
+
+impl BoolMatcher {
+    fn matches(&self, actual: bool) -> MatcherResult {
+        (actual == self.expected).into()
+    }
+
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        match (matcher_result, self.expected) {
+            (MatcherResult::Match, true) | (MatcherResult::NoMatch, false) => "is true".into(),
+            (MatcherResult::Match, false) | (MatcherResult::NoMatch, true) => "is false".into(),
+        }
+    }
+}
+
+impl Matcher<bool> for BoolMatcher {
+    fn matches(&self, actual: bool) -> MatcherResult {
+        self.matches(actual)
+    }
+
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        self.describe(matcher_result)
+    }
+}
+
+impl<'a> Matcher<&'a bool> for BoolMatcher {
+    fn matches(&self, actual: &'a bool) -> MatcherResult {
+        self.matches(*actual)
+    }
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        self.describe(matcher_result)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::prelude::*;
+
+    #[test]
+    fn match_value() -> Result<()> {
+        verify_that!(true, is_true())?;
+        verify_that!(true, not(is_false()))?;
+        verify_that!(false, is_false())?;
+        verify_that!(false, not(is_true()))
+    }
+
+    #[test]
+    fn match_ref() -> Result<()> {
+        let t = true;
+        let f = false;
+
+        verify_that!(&t, is_true())?;
+        verify_that!(&t, not(is_false()))?;
+        verify_that!(&f, is_false())?;
+        verify_that!(&f, not(is_true()))
+    }
+
+    #[test]
+    fn describe() {
+        assert_eq!(is_true().describe(MatcherResult::Match).to_string(), "is true");
+        assert_eq!(is_true().describe(MatcherResult::NoMatch).to_string(), "is false");
+        assert_eq!(is_false().describe(MatcherResult::Match).to_string(), "is false");
+        assert_eq!(is_false().describe(MatcherResult::NoMatch).to_string(), "is true");
+    }
+}
diff --git a/crates/googletest/src/matchers/char_count_matcher.rs b/crates/googletest/src/matchers/char_count_matcher.rs
index 70977d7..4f11edd 100644
--- a/crates/googletest/src/matchers/char_count_matcher.rs
+++ b/crates/googletest/src/matchers/char_count_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a string whose number of Unicode scalars matches `expected`.
 ///
@@ -56,22 +56,18 @@
 /// # }
 /// # should_pass().unwrap();
 /// ```
-pub fn char_count<T: Debug + ?Sized + AsRef<str>, E: Matcher<ActualT = usize>>(
-    expected: E,
-) -> impl Matcher<ActualT = T> {
-    CharLenMatcher { expected, phantom: Default::default() }
+pub fn char_count<E: Matcher<usize>>(expected: E) -> CharLenMatcher<E> {
+    CharLenMatcher { expected }
 }
 
-struct CharLenMatcher<T: ?Sized, E> {
+#[derive(MatcherBase)]
+pub struct CharLenMatcher<E> {
     expected: E,
-    phantom: PhantomData<T>,
 }
 
-impl<T: Debug + ?Sized + AsRef<str>, E: Matcher<ActualT = usize>> Matcher for CharLenMatcher<T, E> {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
-        self.expected.matches(&actual.as_ref().chars().count())
+impl<T: Debug + Copy + AsRef<str>, E: Matcher<usize>> Matcher<T> for CharLenMatcher<E> {
+    fn matches(&self, actual: T) -> MatcherResult {
+        self.expected.matches(actual.as_ref().chars().count())
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -89,12 +85,12 @@
         }
     }
 
-    fn explain_match(&self, actual: &T) -> Description {
+    fn explain_match(&self, actual: T) -> Description {
         let actual_size = actual.as_ref().chars().count();
         format!(
             "which has character count {}, {}",
             actual_size,
-            self.expected.explain_match(&actual_size)
+            self.expected.explain_match(actual_size)
         )
         .into()
     }
@@ -102,13 +98,11 @@
 
 #[cfg(test)]
 mod tests {
-    use super::char_count;
     use crate::description::Description;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
     use std::fmt::Debug;
-    use std::marker::PhantomData;
 
     #[test]
     fn char_count_matches_string_slice() -> Result<()> {
@@ -130,11 +124,11 @@
 
     #[test]
     fn char_count_explains_match() -> Result<()> {
-        struct TestMatcher<T>(PhantomData<T>);
-        impl<T: Debug> Matcher for TestMatcher<T> {
-            type ActualT = T;
+        #[derive(MatcherBase)]
+        struct TestMatcher;
 
-            fn matches(&self, _: &T) -> MatcherResult {
+        impl<T: Debug + Copy> Matcher<T> for TestMatcher {
+            fn matches(&self, _: T) -> MatcherResult {
                 false.into()
             }
 
@@ -142,12 +136,12 @@
                 "called described".into()
             }
 
-            fn explain_match(&self, _: &T) -> Description {
+            fn explain_match(&self, _: T) -> Description {
                 "called explain_match".into()
             }
         }
         verify_that!(
-            char_count(TestMatcher(Default::default())).explain_match(&"A string"),
+            char_count(TestMatcher).explain_match("A string"),
             displays_as(eq("which has character count 8, called explain_match"))
         )
     }
diff --git a/crates/googletest/src/matchers/conjunction_matcher.rs b/crates/googletest/src/matchers/conjunction_matcher.rs
index dc50833..b2e2e27 100644
--- a/crates/googletest/src/matchers/conjunction_matcher.rs
+++ b/crates/googletest/src/matchers/conjunction_matcher.rs
@@ -17,56 +17,87 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
 use std::fmt::Debug;
 
-/// Matcher created by [`Matcher::and`].
+/// Matcher created by [`Matcher::and`] and [`all!`].
+///
+/// Both [`Matcher::and`] and [`all!`] nest on m1. In other words,
+/// both `x.and(y).and(z)` and `all![x, y, z]` produce:
+/// ```ignore
+/// ConjunctionMatcher {
+///     m1: ConjunctionMatcher {
+///         m1: x,
+///         m2: y
+///     },
+///     m2: z
+/// }
+/// ```
+///
+/// This behavior must be respected
+/// to ensure that [`Matcher::explain_match`] and [`Matcher::describe`] produce
+/// useful descriptions.
 ///
 /// **For internal use only. API stablility is not guaranteed!**
 #[doc(hidden)]
+#[derive(MatcherBase)]
 pub struct ConjunctionMatcher<M1, M2> {
     m1: M1,
     m2: M2,
 }
 
 impl<M1, M2> ConjunctionMatcher<M1, M2> {
-    pub(crate) fn new(m1: M1, m2: M2) -> Self {
+    pub fn new(m1: M1, m2: M2) -> Self {
         Self { m1, m2 }
     }
 }
 
-impl<M1: Matcher, M2: Matcher<ActualT = M1::ActualT>> Matcher for ConjunctionMatcher<M1, M2>
-where
-    M1::ActualT: Debug,
-{
-    type ActualT = M1::ActualT;
-
-    fn matches(&self, actual: &M1::ActualT) -> MatcherResult {
+impl<T: Debug + Copy, M1: Matcher<T>, M2: Matcher<T>> Matcher<T> for ConjunctionMatcher<M1, M2> {
+    fn matches(&self, actual: T) -> MatcherResult {
         match (self.m1.matches(actual), self.m2.matches(actual)) {
             (MatcherResult::Match, MatcherResult::Match) => MatcherResult::Match,
             _ => MatcherResult::NoMatch,
         }
     }
 
-    fn explain_match(&self, actual: &M1::ActualT) -> Description {
+    fn explain_match(&self, actual: T) -> Description {
         match (self.m1.matches(actual), self.m2.matches(actual)) {
-            (MatcherResult::Match, MatcherResult::Match) => Description::new()
-                .nested(self.m1.explain_match(actual))
-                .text("and")
-                .nested(self.m2.explain_match(actual)),
             (MatcherResult::NoMatch, MatcherResult::Match) => self.m1.explain_match(actual),
             (MatcherResult::Match, MatcherResult::NoMatch) => self.m2.explain_match(actual),
-            (MatcherResult::NoMatch, MatcherResult::NoMatch) => Description::new()
-                .nested(self.m1.explain_match(actual))
-                .text("and")
-                .nested(self.m2.explain_match(actual)),
+            (_, _) => {
+                let m1_description = self.m1.explain_match(actual);
+                if m1_description.is_conjunction_description() {
+                    m1_description.nested(self.m2.explain_match(actual))
+                } else {
+                    Description::new()
+                        .bullet_list()
+                        .collect([m1_description, self.m2.explain_match(actual)])
+                        .conjunction_description()
+                }
+            }
         }
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
-        format!("{}, and {}", self.m1.describe(matcher_result), self.m2.describe(matcher_result))
-            .into()
+        let m1_description = self.m1.describe(matcher_result);
+        if m1_description.is_conjunction_description() {
+            m1_description.push_in_last_nested(self.m2.describe(matcher_result))
+        } else {
+            let header = if matcher_result.into() {
+                "has all the following properties:"
+            } else {
+                "has at least one of the following properties:"
+            };
+            Description::new()
+                .text(header)
+                .nested(
+                    Description::new()
+                        .bullet_list()
+                        .collect([m1_description, self.m2.describe(matcher_result)]),
+                )
+                .conjunction_description()
+        }
     }
 }
 
@@ -88,7 +119,9 @@
             err(displays_as(contains_substring(indoc!(
                 "
                 Value of: 1
-                Expected: is anything, and never matches
+                Expected: has all the following properties:
+                  * is anything
+                  * never matches
                 Actual: 1,
                   which is anything
                 "
@@ -104,7 +137,9 @@
             err(displays_as(contains_substring(indoc!(
                 "
                     Value of: 1
-                    Expected: never matches, and is anything
+                    Expected: has all the following properties:
+                      * never matches
+                      * is anything
                     Actual: 1,
                       which is anything
                 "
@@ -120,11 +155,37 @@
             err(displays_as(contains_substring(indoc!(
                 "
                 Value of: 1
-                Expected: never matches, and never matches
+                Expected: has all the following properties:
+                  * never matches
+                  * never matches
                 Actual: 1,
-                    which is anything
-                  and
-                    which is anything
+                  * which is anything
+                  * which is anything
+                "
+            ))))
+        )
+    }
+
+    #[test]
+    fn and_long_chain_of_matchers() -> Result<()> {
+        let result = verify_that!(
+            1,
+            anything().and(not(anything())).and(anything()).and(not(anything())).and(anything())
+        );
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                "
+                Value of: 1
+                Expected: has all the following properties:
+                  * is anything
+                  * never matches
+                  * is anything
+                  * never matches
+                  * is anything
+                Actual: 1,
+                  * which is anything
+                  * which is anything
                 "
             ))))
         )
@@ -132,7 +193,7 @@
 
     #[test]
     fn chained_and_matches() -> Result<()> {
-        #[derive(Debug)]
+        #[derive(Debug, Clone, Copy)]
         struct Struct {
             a: i32,
             b: i32,
diff --git a/crates/googletest/src/matchers/container_eq_matcher.rs b/crates/googletest/src/matchers/container_eq_matcher.rs
index d4f872c..7eb0933 100644
--- a/crates/googletest/src/matchers/container_eq_matcher.rs
+++ b/crates/googletest/src/matchers/container_eq_matcher.rs
@@ -13,9 +13,8 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use std::fmt::Debug;
-use std::marker::PhantomData;
 
 /// Matches a container equal (in the sense of `==`) to `expected`.
 ///
@@ -30,15 +29,12 @@
 ///   Unexpected: [4]
 /// ```
 ///
-/// The actual value must be a container such as a `Vec`, an array, or a
-/// dereferenced slice. More precisely, a shared borrow of the actual value must
+/// The actual value must be a container such as a `&Vec`, an array, or a
+/// dereferenced slice. More precisely, the actual value must
 /// implement [`IntoIterator`] whose `Item` type implements
 /// [`PartialEq<ExpectedT>`], where `ExpectedT` is the element type of the
 /// expected value.
 ///
-/// If the container type is a `Vec`, then the expected type may be a slice of
-/// the same element type. For example:
-///
 /// ```
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
@@ -49,78 +45,40 @@
 /// # should_pass().unwrap();
 /// ```
 ///
-/// As an exception, if the actual type is a `Vec<String>`, the expected type
-/// may be a slice of `&str`:
-///
-/// ```
-/// # use googletest::prelude::*;
-/// # fn should_pass() -> Result<()> {
-/// let vec: Vec<String> = vec!["A string".into(), "Another string".into()];
-/// verify_that!(vec, container_eq(["A string", "Another string"]))?;
-/// #     Ok(())
-/// # }
-/// # should_pass().unwrap();
-/// ```
-///
-/// These exceptions allow one to avoid unnecessary allocations in test
-/// assertions.
-///
-/// One can also check container equality of a slice with an array. To do so,
-/// dereference the slice:
-///
-/// ```
-/// # use googletest::prelude::*;
-/// # fn should_pass() -> Result<()> {
-/// let value = &[1, 2, 3];
-/// verify_that!(*value, container_eq([1, 2, 3]))?;
-/// #     Ok(())
-/// # }
-/// # should_pass().unwrap();
-/// ```
-///
-/// Otherwise, the actual and expected types must be identical.
-///
 /// *Performance note*: In the event of a mismatch leading to an assertion
 /// failure, the construction of the lists of missing and unexpected values
 /// uses a naive algorithm requiring time proportional to the product of the
 /// sizes of the expected and actual values. This should therefore only be used
 /// when the containers are small enough that this is not a problem.
-// This returns ContainerEqMatcher and not impl Matcher because
-// ContainerEqMatcher has some specialisations for slice types (see
-// documentation above). Returning impl Matcher would hide those from the
-// compiler.
-pub fn container_eq<ActualContainerT, ExpectedContainerT>(
+pub fn container_eq<ExpectedContainerT>(
     expected: ExpectedContainerT,
-) -> ContainerEqMatcher<ActualContainerT, ExpectedContainerT>
+) -> ContainerEqMatcher<ExpectedContainerT>
 where
-    ActualContainerT: PartialEq<ExpectedContainerT> + Debug + ?Sized,
     ExpectedContainerT: Debug,
 {
-    ContainerEqMatcher { expected, phantom: Default::default() }
+    ContainerEqMatcher { expected }
 }
 
-pub struct ContainerEqMatcher<ActualContainerT: ?Sized, ExpectedContainerT> {
+#[derive(MatcherBase)]
+pub struct ContainerEqMatcher<ExpectedContainerT> {
     expected: ExpectedContainerT,
-    phantom: PhantomData<ActualContainerT>,
 }
 
-impl<ActualElementT, ActualContainerT, ExpectedElementT, ExpectedContainerT> Matcher
-    for ContainerEqMatcher<ActualContainerT, ExpectedContainerT>
+impl<ActualElementT, ActualContainerT, ExpectedElementT, ExpectedContainerT>
+    Matcher<ActualContainerT> for ContainerEqMatcher<ExpectedContainerT>
 where
-    ActualElementT: PartialEq<ExpectedElementT> + Debug + ?Sized,
-    ActualContainerT: PartialEq<ExpectedContainerT> + Debug + ?Sized,
+    ActualElementT: for<'a> PartialEq<&'a ExpectedElementT> + Debug + Copy,
+    ActualContainerT: for<'a> PartialEq<&'a ExpectedContainerT> + Debug + Copy,
     ExpectedElementT: Debug,
     ExpectedContainerT: Debug,
-    for<'a> &'a ActualContainerT: IntoIterator<Item = &'a ActualElementT>,
+    ActualContainerT: IntoIterator<Item = ActualElementT>,
     for<'a> &'a ExpectedContainerT: IntoIterator<Item = &'a ExpectedElementT>,
 {
-    type ActualT = ActualContainerT;
-
-    fn matches(&self, actual: &ActualContainerT) -> MatcherResult {
-        (*actual == self.expected).into()
+    fn matches(&self, actual: ActualContainerT) -> MatcherResult {
+        (actual == &self.expected).into()
     }
 
-    fn explain_match(&self, actual: &ActualContainerT) -> Description {
+    fn explain_match(&self, actual: ActualContainerT) -> Description {
         build_explanation(self.get_missing_items(actual), self.get_unexpected_items(actual)).into()
     }
 
@@ -132,20 +90,32 @@
     }
 }
 
-impl<ActualElementT, ActualContainerT, ExpectedElementT, ExpectedContainerT>
-    ContainerEqMatcher<ActualContainerT, ExpectedContainerT>
+impl<ExpectedElementT, ExpectedContainerT> ContainerEqMatcher<ExpectedContainerT>
 where
-    ActualElementT: PartialEq<ExpectedElementT> + ?Sized,
-    ActualContainerT: PartialEq<ExpectedContainerT> + ?Sized,
-    for<'a> &'a ActualContainerT: IntoIterator<Item = &'a ActualElementT>,
     for<'a> &'a ExpectedContainerT: IntoIterator<Item = &'a ExpectedElementT>,
 {
-    fn get_missing_items(&self, actual: &ActualContainerT) -> Vec<&ExpectedElementT> {
-        self.expected.into_iter().filter(|&i| !actual.into_iter().any(|j| j == i)).collect()
+    fn get_missing_items<ActualElementT, ActualContainerT>(
+        &self,
+        actual: ActualContainerT,
+    ) -> Vec<&'_ ExpectedElementT>
+    where
+        ActualElementT: for<'a> PartialEq<&'a ExpectedElementT> + Copy,
+        ActualContainerT: for<'a> PartialEq<&'a ExpectedContainerT> + Copy,
+        ActualContainerT: IntoIterator<Item = ActualElementT>,
+    {
+        self.expected.into_iter().filter(|i| !actual.into_iter().any(|j| j == *i)).collect()
     }
 
-    fn get_unexpected_items<'a>(&self, actual: &'a ActualContainerT) -> Vec<&'a ActualElementT> {
-        actual.into_iter().filter(|&i| !self.expected.into_iter().any(|j| i == j)).collect()
+    fn get_unexpected_items<ActualElementT, ActualContainerT>(
+        &self,
+        actual: ActualContainerT,
+    ) -> Vec<ActualElementT>
+    where
+        ActualElementT: for<'a> PartialEq<&'a ExpectedElementT> + Copy,
+        ActualContainerT: for<'a> PartialEq<&'a ExpectedContainerT> + Copy,
+        ActualContainerT: IntoIterator<Item = ActualElementT>,
+    {
+        actual.into_iter().filter(|i| !self.expected.into_iter().any(|j| i == &j)).collect()
     }
 }
 
@@ -185,8 +155,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::container_eq;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
     use std::collections::HashSet;
@@ -199,7 +168,7 @@
     #[test]
     fn container_eq_matches_array_with_slice() -> Result<()> {
         let value = &[1, 2, 3];
-        verify_that!(*value, container_eq([1, 2, 3]))
+        verify_that!(value, container_eq([1, 2, 3]))
     }
 
     #[test]
@@ -271,15 +240,15 @@
     }
 
     #[test]
-    fn container_eq_matches_owned_vec_of_owned_strings_with_slice_of_string_references()
-    -> Result<()> {
+    fn container_eq_matches_owned_vec_of_owned_strings_with_slice_of_string_references(
+    ) -> Result<()> {
         let vector = vec!["A string".to_string(), "Another string".to_string()];
         verify_that!(vector, container_eq(["A string", "Another string"]))
     }
 
     #[test]
-    fn container_eq_matches_owned_vec_of_owned_strings_with_shorter_slice_of_string_references()
-    -> Result<()> {
+    fn container_eq_matches_owned_vec_of_owned_strings_with_shorter_slice_of_string_references(
+    ) -> Result<()> {
         let actual = vec!["A string".to_string(), "Another string".to_string()];
         let matcher = container_eq(["A string"]);
 
diff --git a/crates/googletest/src/matchers/contains_matcher.rs b/crates/googletest/src/matchers/contains_matcher.rs
index 1a27ce0..3ce60ec 100644
--- a/crates/googletest/src/matchers/contains_matcher.rs
+++ b/crates/googletest/src/matchers/contains_matcher.rs
@@ -14,11 +14,12 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
-/// Matches an iterable type whose elements contain a value matched by `inner`.
+/// Matches an [`IntoIterator`] type whose elements contain a value matched by
+/// `inner`.
 ///
 /// By default, this matches a container with any number of elements matched
 /// by `inner`. Use the method [`ContainsMatcher::times`] to constrain the
@@ -28,11 +29,11 @@
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
 /// verify_that!(["Some value"], contains(eq("Some value")))?;  // Passes
-/// verify_that!(vec!["Some value"], contains(eq("Some value")))?;  // Passes
+/// verify_that!(vec!["Some value"], contains(eq(&"Some value")))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail_1() -> Result<()> {
-/// verify_that!([] as [String; 0], contains(eq("Some value")))?;   // Fails
+/// verify_that!([] as [&String; 0], contains(eq("Some value")))?;   // Fails
 /// #     Ok(())
 /// # }
 /// # fn should_fail_2() -> Result<()> {
@@ -43,19 +44,19 @@
 /// # should_fail_1().unwrap_err();
 /// # should_fail_2().unwrap_err();
 /// ```
-pub fn contains<T, InnerMatcherT>(inner: InnerMatcherT) -> ContainsMatcher<T, InnerMatcherT> {
-    ContainsMatcher { inner, count: None, phantom: Default::default() }
+pub fn contains<InnerMatcherT>(inner: InnerMatcherT) -> ContainsMatcher<InnerMatcherT> {
+    ContainsMatcher { inner, count: None }
 }
 
 /// A matcher which matches a container containing one or more elements a given
 /// inner [`Matcher`] matches.
-pub struct ContainsMatcher<T, InnerMatcherT> {
+#[derive(MatcherBase)]
+pub struct ContainsMatcher<InnerMatcherT> {
     inner: InnerMatcherT,
-    count: Option<Box<dyn Matcher<ActualT = usize>>>,
-    phantom: PhantomData<T>,
+    count: Option<Box<dyn Matcher<usize>>>,
 }
 
-impl<T, InnerMatcherT> ContainsMatcher<T, InnerMatcherT> {
+impl<InnerMatcherT> ContainsMatcher<InnerMatcherT> {
     /// Configures this instance to match containers which contain a number of
     /// matching items matched by `count`.
     ///
@@ -68,7 +69,7 @@
     ///
     /// One can also use `times(eq(0))` to test for the *absence* of an item
     /// matching the expected value.
-    pub fn times(mut self, count: impl Matcher<ActualT = usize> + 'static) -> Self {
+    pub fn times(mut self, count: impl Matcher<usize> + 'static) -> Self {
         self.count = Some(Box::new(count));
         self
     }
@@ -84,16 +85,14 @@
 //  because val is dropped before matcher but the trait bound requires that
 //  the argument to matches outlive the matcher. It works fine if one defines
 //  val before matcher.
-impl<T: Debug, InnerMatcherT: Matcher<ActualT = T>, ContainerT: Debug> Matcher
-    for ContainsMatcher<ContainerT, InnerMatcherT>
+impl<T: Debug + Copy, InnerMatcherT: Matcher<T>, ContainerT: Debug + Copy> Matcher<ContainerT>
+    for ContainsMatcher<InnerMatcherT>
 where
-    for<'a> &'a ContainerT: IntoIterator<Item = &'a T>,
+    ContainerT: IntoIterator<Item = T>,
 {
-    type ActualT = ContainerT;
-
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
+    fn matches(&self, actual: ContainerT) -> MatcherResult {
         if let Some(count) = &self.count {
-            count.matches(&self.count_matches(actual))
+            count.matches(self.count_matches(actual))
         } else {
             for v in actual.into_iter() {
                 if self.inner.matches(v).into() {
@@ -104,7 +103,7 @@
         }
     }
 
-    fn explain_match(&self, actual: &Self::ActualT) -> Description {
+    fn explain_match(&self, actual: ContainerT) -> Description {
         let count = self.count_matches(actual);
         match (count, &self.count) {
             (_, Some(_)) => format!("which contains {} matching elements", count).into(),
@@ -140,11 +139,11 @@
     }
 }
 
-impl<ActualT, InnerMatcherT> ContainsMatcher<ActualT, InnerMatcherT> {
-    fn count_matches<T: Debug, ContainerT>(&self, actual: &ContainerT) -> usize
+impl<InnerMatcherT> ContainsMatcher<InnerMatcherT> {
+    fn count_matches<T: Debug + Copy, ContainerT>(&self, actual: ContainerT) -> usize
     where
-        for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
-        InnerMatcherT: Matcher<ActualT = T>,
+        ContainerT: IntoIterator<Item = T>,
+        InnerMatcherT: Matcher<T>,
     {
         let mut count = 0;
         for v in actual.into_iter() {
@@ -158,13 +157,12 @@
 
 #[cfg(test)]
 mod tests {
-    use super::{contains, ContainsMatcher};
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
 
     #[test]
     fn contains_matches_singleton_slice_with_value() -> Result<()> {
-        let matcher = contains(eq(1));
+        let matcher = contains(eq(&1));
 
         let result = matcher.matches(&vec![1]);
 
@@ -173,7 +171,7 @@
 
     #[test]
     fn contains_matches_singleton_vec_with_value() -> Result<()> {
-        let matcher = contains(eq(1));
+        let matcher = contains(eq(&1));
 
         let result = matcher.matches(&vec![1]);
 
@@ -182,7 +180,7 @@
 
     #[test]
     fn contains_matches_two_element_slice_with_value() -> Result<()> {
-        let matcher = contains(eq(1));
+        let matcher = contains(eq(&1));
 
         let result = matcher.matches(&[0, 1]);
 
@@ -191,7 +189,7 @@
 
     #[test]
     fn contains_does_not_match_singleton_slice_with_wrong_value() -> Result<()> {
-        let matcher = contains(eq(1));
+        let matcher = contains(eq(&1));
 
         let result = matcher.matches(&[0]);
 
@@ -200,16 +198,16 @@
 
     #[test]
     fn contains_does_not_match_empty_slice() -> Result<()> {
-        let matcher = contains(eq::<i32, _>(1));
+        let matcher = contains(eq(&1));
 
-        let result = matcher.matches(&[]);
+        let result = matcher.matches(&[1; 0]);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
     #[test]
     fn contains_matches_slice_with_repeated_value() -> Result<()> {
-        let matcher = contains(eq(1)).times(eq(2));
+        let matcher = contains(eq(&1)).times(eq(2));
 
         let result = matcher.matches(&[1, 1]);
 
@@ -218,7 +216,7 @@
 
     #[test]
     fn contains_does_not_match_slice_with_too_few_of_value() -> Result<()> {
-        let matcher = contains(eq(1)).times(eq(2));
+        let matcher = contains(eq(&1)).times(eq(2));
 
         let result = matcher.matches(&[0, 1]);
 
@@ -227,7 +225,7 @@
 
     #[test]
     fn contains_does_not_match_slice_with_too_many_of_value() -> Result<()> {
-        let matcher = contains(eq(1)).times(eq(1));
+        let matcher = contains(eq(&1)).times(eq(1));
 
         let result = matcher.matches(&[1, 1]);
 
@@ -236,20 +234,20 @@
 
     #[test]
     fn contains_formats_without_multiplicity_by_default() -> Result<()> {
-        let matcher: ContainsMatcher<Vec<i32>, _> = contains(eq(1));
+        let matcher = contains(eq(&1));
 
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&Vec<i32>>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("contains at least one element which is equal to 1"))
         )
     }
 
     #[test]
     fn contains_formats_with_multiplicity_when_specified() -> Result<()> {
-        let matcher: ContainsMatcher<Vec<i32>, _> = contains(eq(1)).times(eq(2));
+        let matcher = contains(eq(&1)).times(eq(2));
 
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&Vec<i32>>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("contains n elements which is equal to 1\n  where n is equal to 2"))
         )
     }
@@ -257,7 +255,7 @@
     #[test]
     fn contains_mismatch_shows_number_of_times_element_was_found() -> Result<()> {
         verify_that!(
-            contains(eq(3)).times(eq(1)).explain_match(&vec![1, 2, 3, 3]),
+            contains(eq(&3)).times(eq(1)).explain_match(&vec![1, 2, 3, 3]),
             displays_as(eq("which contains 2 matching elements"))
         )
     }
@@ -265,7 +263,7 @@
     #[test]
     fn contains_mismatch_shows_when_matches() -> Result<()> {
         verify_that!(
-            contains(eq(3)).explain_match(&vec![1, 2, 3, 3]),
+            contains(eq(&3)).explain_match(&vec![1, 2, 3, 3]),
             displays_as(eq("which contains a matching element"))
         )
     }
@@ -273,7 +271,7 @@
     #[test]
     fn contains_mismatch_shows_when_no_matches() -> Result<()> {
         verify_that!(
-            contains(eq(3)).explain_match(&vec![1, 2]),
+            contains(eq(&3)).explain_match(&vec![1, 2]),
             displays_as(eq("which does not contain a matching element"))
         )
     }
diff --git a/crates/googletest/src/matchers/contains_regex_matcher.rs b/crates/googletest/src/matchers/contains_regex_matcher.rs
index 6f68168..61a2d30 100644
--- a/crates/googletest/src/matchers/contains_regex_matcher.rs
+++ b/crates/googletest/src/matchers/contains_regex_matcher.rs
@@ -13,10 +13,9 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use regex::Regex;
 use std::fmt::Debug;
-use std::marker::PhantomData;
 use std::ops::Deref;
 
 /// Matches a string containing a substring which matches the given regular
@@ -47,18 +46,9 @@
 ///
 /// Panics if the given `pattern` is not a syntactically valid regular
 /// expression.
-// N.B. This returns the concrete type rather than an impl Matcher so that it
-// can act simultaneously as a Matcher<str> and a Matcher<String>. Otherwise the
-// compiler treats it as a Matcher<str> only and the code
-//   verify_that!("Some value".to_string(), contains_regex(".*value"))?;
-// doesn't compile.
-pub fn contains_regex<ActualT: ?Sized, PatternT: Deref<Target = str>>(
-    pattern: PatternT,
-) -> ContainsRegexMatcher<ActualT> {
-    ContainsRegexMatcher {
-        regex: Regex::new(pattern.deref()).unwrap(),
-        phantom: Default::default(),
-    }
+#[track_caller]
+pub fn contains_regex<PatternT: Deref<Target = str>>(pattern: PatternT) -> ContainsRegexMatcher {
+    ContainsRegexMatcher { regex: Regex::new(pattern.deref()).unwrap() }
 }
 
 /// A matcher matching a string-like type containing a substring matching a
@@ -66,15 +56,13 @@
 ///
 /// Intended only to be used from the function [`contains_regex`] only.
 /// Should not be referenced by code outside this library.
-pub struct ContainsRegexMatcher<ActualT: ?Sized> {
+#[derive(MatcherBase)]
+pub struct ContainsRegexMatcher {
     regex: Regex,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ActualT: AsRef<str> + Debug + ?Sized> Matcher for ContainsRegexMatcher<ActualT> {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
+impl<ActualT: AsRef<str> + Debug + Copy> Matcher<ActualT> for ContainsRegexMatcher {
+    fn matches(&self, actual: ActualT) -> MatcherResult {
         self.regex.is_match(actual.as_ref()).into()
     }
 
@@ -92,8 +80,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::{contains_regex, ContainsRegexMatcher};
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
 
     #[test]
@@ -139,10 +126,10 @@
 
     #[test]
     fn contains_regex_displays_quoted_debug_of_pattern() -> Result<()> {
-        let matcher: ContainsRegexMatcher<&str> = contains_regex("\n");
+        let matcher = contains_regex("\n");
 
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("contains the regular expression \"\\n\""))
         )
     }
diff --git a/crates/googletest/src/matchers/derefs_to_matcher.rs b/crates/googletest/src/matchers/derefs_to_matcher.rs
new file mode 100644
index 0000000..2c9082e
--- /dev/null
+++ b/crates/googletest/src/matchers/derefs_to_matcher.rs
@@ -0,0 +1,99 @@
+// Copyright 2024 Google LLC
+//
+// 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.
+
+use crate::{
+    description::Description,
+    matcher::{Matcher, MatcherBase, MatcherResult},
+};
+use std::{fmt::Debug, ops::Deref};
+
+/// Dereferences the `actual` value and verifies that the returned reference
+/// matches the `inner` matcher.
+///
+/// ```
+/// # use googletest::{matchers::{derefs_to, eq}, verify_that};
+/// verify_that!(Box::new(123), derefs_to(eq(&123)))
+/// #    .unwrap()
+/// ```
+pub fn derefs_to<Inner>(inner: Inner) -> DerefsTo<Inner> {
+    DerefsTo { inner }
+}
+
+/// A matcher which derefs a value and verifies that the result matches the
+/// `inner` matcher.
+///
+/// See [`derefs_to`].
+#[derive(MatcherBase)]
+pub struct DerefsTo<InnerT> {
+    pub(crate) inner: InnerT,
+}
+
+impl<'a, ActualT, ExpectedT, Inner> Matcher<&'a ActualT> for DerefsTo<Inner>
+where
+    ActualT: Deref<Target = ExpectedT> + Debug,
+    ExpectedT: Copy + Debug + 'a,
+    Inner: Matcher<&'a ExpectedT>,
+{
+    fn matches(&self, actual: &'a ActualT) -> MatcherResult {
+        self.inner.matches(actual.deref())
+    }
+
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        self.inner.describe(matcher_result)
+    }
+
+    fn explain_match(&self, actual: &'a ActualT) -> Description {
+        self.inner.explain_match(actual.deref())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::rc::Rc;
+
+    use crate::prelude::*;
+    use indoc::indoc;
+
+    #[test]
+    fn deref_to_matches_box_of_int_with_int() -> Result<()> {
+        let actual = Box::new(123);
+        verify_that!(actual, derefs_to(eq(&123)))
+    }
+
+    #[test]
+    fn deref_to_matches_rc_of_int_with_int() -> Result<()> {
+        verify_that!(Rc::new(123), derefs_to(eq(&123)))
+    }
+
+    #[test]
+    fn deref_to_combines_with_points_to_for_copy() -> Result<()> {
+        verify_that!(Rc::new(123), derefs_to(points_to(eq(123))))
+    }
+
+    #[test]
+    fn match_explanation_references_actual_value() -> Result<()> {
+        let actual = Box::new(1);
+        let result = verify_that!(actual, derefs_to(eq(&0)));
+
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                "
+                    Actual: 1,
+                      which isn't equal to 0
+                "
+            ))))
+        )
+    }
+}
diff --git a/crates/googletest/src/matchers/disjunction_matcher.rs b/crates/googletest/src/matchers/disjunction_matcher.rs
index dd56be2..77e18f6 100644
--- a/crates/googletest/src/matchers/disjunction_matcher.rs
+++ b/crates/googletest/src/matchers/disjunction_matcher.rs
@@ -17,48 +17,81 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
 use std::fmt::Debug;
 
-/// Matcher created by [`Matcher::or`].
+/// Matcher created by [`Matcher::or`] and [`any!`].
 ///
+/// Both [`Matcher::or`] and [`any!`] nest on m1. In other words,
+/// both `x.or(y).or(z)` and `any![x, y, z]` produce:
+/// ```ignore
+/// DisjunctionMatcher {
+///     m1: DisjunctionMatcher {
+///         m1: x, m2: y
+///     },
+///     m2: z
+/// }
+/// ```
 /// **For internal use only. API stablility is not guaranteed!**
 #[doc(hidden)]
+#[derive(MatcherBase)]
 pub struct DisjunctionMatcher<M1, M2> {
     m1: M1,
     m2: M2,
 }
 
 impl<M1, M2> DisjunctionMatcher<M1, M2> {
-    pub(crate) fn new(m1: M1, m2: M2) -> Self {
+    pub fn new(m1: M1, m2: M2) -> Self {
         Self { m1, m2 }
     }
 }
 
-impl<M1: Matcher, M2: Matcher<ActualT = M1::ActualT>> Matcher for DisjunctionMatcher<M1, M2>
-where
-    M1::ActualT: Debug,
-{
-    type ActualT = M1::ActualT;
-
-    fn matches(&self, actual: &M1::ActualT) -> MatcherResult {
+impl<T: Debug + Copy, M1: Matcher<T>, M2: Matcher<T>> Matcher<T> for DisjunctionMatcher<M1, M2> {
+    fn matches(&self, actual: T) -> MatcherResult {
         match (self.m1.matches(actual), self.m2.matches(actual)) {
             (MatcherResult::NoMatch, MatcherResult::NoMatch) => MatcherResult::NoMatch,
             _ => MatcherResult::Match,
         }
     }
 
-    fn explain_match(&self, actual: &M1::ActualT) -> Description {
-        Description::new()
-            .nested(self.m1.explain_match(actual))
-            .text("and")
-            .nested(self.m2.explain_match(actual))
+    fn explain_match(&self, actual: T) -> Description {
+        match (self.m1.matches(actual), self.m2.matches(actual)) {
+            (MatcherResult::NoMatch, MatcherResult::Match) => self.m1.explain_match(actual),
+            (MatcherResult::Match, MatcherResult::NoMatch) => self.m2.explain_match(actual),
+            (_, _) => {
+                let m1_description = self.m1.explain_match(actual);
+                if m1_description.is_disjunction_description() {
+                    m1_description.nested(self.m2.explain_match(actual))
+                } else {
+                    Description::new()
+                        .bullet_list()
+                        .collect([m1_description, self.m2.explain_match(actual)])
+                        .disjunction_description()
+                }
+            }
+        }
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
-        format!("{}, or {}", self.m1.describe(matcher_result), self.m2.describe(matcher_result))
-            .into()
+        let m1_description = self.m1.describe(matcher_result);
+        if m1_description.is_disjunction_description() {
+            m1_description.push_in_last_nested(self.m2.describe(matcher_result))
+        } else {
+            let header = if matcher_result.into() {
+                "has at least one of the following properties:"
+            } else {
+                "has all of the following properties:"
+            };
+            Description::new()
+                .text(header)
+                .nested(
+                    Description::new()
+                        .bullet_list()
+                        .collect([m1_description, self.m2.describe(matcher_result)]),
+                )
+                .disjunction_description()
+        }
     }
 }
 
@@ -90,11 +123,12 @@
             err(displays_as(contains_substring(indoc!(
                 "
                 Value of: 1
-                Expected: never matches, or never matches
+                Expected: has at least one of the following properties:
+                  * never matches
+                  * never matches
                 Actual: 1,
-                    which is anything
-                  and
-                    which is anything
+                  * which is anything
+                  * which is anything
                 "
             ))))
         )
diff --git a/crates/googletest/src/matchers/display_matcher.rs b/crates/googletest/src/matchers/display_matcher.rs
index 51a5bff..9edccca 100644
--- a/crates/googletest/src/matchers/display_matcher.rs
+++ b/crates/googletest/src/matchers/display_matcher.rs
@@ -13,9 +13,8 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use std::fmt::{Debug, Display};
-use std::marker::PhantomData;
 
 /// Matches the string representation of types that implement `Display`.
 ///
@@ -23,29 +22,31 @@
 /// let result: impl Display = ...;
 /// verify_that!(result, displays_as(eq(format!("{}", result))))?;
 /// ```
-pub fn displays_as<T: Debug + Display, InnerMatcher: Matcher<ActualT = String>>(
+pub fn displays_as<InnerMatcher: for<'a> Matcher<&'a str>>(
     inner: InnerMatcher,
-) -> impl Matcher<ActualT = T> {
-    DisplayMatcher::<T, _> { inner, phantom: Default::default() }
+) -> DisplayMatcher<InnerMatcher> {
+    DisplayMatcher { inner }
 }
 
-struct DisplayMatcher<T, InnerMatcher: Matcher> {
+#[derive(MatcherBase)]
+pub struct DisplayMatcher<InnerMatcher> {
     inner: InnerMatcher,
-    phantom: PhantomData<T>,
 }
 
-impl<T: Debug + Display, InnerMatcher: Matcher<ActualT = String>> Matcher
-    for DisplayMatcher<T, InnerMatcher>
+impl<T: Debug + Display + Copy, InnerMatcher: for<'a> Matcher<&'a str>> Matcher<T>
+    for DisplayMatcher<InnerMatcher>
 {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
+    fn matches(&self, actual: T) -> MatcherResult {
         self.inner.matches(&format!("{actual}"))
     }
 
-    fn explain_match(&self, actual: &T) -> Description {
-        format!("which displays as a string {}", self.inner.explain_match(&format!("{actual}")))
-            .into()
+    fn explain_match(&self, actual: T) -> Description {
+        format!(
+            "which displays as {:?} {}",
+            actual.to_string(),
+            self.inner.explain_match(&format!("{actual}"))
+        )
+        .into()
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -65,7 +66,6 @@
 
 #[cfg(test)]
 mod tests {
-    use super::displays_as;
     use crate::prelude::*;
     use indoc::indoc;
     use std::fmt::{Debug, Display, Error, Formatter};
@@ -110,7 +110,8 @@
             err(displays_as(contains_substring(indoc!(
                 "
                   Actual: \"123\\n234\",
-                    which displays as a string which isn't equal to \"123\\n345\"
+                    which displays as \"123\\n234\" which isn't equal to \"123\\n345\"
+                    
                     Difference(-actual / +expected):
                      123
                     -234
diff --git a/crates/googletest/src/matchers/each_matcher.rs b/crates/googletest/src/matchers/each_matcher.rs
index 08a0742..6b76432 100644
--- a/crates/googletest/src/matchers/each_matcher.rs
+++ b/crates/googletest/src/matchers/each_matcher.rs
@@ -13,77 +13,58 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
-use std::{fmt::Debug, marker::PhantomData};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
+use std::fmt::Debug;
 
 /// Matches a container all of whose elements are matched by the matcher
 /// `inner`.
 ///
-/// `T` can be any container such that `&T` implements `IntoIterator`. This
-/// includes `Vec`, arrays, and (dereferenced) slices.
+/// `T` must implement [`IntoIterator`]. This
+/// includes `&Vec`, arrays, and slices.
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # use std::collections::HashSet;
 /// # fn should_pass_1() -> Result<()> {
 /// let value = vec![1, 2, 3];
-/// verify_that!(value, each(gt(0)))?;  // Passes
+/// verify_that!(value, each(gt(&0)))?;  // Passes
 /// let array_value = [1, 2, 3];
 /// verify_that!(array_value, each(gt(0)))?;  // Passes
 /// let slice_value = &[1, 2, 3];
-/// verify_that!(*slice_value, each(gt(0)))?;  // Passes
+/// verify_that!(slice_value, each(gt(&0)))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail() -> Result<()> {
 /// #     let value = vec![1, 2, 3];
-/// verify_that!(value, each(lt(2)))?;  // Fails: 2 and 3 are not less than 2
+/// verify_that!(value, each(lt(&2)))?;  // Fails: 2 and 3 are not less than 2
 /// #     Ok(())
 /// # }
 ///
 /// # fn should_pass_2() -> Result<()> {
 /// let value: HashSet<i32> = [1, 2, 3].into();
-/// verify_that!(value, each(gt(0)))?;  // Passes
+/// verify_that!(value, each(gt(&0)))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # should_pass_1().unwrap();
 /// # should_fail().unwrap_err();
 /// # should_pass_2().unwrap();
 /// ```
-///
-/// One can also verify the contents of a slice by dereferencing it:
-///
-/// ```
-/// # use googletest::prelude::*;
-/// # fn should_pass() -> Result<()> {
-/// let value = &[1, 2, 3];
-/// verify_that!(*value, each(gt(0)))?;
-/// #     Ok(())
-/// # }
-/// # should_pass().unwrap();
-/// ```
-pub fn each<ElementT: Debug, ActualT: Debug + ?Sized, MatcherT>(
-    inner: MatcherT,
-) -> impl Matcher<ActualT = ActualT>
-where
-    for<'a> &'a ActualT: IntoIterator<Item = &'a ElementT>,
-    MatcherT: Matcher<ActualT = ElementT>,
-{
-    EachMatcher { inner, phantom: Default::default() }
+pub fn each<MatcherT>(inner: MatcherT) -> EachMatcher<MatcherT> {
+    EachMatcher { inner }
 }
 
-struct EachMatcher<ActualT: ?Sized, MatcherT> {
+#[derive(MatcherBase)]
+pub struct EachMatcher<MatcherT> {
     inner: MatcherT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ElementT: Debug, ActualT: Debug + ?Sized, MatcherT> Matcher for EachMatcher<ActualT, MatcherT>
+impl<ElementT: Debug + Copy, ActualT: Debug + Copy, MatcherT> Matcher<ActualT>
+    for EachMatcher<MatcherT>
 where
-    for<'a> &'a ActualT: IntoIterator<Item = &'a ElementT>,
-    MatcherT: Matcher<ActualT = ElementT>,
+    ActualT: IntoIterator<Item = ElementT>,
+    MatcherT: Matcher<ElementT>,
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
+    fn matches(&self, actual: ActualT) -> MatcherResult {
         for element in actual {
             if self.inner.matches(element).is_no_match() {
                 return MatcherResult::NoMatch;
@@ -92,7 +73,7 @@
         MatcherResult::Match
     }
 
-    fn explain_match(&self, actual: &ActualT) -> Description {
+    fn explain_match(&self, actual: ActualT) -> Description {
         let mut non_matching_elements = Vec::new();
         for (index, element) in actual.into_iter().enumerate() {
             if self.inner.matches(element).is_no_match() {
@@ -137,7 +118,6 @@
 
 #[cfg(test)]
 mod tests {
-    use super::each;
     use crate::prelude::*;
     use indoc::indoc;
     use std::collections::HashSet;
@@ -145,19 +125,19 @@
     #[test]
     fn each_matches_empty_vec() -> Result<()> {
         let value: Vec<i32> = vec![];
-        verify_that!(value, each(gt(0)))
+        verify_that!(value, each(gt(&0)))
     }
 
     #[test]
     fn each_matches_vec_with_one_element() -> Result<()> {
         let value = vec![1];
-        verify_that!(value, each(gt(0)))
+        verify_that!(value, each(gt(&0)))
     }
 
     #[test]
     fn each_matches_vec_with_two_elements() -> Result<()> {
         let value = vec![1, 2];
-        verify_that!(value, each(gt(0)))
+        verify_that!(value, each(gt(&0)))
     }
 
     #[test]
@@ -169,24 +149,24 @@
     #[test]
     fn each_matches_hash_set_with_one_element() -> Result<()> {
         let value: HashSet<i32> = [1].into();
-        verify_that!(value, each(gt(0)))
+        verify_that!(value, each(gt(&0)))
     }
 
     #[test]
     fn each_does_not_match_when_first_element_does_not_match() -> Result<()> {
         let value = vec![0];
-        verify_that!(value, not(each(gt(1))))
+        verify_that!(value, not(each(gt(&1))))
     }
 
     #[test]
     fn each_does_not_match_when_second_element_does_not_match() -> Result<()> {
         let value = vec![2, 0];
-        verify_that!(value, not(each(gt(1))))
+        verify_that!(value, not(each(gt(&1))))
     }
 
     #[test]
     fn each_shows_correct_message_when_first_item_does_not_match() -> Result<()> {
-        let result = verify_that!(vec![0, 2, 3], each(gt(0)));
+        let result = verify_that!(vec![0, 2, 3], each(gt(&0)));
 
         verify_that!(
             result,
@@ -202,7 +182,7 @@
 
     #[test]
     fn each_shows_correct_message_when_second_item_does_not_match() -> Result<()> {
-        let result = verify_that!(vec![1, 0, 3], each(gt(0)));
+        let result = verify_that!(vec![1, 0, 3], each(gt(&0)));
 
         verify_that!(
             result,
@@ -218,7 +198,7 @@
 
     #[test]
     fn each_shows_correct_message_when_first_two_items_do_not_match() -> Result<()> {
-        let result = verify_that!(vec![0, 1, 3], each(gt(1)));
+        let result = verify_that!(vec![0, 1, 3], each(gt(&1)));
 
         verify_that!(
             result,
@@ -235,7 +215,7 @@
     }
     #[test]
     fn each_shows_inner_explanation() -> Result<()> {
-        let result = verify_that!(vec![vec![1, 2], vec![1]], each(each(eq(1))));
+        let result = verify_that!(vec![vec![1, 2], vec![1]], each(each(eq(&1))));
 
         verify_that!(
             result,
diff --git a/crates/googletest/src/matchers/elements_are_matcher.rs b/crates/googletest/src/matchers/elements_are_matcher.rs
index 3a4b5b2..a1b926b 100644
--- a/crates/googletest/src/matchers/elements_are_matcher.rs
+++ b/crates/googletest/src/matchers/elements_are_matcher.rs
@@ -24,19 +24,18 @@
 ///
 /// ```
 /// # use googletest::prelude::*;
-/// verify_that!(vec![1, 2, 3], elements_are![eq(1), anything(), gt(0).and(lt(123))])
+/// verify_that!(vec![1, 2, 3], elements_are![eq(&1), anything(), gt(&0).and(lt(&123))])
 /// #    .unwrap();
 /// ```
 ///
-/// The actual value must be a container such as a `Vec`, an array, or a
-/// dereferenced slice. More precisely, a shared borrow of the actual value must
-/// implement [`IntoIterator`].
+/// The actual value must be a container such as a `&Vec`, an array, or a slice.
+/// More precisely, the actual value must implement [`IntoIterator`].
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// let vector = vec![1, 2, 3];
 /// let slice = vector.as_slice();
-/// verify_that!(*slice, elements_are![eq(1), anything(), gt(0).and(lt(123))])
+/// verify_that!(slice, elements_are![eq(&1), anything(), gt(&0).and(lt(&123))])
 /// #    .unwrap();
 /// ```
 ///
@@ -45,7 +44,7 @@
 ///
 /// ```
 /// # use googletest::prelude::*;
-///  verify_that!(vec![1, 2], [eq(1), eq(2)])
+///  verify_that!(vec![1, 2], [eq(&1), eq(&2)])
 /// #     .unwrap();
 /// ```
 ///
@@ -55,19 +54,25 @@
 ///
 /// ```compile_fail
 /// # use googletest::prelude::*;
-/// verify_that!(vec![vec![1,2], vec![3]], [[eq(1), eq(2)], [eq(3)]])
+/// verify_that!(vec![vec![1,2], vec![3]], [[eq(&1), eq(&2)], [eq(&3)]])
 /// # .unwrap();
 /// ```
 ///
 /// Use this instead:
 /// ```
 /// # use googletest::prelude::*;
-/// verify_that!(vec![vec![1,2], vec![3]], [elements_are![eq(1), eq(2)], elements_are![eq(3)]])
+/// verify_that!(vec![vec![1,2], vec![3]], [elements_are![eq(&1), eq(&2)], elements_are![eq(&3)]])
 /// # .unwrap();
 /// ```
 ///
-/// This matcher does not support matching directly against an [`Iterator`]. To
-/// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
+///  If an inner matcher is `eq(...)`, it can be omitted:
+///
+/// ```
+/// # use googletest::prelude::*;
+///
+/// verify_that!(vec![1,2,3], elements_are![&1, lt(&1000), gt(&1)])
+/// #     .unwrap();
+/// ```
 ///
 /// Do not use this with unordered containers, since that will lead to flaky
 /// tests. Use
@@ -82,8 +87,12 @@
 #[doc(hidden)]
 macro_rules! __elements_are {
     ($($matcher:expr),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::ElementsAre;
-        ElementsAre::new(vec![$(Box::new($matcher)),*])
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::ElementsAre::new(
+            vec![$(Box::new(
+                $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!(
+                    $matcher
+                )
+            )),*])
     }}
 }
 
@@ -93,36 +102,34 @@
 #[doc(hidden)]
 pub mod internal {
     use crate::description::Description;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::{Matcher, MatcherBase, MatcherResult};
     use crate::matcher_support::zipped_iterator::zip;
-    use std::{fmt::Debug, marker::PhantomData};
+    use std::fmt::Debug;
 
     /// This struct is meant to be used only by the macro `elements_are!`.
     ///
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
-    pub struct ElementsAre<'a, ContainerT: ?Sized, T: Debug> {
-        elements: Vec<Box<dyn Matcher<ActualT = T> + 'a>>,
-        phantom: PhantomData<ContainerT>,
+    #[derive(MatcherBase)]
+    pub struct ElementsAre<'a, T: Debug + Copy> {
+        elements: Vec<Box<dyn Matcher<T> + 'a>>,
     }
 
-    impl<'a, ContainerT: ?Sized, T: Debug> ElementsAre<'a, ContainerT, T> {
+    impl<'a, T: Debug + Copy> ElementsAre<'a, T> {
         /// Factory only intended for use in the macro `elements_are!`.
         ///
         /// **For internal use only. API stablility is not guaranteed!**
         #[doc(hidden)]
-        pub fn new(elements: Vec<Box<dyn Matcher<ActualT = T> + 'a>>) -> Self {
-            Self { elements, phantom: Default::default() }
+        pub fn new(elements: Vec<Box<dyn Matcher<T> + 'a>>) -> Self {
+            Self { elements }
         }
     }
 
-    impl<'a, T: Debug, ContainerT: Debug + ?Sized> Matcher for ElementsAre<'a, ContainerT, T>
+    impl<'a, T: Debug + Copy, ContainerT: Debug + Copy> Matcher<ContainerT> for ElementsAre<'a, T>
     where
-        for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
+        ContainerT: IntoIterator<Item = T>,
     {
-        type ActualT = ContainerT;
-
-        fn matches(&self, actual: &ContainerT) -> MatcherResult {
+        fn matches(&self, actual: ContainerT) -> MatcherResult {
             let mut zipped_iterator = zip(actual.into_iter(), self.elements.iter());
             for (a, e) in zipped_iterator.by_ref() {
                 if e.matches(a).is_no_match() {
@@ -136,7 +143,7 @@
             }
         }
 
-        fn explain_match(&self, actual: &ContainerT) -> Description {
+        fn explain_match(&self, actual: ContainerT) -> Description {
             let actual_iterator = actual.into_iter();
             let mut zipped_iterator = zip(actual_iterator, self.elements.iter());
             let mut mismatches = Vec::new();
diff --git a/crates/googletest/src/matchers/empty_matcher.rs b/crates/googletest/src/matchers/empty_matcher.rs
index 11cb675..7631fc8 100644
--- a/crates/googletest/src/matchers/empty_matcher.rs
+++ b/crates/googletest/src/matchers/empty_matcher.rs
@@ -14,15 +14,15 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches an empty container.
 ///
-/// `T` can be any container such that `&T` implements `IntoIterator`. For
-/// instance, `T` can be a common container like `Vec` and
-/// [`HashSet`][std::collections::HashSet].
+/// `T` can be any container that implements `IntoIterator`. For instance, `T`
+/// can be the reference of a common container like `&Vec` and
+/// [`&HashSet`][std::collections::HashSet].
 ///
 /// ```
 /// # use googletest::prelude::*;
@@ -32,42 +32,24 @@
 /// verify_that!(value, empty())?;
 /// let value: HashSet<i32> = HashSet::new();
 /// verify_that!(value, empty())?;
-/// #     Ok(())
-/// # }
-/// # should_pass().unwrap();
-/// ```
-///
-/// One can also check whether a slice is empty by dereferencing it:
-///
-/// ```
-/// # use googletest::prelude::*;
-/// # use std::collections::HashSet;
-/// # fn should_pass() -> Result<()> {
 /// let value: &[u32] = &[];
-/// verify_that!(*value, empty())?;
+/// verify_that!(value, empty())?;
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
 /// ```
-
-pub fn empty<T: Debug + ?Sized>() -> impl Matcher<ActualT = T>
-where
-    for<'a> &'a T: IntoIterator,
-{
-    EmptyMatcher { phantom: Default::default() }
+pub fn empty() -> EmptyMatcher {
+    EmptyMatcher
 }
 
-struct EmptyMatcher<T: ?Sized> {
-    phantom: PhantomData<T>,
-}
+#[derive(MatcherBase)]
+pub struct EmptyMatcher;
 
-impl<T: Debug + ?Sized> Matcher for EmptyMatcher<T>
+impl<T: Debug + Copy> Matcher<T> for EmptyMatcher
 where
-    for<'a> &'a T: IntoIterator,
+    T: IntoIterator,
 {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
+    fn matches(&self, actual: T) -> MatcherResult {
         actual.into_iter().next().is_none().into()
     }
 
@@ -78,7 +60,6 @@
 
 #[cfg(test)]
 mod tests {
-    use super::empty;
     use crate::prelude::*;
     use std::collections::HashSet;
 
@@ -97,7 +78,7 @@
     #[test]
     fn empty_matcher_matches_empty_slice() -> Result<()> {
         let value: &[i32] = &[];
-        verify_that!(*value, empty())
+        verify_that!(value, empty())
     }
 
     #[test]
diff --git a/crates/googletest/src/matchers/eq_deref_of_matcher.rs b/crates/googletest/src/matchers/eq_deref_of_matcher.rs
deleted file mode 100644
index 320aafb..0000000
--- a/crates/googletest/src/matchers/eq_deref_of_matcher.rs
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// 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.
-
-use crate::{
-    description::Description,
-    matcher::{Matcher, MatcherResult},
-    matcher_support::{edit_distance, summarize_diff::create_diff},
-};
-use std::{fmt::Debug, marker::PhantomData, ops::Deref};
-
-/// Matches a value equal (in the sense of `==`) to the dereferenced value of
-/// `expected`.
-///
-/// This is similar to [`eq`][crate::matchers::eq] but takes a reference or
-/// smart pointer to the expected value rather than consuming it. This is useful
-/// when:
-///
-///  * one has only a reference to the expected value, and
-///  * the expected value cannot or should not be copied or cloned to create an
-///    owned value from it.
-///
-/// ```
-/// # use googletest::{matchers::eq_deref_of, verify_that};
-/// #[derive(Debug, PartialEq)]
-/// struct NonCloneableStruct(i32);
-/// let expected = NonCloneableStruct(123);
-/// verify_that!(NonCloneableStruct(123), eq_deref_of(&expected))
-/// #    .unwrap()
-/// ```
-///
-/// **Note**: while one can use `eq_deref_of` with the configuration methods of
-/// [`StrMatcherConfigurator`][crate::matchers::str_matcher::StrMatcherConfigurator]
-/// to configure string equality, it is not possible to do so when the input is
-/// a smart pointer to a string.
-///
-/// ```compile_fail
-/// # use googletest::{matchers::{eq_deref_of, str_matcher::StrMatcherConfigurator}, verify_that};
-/// verify_that!("A string", eq_deref_of(Box::new("A STRING")).ignoring_ascii_case()) // Does not compile
-/// #    .unwrap()
-/// ```
-///
-/// Otherwise, this has the same behaviour as [`eq`][crate::matchers::eq].
-pub fn eq_deref_of<ActualT: ?Sized, ExpectedRefT>(
-    expected: ExpectedRefT,
-) -> EqDerefOfMatcher<ActualT, ExpectedRefT> {
-    EqDerefOfMatcher { expected, phantom: Default::default() }
-}
-
-/// A matcher which matches a value equal to the derefenced value of `expected`.
-///
-/// See [`eq_deref_of`].
-pub struct EqDerefOfMatcher<ActualT: ?Sized, ExpectedRefT> {
-    pub(crate) expected: ExpectedRefT,
-    phantom: PhantomData<ActualT>,
-}
-
-impl<ActualT, ExpectedRefT, ExpectedT> Matcher for EqDerefOfMatcher<ActualT, ExpectedRefT>
-where
-    ActualT: Debug + ?Sized,
-    ExpectedRefT: Deref<Target = ExpectedT> + Debug,
-    ExpectedT: PartialEq<ActualT> + Debug,
-{
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
-        (self.expected.deref() == actual).into()
-    }
-
-    fn describe(&self, matcher_result: MatcherResult) -> Description {
-        match matcher_result {
-            MatcherResult::Match => format!("is equal to {:?}", self.expected).into(),
-            MatcherResult::NoMatch => format!("isn't equal to {:?}", self.expected).into(),
-        }
-    }
-
-    fn explain_match(&self, actual: &ActualT) -> Description {
-        format!(
-            "which {}{}",
-            &self.describe(self.matches(actual)),
-            create_diff(
-                &format!("{:#?}", actual),
-                &format!("{:#?}", self.expected.deref()),
-                edit_distance::Mode::Exact,
-            )
-        )
-        .into()
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::eq_deref_of;
-    use crate::prelude::*;
-    use indoc::indoc;
-
-    #[derive(Debug, PartialEq)]
-    struct NonCloneNonCopyStruct(i32);
-
-    #[test]
-    fn matches_value_with_ref_to_equal_value() -> Result<()> {
-        verify_that!(NonCloneNonCopyStruct(123), eq_deref_of(&NonCloneNonCopyStruct(123)))
-    }
-
-    #[test]
-    fn matches_value_with_box_of_equal_value() -> Result<()> {
-        verify_that!(NonCloneNonCopyStruct(123), eq_deref_of(Box::new(NonCloneNonCopyStruct(123))))
-    }
-
-    #[test]
-    fn does_not_match_value_with_non_equal_value() -> Result<()> {
-        verify_that!(NonCloneNonCopyStruct(123), not(eq_deref_of(&NonCloneNonCopyStruct(234))))
-    }
-
-    #[test]
-    fn shows_structured_diff() -> Result<()> {
-        #[derive(Debug, PartialEq)]
-        struct Strukt {
-            int: i32,
-            string: String,
-        }
-
-        let result = verify_that!(
-            Strukt { int: 123, string: "something".into() },
-            eq_deref_of(Box::new(Strukt { int: 321, string: "someone".into() }))
-        );
-        verify_that!(
-            result,
-            err(displays_as(contains_substring(indoc! {
-            "
-            Actual: Strukt { int: 123, string: \"something\" },
-              which isn't equal to Strukt { int: 321, string: \"someone\" }
-              Difference(-actual / +expected):
-               Strukt {
-              -    int: 123,
-              +    int: 321,
-              -    string: \"something\",
-              +    string: \"someone\",
-               }
-            "})))
-        )
-    }
-}
diff --git a/crates/googletest/src/matchers/eq_matcher.rs b/crates/googletest/src/matchers/eq_matcher.rs
index 985307f..c39b79b 100644
--- a/crates/googletest/src/matchers/eq_matcher.rs
+++ b/crates/googletest/src/matchers/eq_matcher.rs
@@ -13,11 +13,11 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use crate::matcher_support::edit_distance;
 use crate::matcher_support::summarize_diff::create_diff;
 
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a value equal (in the sense of `==`) to `expected`.
 ///
@@ -71,23 +71,21 @@
 /// options on how equality is checked through the
 /// [`StrMatcherConfigurator`][crate::matchers::str_matcher::StrMatcherConfigurator]
 /// extension trait, which is implemented for this matcher.
-pub fn eq<A: ?Sized, T>(expected: T) -> EqMatcher<A, T> {
-    EqMatcher { expected, phantom: Default::default() }
+pub fn eq<T>(expected: T) -> EqMatcher<T> {
+    EqMatcher { expected }
 }
 
 /// A matcher which matches a value equal to `expected`.
 ///
 /// See [`eq`].
-pub struct EqMatcher<A: ?Sized, T> {
+#[derive(MatcherBase)]
+pub struct EqMatcher<T> {
     pub(crate) expected: T,
-    phantom: PhantomData<A>,
 }
 
-impl<T: Debug, A: Debug + ?Sized + PartialEq<T>> Matcher for EqMatcher<A, T> {
-    type ActualT = A;
-
-    fn matches(&self, actual: &A) -> MatcherResult {
-        (*actual == self.expected).into()
+impl<T: Debug, A: Debug + Copy + PartialEq<T>> Matcher<A> for EqMatcher<T> {
+    fn matches(&self, actual: A) -> MatcherResult {
+        (actual == self.expected).into()
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -97,10 +95,10 @@
         }
     }
 
-    fn explain_match(&self, actual: &A) -> Description {
+    fn explain_match(&self, actual: A) -> Description {
         let expected_debug = format!("{:#?}", self.expected);
         let actual_debug = format!("{:#?}", actual);
-        let description = self.describe(self.matches(actual));
+        let description = Matcher::<A>::describe(self, self.matches(actual));
 
         let diff = if is_multiline_string_debug(&actual_debug)
             && is_multiline_string_debug(&expected_debug)
@@ -118,7 +116,11 @@
             create_diff(&actual_debug, &expected_debug, edit_distance::Mode::Exact)
         };
 
-        format!("which {description}{diff}").into()
+        if diff.is_empty() {
+            format!("which {description}").into()
+        } else {
+            format!("which {description}\n\n{diff}").into()
+        }
     }
 }
 
@@ -135,7 +137,6 @@
 
 #[cfg(test)]
 mod tests {
-    use super::eq;
     use crate::prelude::*;
     use indoc::indoc;
 
@@ -171,7 +172,7 @@
 
         let result = verify_that!(
             Strukt { int: 123, string: "something".into() },
-            eq(Strukt { int: 321, string: "someone".into() })
+            eq(&Strukt { int: 321, string: "someone".into() })
         );
         verify_that!(
             result,
@@ -179,6 +180,7 @@
             "
             Actual: Strukt { int: 123, string: \"something\" },
               which isn't equal to Strukt { int: 321, string: \"someone\" }
+              
               Difference(-actual / +expected):
                Strukt {
               -    int: 123,
@@ -192,7 +194,7 @@
 
     #[test]
     fn eq_vec_debug_diff() -> Result<()> {
-        let result = verify_that!(vec![1, 2, 3], eq(vec![1, 3, 4]));
+        let result = verify_that!(vec![1, 2, 3], eq(&vec![1, 3, 4]));
         verify_that!(
             result,
             err(displays_as(contains_substring(indoc! {
@@ -201,6 +203,7 @@
             Expected: is equal to [1, 3, 4]
             Actual: [1, 2, 3],
               which isn't equal to [1, 3, 4]
+              
               Difference(-actual / +expected):
                [
                    1,
@@ -214,7 +217,7 @@
 
     #[test]
     fn eq_vec_debug_diff_length_mismatch() -> Result<()> {
-        let result = verify_that!(vec![1, 2, 3, 4, 5], eq(vec![1, 3, 5]));
+        let result = verify_that!(vec![1, 2, 3, 4, 5], eq(&vec![1, 3, 5]));
         verify_that!(
             result,
             err(displays_as(contains_substring(indoc! {
@@ -223,6 +226,7 @@
             Expected: is equal to [1, 3, 5]
             Actual: [1, 2, 3, 4, 5],
               which isn't equal to [1, 3, 5]
+              
               Difference(-actual / +expected):
                [
                    1,
@@ -237,13 +241,14 @@
 
     #[test]
     fn eq_debug_diff_common_lines_omitted() -> Result<()> {
-        let result = verify_that!((1..50).collect::<Vec<_>>(), eq((3..52).collect::<Vec<_>>()));
+        let result = verify_that!((1..50).collect::<Vec<_>>(), eq(&(3..52).collect::<Vec<_>>()));
         verify_that!(
             result,
             err(displays_as(contains_substring(indoc! {
             "
             ],
               which isn't equal to [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
+              
               Difference(-actual / +expected):
                [
               -    1,
@@ -261,13 +266,14 @@
 
     #[test]
     fn eq_debug_diff_5_common_lines_not_omitted() -> Result<()> {
-        let result = verify_that!((1..8).collect::<Vec<_>>(), eq((3..10).collect::<Vec<_>>()));
+        let result = verify_that!((1..8).collect::<Vec<_>>(), eq(&(3..10).collect::<Vec<_>>()));
         verify_that!(
             result,
             err(displays_as(contains_substring(indoc! {
             "
             Actual: [1, 2, 3, 4, 5, 6, 7],
               which isn't equal to [3, 4, 5, 6, 7, 8, 9]
+              
               Difference(-actual / +expected):
                [
               -    1,
@@ -285,13 +291,14 @@
 
     #[test]
     fn eq_debug_diff_start_common_lines_omitted() -> Result<()> {
-        let result = verify_that!((1..50).collect::<Vec<_>>(), eq((1..52).collect::<Vec<_>>()));
+        let result = verify_that!((1..50).collect::<Vec<_>>(), eq(&(1..52).collect::<Vec<_>>()));
         verify_that!(
             result,
             err(displays_as(contains_substring(indoc! {
             "
             ],
               which isn't equal to [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
+              
               Difference(-actual / +expected):
                [
                    1,
@@ -306,13 +313,14 @@
 
     #[test]
     fn eq_debug_diff_end_common_lines_omitted() -> Result<()> {
-        let result = verify_that!((1..52).collect::<Vec<_>>(), eq((3..52).collect::<Vec<_>>()));
+        let result = verify_that!((1..52).collect::<Vec<_>>(), eq(&(3..52).collect::<Vec<_>>()));
         verify_that!(
             result,
             err(displays_as(contains_substring(indoc! {
             "
             ],
               which isn't equal to [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
+              
               Difference(-actual / +expected):
                [
               -    1,
diff --git a/crates/googletest/src/matchers/err_matcher.rs b/crates/googletest/src/matchers/err_matcher.rs
index 3b10de4..aa88045 100644
--- a/crates/googletest/src/matchers/err_matcher.rs
+++ b/crates/googletest/src/matchers/err_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a `Result` containing `Err` with a value matched by `inner`.
 ///
@@ -38,28 +38,53 @@
 /// # should_fail_1().unwrap_err();
 /// # should_fail_2().unwrap_err();
 /// ```
-pub fn err<T: Debug, E: Debug>(
-    inner: impl Matcher<ActualT = E>,
-) -> impl Matcher<ActualT = std::result::Result<T, E>> {
-    ErrMatcher::<T, E, _> { inner, phantom_t: Default::default(), phantom_e: Default::default() }
+pub fn err<Inner>(inner: Inner) -> ErrMatcher<Inner> {
+    ErrMatcher { inner }
 }
 
-struct ErrMatcher<T, E, InnerMatcherT> {
+#[derive(MatcherBase)]
+pub struct ErrMatcher<InnerMatcherT> {
     inner: InnerMatcherT,
-    phantom_t: PhantomData<T>,
-    phantom_e: PhantomData<E>,
 }
 
-impl<T: Debug, E: Debug, InnerMatcherT: Matcher<ActualT = E>> Matcher
-    for ErrMatcher<T, E, InnerMatcherT>
+impl<T: Debug + Copy, E: Debug + Copy, InnerMatcherT: Matcher<E>> Matcher<std::result::Result<T, E>>
+    for ErrMatcher<InnerMatcherT>
 {
-    type ActualT = std::result::Result<T, E>;
+    fn matches(&self, actual: std::result::Result<T, E>) -> MatcherResult {
+        actual.err().map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
+    }
 
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
+    fn explain_match(&self, actual: std::result::Result<T, E>) -> Description {
+        match actual {
+            Err(e) => {
+                Description::new().text("which is an error").nested(self.inner.explain_match(e))
+            }
+            Ok(_) => "which is a success".into(),
+        }
+    }
+
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        match matcher_result {
+            MatcherResult::Match => {
+                format!("is an error which {}", self.inner.describe(MatcherResult::Match)).into()
+            }
+            MatcherResult::NoMatch => format!(
+                "is a success or is an error containing a value which {}",
+                self.inner.describe(MatcherResult::NoMatch)
+            )
+            .into(),
+        }
+    }
+}
+
+impl<'a, T: Debug, E: Debug, InnerMatcherT: Matcher<&'a E>> Matcher<&'a std::result::Result<T, E>>
+    for ErrMatcher<InnerMatcherT>
+{
+    fn matches(&self, actual: &'a std::result::Result<T, E>) -> MatcherResult {
         actual.as_ref().err().map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
     }
 
-    fn explain_match(&self, actual: &Self::ActualT) -> Description {
+    fn explain_match(&self, actual: &'a std::result::Result<T, E>) -> Description {
         match actual {
             Err(e) => {
                 Description::new().text("which is an error").nested(self.inner.explain_match(e))
@@ -84,8 +109,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::err;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
 
@@ -94,7 +118,7 @@
         let matcher = err(eq(1));
         let value: std::result::Result<i32, i32> = Err(1);
 
-        let result = matcher.matches(&value);
+        let result = matcher.matches(value);
 
         verify_that!(result, eq(MatcherResult::Match))
     }
@@ -104,7 +128,7 @@
         let matcher = err(eq(1));
         let value: std::result::Result<i32, i32> = Err(0);
 
-        let result = matcher.matches(&value);
+        let result = matcher.matches(value);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
@@ -114,12 +138,30 @@
         let matcher = err(eq(1));
         let value: std::result::Result<i32, i32> = Ok(1);
 
-        let result = matcher.matches(&value);
+        let result = matcher.matches(value);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
     #[test]
+    fn err_matches_result_with_err_value_by_ref() -> Result<()> {
+        let value: std::result::Result<String, String> = Err("123".to_string());
+        verify_that!(value, err(eq("123")))
+    }
+
+    #[test]
+    fn err_does_not_match_result_with_wrong_err_value_by_ref() -> Result<()> {
+        let value: std::result::Result<String, String> = Err("321".to_string());
+        verify_that!(value, not(err(eq("123"))))
+    }
+
+    #[test]
+    fn err_does_not_match_result_with_ok_by_ref() -> Result<()> {
+        let value: std::result::Result<String, String> = Ok("123".to_string());
+        verify_that!(value, not(err(eq("123"))))
+    }
+
+    #[test]
     fn err_full_error_message() -> Result<()> {
         let result = verify_that!(Err::<i32, i32>(1), err(eq(2)));
 
@@ -138,15 +180,102 @@
     }
 
     #[test]
-    fn err_describe_matches() -> Result<()> {
-        let matcher = super::ErrMatcher::<i32, i32, _> {
-            inner: eq(1),
-            phantom_t: Default::default(),
-            phantom_e: Default::default(),
-        };
+    fn err_describe_match() -> Result<()> {
+        let matcher = err(eq(1));
         verify_that!(
-            matcher.describe(MatcherResult::Match),
+            Matcher::<std::result::Result<i32, i32>>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("is an error which is equal to 1"))
         )
     }
+
+    #[test]
+    fn err_describe_no_match() -> Result<()> {
+        let matcher = err(eq(1));
+        verify_that!(
+            Matcher::<std::result::Result<i32, i32>>::describe(&matcher, MatcherResult::NoMatch),
+            displays_as(eq(
+                "is a success or is an error containing a value which isn't equal to 1"
+            ))
+        )
+    }
+
+    #[test]
+    fn err_describe_match_by_ref() -> Result<()> {
+        let matcher = err(eq("123"));
+        verify_that!(
+            Matcher::<&std::result::Result<String, String>>::describe(
+                &matcher,
+                MatcherResult::Match
+            ),
+            displays_as(eq("is an error which is equal to \"123\""))
+        )
+    }
+
+    #[test]
+    fn err_describe_no_match_by_ref() -> Result<()> {
+        let matcher = err(eq("123"));
+        verify_that!(
+            Matcher::<&std::result::Result<String, String>>::describe(
+                &matcher,
+                MatcherResult::NoMatch
+            ),
+            displays_as(eq(
+                "is a success or is an error containing a value which isn't equal to \"123\""
+            ))
+        )
+    }
+
+    #[test]
+    fn err_explain_match_success() -> Result<()> {
+        let actual: std::result::Result<i32, i32> = Err(1);
+        let matcher = err(eq(1));
+        verify_that!(
+            matcher.explain_match(actual),
+            displays_as(eq("which is an error\n  which is equal to 1"))
+        )
+    }
+
+    #[test]
+    fn err_explain_match_fail() -> Result<()> {
+        let actual: std::result::Result<i32, i32> = Err(2);
+        let matcher = err(eq(1));
+        verify_that!(
+            matcher.explain_match(actual),
+            displays_as(eq("which is an error\n  which isn't equal to 1"))
+        )
+    }
+
+    #[test]
+    fn err_explain_match_ok() -> Result<()> {
+        let actual: std::result::Result<i32, i32> = Ok(1);
+        let matcher = err(eq(1));
+        verify_that!(matcher.explain_match(actual), displays_as(eq("which is a success")))
+    }
+
+    #[test]
+    fn err_explain_match_success_by_ref() -> Result<()> {
+        let actual: std::result::Result<String, String> = Err("123".to_string());
+        let matcher = err(eq("123"));
+        verify_that!(
+            matcher.explain_match(&actual),
+            displays_as(eq("which is an error\n  which is equal to \"123\""))
+        )
+    }
+
+    #[test]
+    fn err_explain_match_fail_by_ref() -> Result<()> {
+        let actual: std::result::Result<String, String> = Err("321".to_string());
+        let matcher = err(eq("123"));
+        verify_that!(
+            matcher.explain_match(&actual),
+            displays_as(eq("which is an error\n  which isn't equal to \"123\""))
+        )
+    }
+
+    #[test]
+    fn err_explain_match_ok_by_ref() -> Result<()> {
+        let actual: std::result::Result<String, String> = Ok("123".to_string());
+        let matcher = err(eq("123"));
+        verify_that!(matcher.explain_match(&actual), displays_as(eq("which is a success")))
+    }
 }
diff --git a/crates/googletest/src/matchers/field_matcher.rs b/crates/googletest/src/matchers/field_matcher.rs
index fc37ce6..58a55c6 100644
--- a/crates/googletest/src/matchers/field_matcher.rs
+++ b/crates/googletest/src/matchers/field_matcher.rs
@@ -33,7 +33,7 @@
 ///   int: i32
 /// }
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(IntField{int: 32}, field!(IntField.int, eq(32)))?;
+/// verify_that!(IntField{int: 32}, field!(&IntField.int, eq(32)))?;
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -46,7 +46,7 @@
 /// #[derive(Debug)]
 /// struct IntField(i32);
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(IntField(32), field!(IntField.0, eq(32)))?;
+/// verify_that!(IntField(32), field!(&IntField.0, eq(32)))?;
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -63,11 +63,11 @@
 ///     B,
 /// }
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(MyEnum::A(32), field!(MyEnum::A.0, eq(32)))?; // Passes
+/// verify_that!(MyEnum::A(32), field!(&MyEnum::A.0, eq(32)))?; // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail() -> Result<()> {
-/// verify_that!(MyEnum::B, field!(MyEnum::A.0, eq(32)))?; // Fails: wrong enum variant
+/// verify_that!(MyEnum::B, field!(&MyEnum::A.0, eq(32)))?; // Fails: wrong enum variant
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -83,7 +83,22 @@
 ///     pub struct AStruct(pub i32);
 /// }
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(a_module::AStruct(32), field!(a_module::AStruct.0, eq(32)))?;
+/// verify_that!(a_module::AStruct(32), field!(&a_module::AStruct.0, eq(32)))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
+/// ```
+///
+/// If the inner matcher is `eq(...)`, it can be omitted:
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug)]
+/// struct IntField {
+///   int: i32
+/// }
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(IntField{int: 32}, field!(&IntField.int, 32))?;
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -105,6 +120,67 @@
 /// # }
 /// ```
 ///
+/// # Specification of the field pattern
+///
+/// The specification of the field follow the syntax: `(ref)? (&)?
+/// $TYPE.$FIELD`.
+/// The `&` allows to specify whether this matcher matches against an actual of
+/// type `$TYPE` (`$TYPE`` must implement `Copy`) or a `&$TYPE`.
+///
+/// For instance:
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug)]
+/// pub struct AStruct{a_field: i32};
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(AStruct{a_field: 32}, field!(&AStruct.a_field, eq(32)))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
+/// ```
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug, Clone, Copy)]
+/// pub struct AStruct{a_field: i32};
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(AStruct{a_field: 32}, field!(AStruct.a_field, eq(32)))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
+/// ```
+///
+/// The `ref` allows to bind the field value by reference, which is required if
+/// the field type does not implement `Copy`.
+///
+/// For instance:
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug)]
+/// pub struct AStruct{a_field: i32};
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(AStruct{a_field: 32}, field!(&AStruct.a_field, eq(32)))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
+/// ```
+///
+/// If `field!` is qualified by both `&` and `ref`, they can both be omitted.
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug)]
+/// pub struct AStruct{a_field: String};
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(AStruct{a_field: "32".into()}, field!(&AStruct.a_field, ref eq("32")))?;
+/// verify_that!(AStruct{a_field: "32".into()}, field!(AStruct.a_field, eq("32")))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
+/// ```
+///
 /// See also the macro [`property`][crate::matchers::property] for an analogous
 /// mechanism to extract a datum by invoking a method.
 #[macro_export]
@@ -115,15 +191,16 @@
 
 // Internal-only macro created so that the macro definition does not appear in
 // generated documentation.
+// We cannot use `path` or `ty` to capture the type as we are terminating the
+// type with a . (dot).
 #[doc(hidden)]
 #[macro_export]
 macro_rules! field_internal {
-    ($($t:ident)::+.$field:tt, $m:expr) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::field_matcher;
-        field_matcher(
-            |o| {
+    (&$($t:ident)::+.$field:tt, ref $m:expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::field_matcher(
+            |o: &_| {
                 match o {
-                    $($t)::* { $field: value, .. } => Some(value),
+                    &$($t)::* {$field: ref value, .. } => Some(value),
                     // The pattern below is unreachable if the type is a struct (as opposed to an
                     // enum). Since the macro can't know which it is, we always include it and just
                     // tell the compiler not to complain.
@@ -132,7 +209,37 @@
                 }
             },
             &stringify!($field),
-            $m)
+            $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
+    }};
+    (&$($t:ident)::+.$field:tt, $m:expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::field_matcher(
+            |o: &&_| {
+                match o {
+                    &$($t)::* {$field: value, .. } => Some(value),
+                    // The pattern below is unreachable if the type is a struct (as opposed to an
+                    // enum). Since the macro can't know which it is, we always include it and just
+                    // tell the compiler not to complain.
+                    #[allow(unreachable_patterns)]
+                    _ => None,
+                }
+            },
+            &stringify!($field),
+            $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
+    }};
+    ($($t:ident)::+.$field:tt, $m:expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::field_matcher(
+            |o: &_| {
+                match o {
+                    $($t)::* {$field: value, .. } => Some(value),
+                    // The pattern below is unreachable if the type is a struct (as opposed to an
+                    // enum). Since the macro can't know which it is, we always include it and just
+                    // tell the compiler not to complain.
+                    #[allow(unreachable_patterns)]
+                    _ => None,
+                }
+            },
+            &stringify!($field),
+            $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
     }};
 }
 
@@ -143,7 +250,7 @@
 pub mod internal {
     use crate::{
         description::Description,
-        matcher::{Matcher, MatcherResult},
+        matcher::{Matcher, MatcherBase, MatcherResult},
     };
     use std::fmt::Debug;
 
@@ -152,26 +259,25 @@
     ///
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
-    pub fn field_matcher<OuterT: Debug, InnerT: Debug, InnerMatcher: Matcher<ActualT = InnerT>>(
+    pub fn field_matcher<OuterT, InnerT, InnerMatcher>(
         field_accessor: fn(&OuterT) -> Option<&InnerT>,
         field_path: &'static str,
         inner: InnerMatcher,
-    ) -> impl Matcher<ActualT = OuterT> {
+    ) -> FieldMatcher<OuterT, InnerT, InnerMatcher> {
         FieldMatcher { field_accessor, field_path, inner }
     }
 
-    struct FieldMatcher<OuterT, InnerT, InnerMatcher> {
+    #[derive(MatcherBase)]
+    pub struct FieldMatcher<OuterT, InnerT, InnerMatcher> {
         field_accessor: fn(&OuterT) -> Option<&InnerT>,
         field_path: &'static str,
         inner: InnerMatcher,
     }
 
-    impl<OuterT: Debug, InnerT: Debug, InnerMatcher: Matcher<ActualT = InnerT>> Matcher
-        for FieldMatcher<OuterT, InnerT, InnerMatcher>
+    impl<'a, OuterT: Debug + 'a, InnerT: Debug + 'a, InnerMatcher: Matcher<&'a InnerT>>
+        Matcher<&'a OuterT> for FieldMatcher<OuterT, InnerT, InnerMatcher>
     {
-        type ActualT = OuterT;
-
-        fn matches(&self, actual: &OuterT) -> MatcherResult {
+        fn matches(&self, actual: &'a OuterT) -> MatcherResult {
             if let Some(value) = (self.field_accessor)(actual) {
                 self.inner.matches(value)
             } else {
@@ -179,7 +285,7 @@
             }
         }
 
-        fn explain_match(&self, actual: &OuterT) -> Description {
+        fn explain_match(&self, actual: &'a OuterT) -> Description {
             if let Some(actual) = (self.field_accessor)(actual) {
                 format!(
                     "which has field `{}`, {}",
@@ -204,4 +310,41 @@
             .into()
         }
     }
+
+    impl<OuterT: Debug + Copy, InnerT: Debug + Copy, InnerMatcher: Matcher<InnerT>> Matcher<OuterT>
+        for FieldMatcher<OuterT, InnerT, InnerMatcher>
+    {
+        fn matches(&self, actual: OuterT) -> MatcherResult {
+            if let Some(value) = (self.field_accessor)(&actual) {
+                self.inner.matches(*value)
+            } else {
+                MatcherResult::NoMatch
+            }
+        }
+
+        fn explain_match(&self, actual: OuterT) -> Description {
+            if let Some(actual) = (self.field_accessor)(&actual) {
+                format!(
+                    "which has field `{}`, {}",
+                    self.field_path,
+                    self.inner.explain_match(*actual)
+                )
+                .into()
+            } else {
+                let formatted_actual_value = format!("{actual:?}");
+                let without_fields = formatted_actual_value.split('(').next().unwrap_or("");
+                let without_fields = without_fields.split('{').next().unwrap_or("").trim_end();
+                format!("which has the wrong enum variant `{without_fields}`").into()
+            }
+        }
+
+        fn describe(&self, matcher_result: MatcherResult) -> Description {
+            format!(
+                "has field `{}`, which {}",
+                self.field_path,
+                self.inner.describe(matcher_result)
+            )
+            .into()
+        }
+    }
 }
diff --git a/crates/googletest/src/matchers/ge_matcher.rs b/crates/googletest/src/matchers/ge_matcher.rs
index cb2a91f..4919f2c 100644
--- a/crates/googletest/src/matchers/ge_matcher.rs
+++ b/crates/googletest/src/matchers/ge_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a value greater than or equal to (in the sense of `>=`) `expected`.
 ///
@@ -74,24 +74,20 @@
 ///
 /// You can find the standard library `PartialOrd` implementation in
 /// <https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html#implementors>
-pub fn ge<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug>(
-    expected: ExpectedT,
-) -> impl Matcher<ActualT = ActualT> {
-    GeMatcher::<ActualT, _> { expected, phantom: Default::default() }
+pub fn ge<ExpectedT>(expected: ExpectedT) -> GeMatcher<ExpectedT> {
+    GeMatcher { expected }
 }
 
-struct GeMatcher<ActualT, ExpectedT> {
+#[derive(MatcherBase)]
+pub struct GeMatcher<ExpectedT> {
     expected: ExpectedT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug> Matcher
-    for GeMatcher<ActualT, ExpectedT>
+impl<ActualT: Debug + PartialOrd<ExpectedT> + Copy, ExpectedT: Debug> Matcher<ActualT>
+    for GeMatcher<ExpectedT>
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
-        (*actual >= self.expected).into()
+    fn matches(&self, actual: ActualT) -> MatcherResult {
+        (actual >= self.expected).into()
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -106,8 +102,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::ge;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
     use std::ffi::OsString;
@@ -122,7 +117,7 @@
     #[test]
     fn ge_does_not_match_smaller_i32() -> Result<()> {
         let matcher = ge(10);
-        let result = matcher.matches(&9);
+        let result = matcher.matches(9);
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
@@ -134,7 +129,7 @@
     #[test]
     fn ge_does_not_match_lesser_str() -> Result<()> {
         let matcher = ge("z");
-        let result = matcher.matches(&"a");
+        let result = matcher.matches("a");
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
diff --git a/crates/googletest/src/matchers/gt_matcher.rs b/crates/googletest/src/matchers/gt_matcher.rs
index b52c6e3..123201f 100644
--- a/crates/googletest/src/matchers/gt_matcher.rs
+++ b/crates/googletest/src/matchers/gt_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a value greater (in the sense of `>`) than `expected`.
 ///
@@ -74,24 +74,20 @@
 ///
 /// You can find the standard library `PartialOrd` implementation in
 /// <https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html#implementors>
-pub fn gt<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug>(
-    expected: ExpectedT,
-) -> impl Matcher<ActualT = ActualT> {
-    GtMatcher::<ActualT, _> { expected, phantom: Default::default() }
+pub fn gt<ExpectedT: Debug>(expected: ExpectedT) -> GtMatcher<ExpectedT> {
+    GtMatcher { expected }
 }
 
-struct GtMatcher<ActualT, ExpectedT> {
+#[derive(MatcherBase)]
+pub struct GtMatcher<ExpectedT> {
     expected: ExpectedT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug> Matcher
-    for GtMatcher<ActualT, ExpectedT>
+impl<ActualT: Debug + PartialOrd<ExpectedT> + Copy, ExpectedT: Debug> Matcher<ActualT>
+    for GtMatcher<ExpectedT>
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
-        (*actual > self.expected).into()
+    fn matches(&self, actual: ActualT) -> MatcherResult {
+        (actual > self.expected).into()
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -106,8 +102,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::gt;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
     use std::ffi::OsString;
@@ -122,14 +117,14 @@
     #[test]
     fn gt_does_not_match_equal_i32() -> Result<()> {
         let matcher = gt(10);
-        let result = matcher.matches(&10);
+        let result = matcher.matches(10);
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
     #[test]
     fn gt_does_not_match_lower_i32() -> Result<()> {
         let matcher = gt(-50);
-        let result = matcher.matches(&-51);
+        let result = matcher.matches(-51);
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
@@ -141,7 +136,7 @@
     #[test]
     fn gt_does_not_match_lesser_str() -> Result<()> {
         let matcher = gt("B");
-        let result = matcher.matches(&"A");
+        let result = matcher.matches("A");
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
@@ -163,7 +158,7 @@
 
     #[test]
     fn gt_mismatch_combined_with_each() -> Result<()> {
-        let result = verify_that!(vec![19, 23, 11], each(gt(15)));
+        let result = verify_that!(vec![19, 23, 11], each(gt(&15)));
 
         verify_that!(
             result,
@@ -181,7 +176,7 @@
     #[test]
     fn gt_describe_matches() -> Result<()> {
         verify_that!(
-            gt::<i32, i32>(232).describe(MatcherResult::Match),
+            Matcher::<i32>::describe(&gt(232), MatcherResult::Match),
             displays_as(eq("is greater than 232"))
         )
     }
@@ -189,7 +184,7 @@
     #[test]
     fn gt_describe_does_not_match() -> Result<()> {
         verify_that!(
-            gt::<i32, i32>(232).describe(MatcherResult::NoMatch),
+            Matcher::<i32>::describe(&gt(232), MatcherResult::NoMatch),
             displays_as(eq("is less than or equal to 232"))
         )
     }
diff --git a/crates/googletest/src/matchers/has_entry_matcher.rs b/crates/googletest/src/matchers/has_entry_matcher.rs
index 7f9d2ad..b5cce71 100644
--- a/crates/googletest/src/matchers/has_entry_matcher.rs
+++ b/crates/googletest/src/matchers/has_entry_matcher.rs
@@ -13,31 +13,30 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use std::collections::HashMap;
 use std::fmt::Debug;
 use std::hash::Hash;
-use std::marker::PhantomData;
 
-/// Matches a HashMap containing the given `key` whose value is matched by the
-/// matcher `inner`.
+/// Matches a `&HashMap` containing the given `key` whose value is matched by
+/// the matcher `inner`.
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # use std::collections::HashMap;
 /// # fn should_pass() -> Result<()> {
 /// let value = HashMap::from([(0, 1), (1, -1)]);
-/// verify_that!(value, has_entry(0, eq(1)))?;  // Passes
+/// verify_that!(value, has_entry(0, eq(&1)))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail_1() -> Result<()> {
 /// # let value = HashMap::from([(0, 1), (1, -1)]);
-/// verify_that!(value, has_entry(1, gt(0)))?;  // Fails: value not matched
+/// verify_that!(value, has_entry(1, gt(&0)))?;  // Fails: value not matched
 /// #     Ok(())
 /// # }
 /// # fn should_fail_2() -> Result<()> {
 /// # let value = HashMap::from([(0, 1), (1, -1)]);
-/// verify_that!(value, has_entry(2, eq(0)))?;  // Fails: key not present
+/// verify_that!(value, has_entry(2, eq(&0)))?;  // Fails: key not present
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -45,42 +44,33 @@
 /// # should_fail_2().unwrap_err();
 /// ```
 ///
-/// Note: One could obtain the same effect by collecting entries into a `Vec`
-/// and using `contains`:
+/// Note: One could obtain the same effect by using `contains` and a
+/// `Matcher<(&Key, &Value)>`:
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # use std::collections::HashMap;
 /// # fn should_pass() -> Result<()> {
 /// let value = HashMap::from([(0, 1), (1, -1)]);
-/// verify_that!(value.into_iter().collect::<Vec<_>>(), contains(eq((0, 1))))?;
+/// verify_that!(value, contains(eq((&0, &1))))?;
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
 /// ```
-///
-/// However, `has_entry` will offer somewhat better diagnostic messages in the
-/// case of assertion failure. And it avoid the extra allocation hidden in the
-/// code above.
-pub fn has_entry<KeyT: Debug + Eq + Hash, ValueT: Debug, MatcherT: Matcher<ActualT = ValueT>>(
-    key: KeyT,
-    inner: MatcherT,
-) -> impl Matcher<ActualT = HashMap<KeyT, ValueT>> {
-    HasEntryMatcher { key, inner, phantom: Default::default() }
+pub fn has_entry<KeyT, MatcherT>(key: KeyT, inner: MatcherT) -> HasEntryMatcher<KeyT, MatcherT> {
+    HasEntryMatcher { key, inner }
 }
 
-struct HasEntryMatcher<KeyT, ValueT, MatcherT> {
+#[derive(MatcherBase)]
+pub struct HasEntryMatcher<KeyT, MatcherT> {
     key: KeyT,
     inner: MatcherT,
-    phantom: PhantomData<ValueT>,
 }
 
-impl<KeyT: Debug + Eq + Hash, ValueT: Debug, MatcherT: Matcher<ActualT = ValueT>> Matcher
-    for HasEntryMatcher<KeyT, ValueT, MatcherT>
+impl<'a, KeyT: Debug + Eq + Hash, ValueT: Debug, MatcherT: Matcher<&'a ValueT>>
+    Matcher<&'a HashMap<KeyT, ValueT>> for HasEntryMatcher<KeyT, MatcherT>
 {
-    type ActualT = HashMap<KeyT, ValueT>;
-
-    fn matches(&self, actual: &HashMap<KeyT, ValueT>) -> MatcherResult {
+    fn matches(&self, actual: &'a HashMap<KeyT, ValueT>) -> MatcherResult {
         if let Some(value) = actual.get(&self.key) {
             self.inner.matches(value)
         } else {
@@ -88,7 +78,7 @@
         }
     }
 
-    fn explain_match(&self, actual: &HashMap<KeyT, ValueT>) -> Description {
+    fn explain_match(&self, actual: &'a HashMap<KeyT, ValueT>) -> Description {
         if let Some(value) = actual.get(&self.key) {
             format!(
                 "which contains key {:?}, but is mapped to value {:#?}, {}",
@@ -123,7 +113,6 @@
 
 #[cfg(test)]
 mod tests {
-    use super::has_entry;
     use crate::prelude::*;
     use indoc::indoc;
     use std::collections::HashMap;
@@ -131,30 +120,30 @@
     #[test]
     fn has_entry_does_not_match_empty_hash_map() -> Result<()> {
         let value: HashMap<i32, i32> = HashMap::new();
-        verify_that!(value, not(has_entry(0, eq(0))))
+        verify_that!(&value, not(has_entry(0, eq(&0))))
     }
 
     #[test]
     fn has_entry_matches_hash_map_with_value() -> Result<()> {
         let value: HashMap<i32, i32> = HashMap::from([(0, 0)]);
-        verify_that!(value, has_entry(0, eq(0)))
+        verify_that!(&value, has_entry(0, eq(&0)))
     }
 
     #[test]
     fn has_entry_does_not_match_hash_map_with_wrong_value() -> Result<()> {
         let value: HashMap<i32, i32> = HashMap::from([(0, 1)]);
-        verify_that!(value, not(has_entry(0, eq(0))))
+        verify_that!(&value, not(has_entry(0, eq(&0))))
     }
 
     #[test]
     fn has_entry_does_not_match_hash_map_with_wrong_key() -> Result<()> {
         let value: HashMap<i32, i32> = HashMap::from([(1, 0)]);
-        verify_that!(value, not(has_entry(0, eq(0))))
+        verify_that!(&value, not(has_entry(0, eq(&0))))
     }
 
     #[test]
     fn has_entry_shows_correct_message_when_key_is_not_present() -> Result<()> {
-        let result = verify_that!(HashMap::from([(0, 0)]), has_entry(1, eq(0)));
+        let result = verify_that!(HashMap::from([(0, 0)]), has_entry(1, eq(&0)));
 
         verify_that!(
             result,
@@ -171,7 +160,7 @@
 
     #[test]
     fn has_entry_shows_correct_message_when_key_has_non_matching_value() -> Result<()> {
-        let result = verify_that!(HashMap::from([(0, 0)]), has_entry(0, eq(1)));
+        let result = verify_that!(HashMap::from([(0, 0)]), has_entry(0, eq(&1)));
 
         verify_that!(
             result,
diff --git a/crates/googletest/src/matchers/is_encoded_string_matcher.rs b/crates/googletest/src/matchers/is_encoded_string_matcher.rs
index d2fb259..098658b 100644
--- a/crates/googletest/src/matchers/is_encoded_string_matcher.rs
+++ b/crates/googletest/src/matchers/is_encoded_string_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a byte sequence which is a UTF-8 encoded string matched by `inner`.
 ///
@@ -48,30 +48,26 @@
 /// # should_fail_1().unwrap_err();
 /// # should_fail_2().unwrap_err();
 /// ```
-pub fn is_utf8_string<'a, ActualT: AsRef<[u8]> + Debug + 'a, InnerMatcherT>(
-    inner: InnerMatcherT,
-) -> impl Matcher<ActualT = ActualT>
+pub fn is_utf8_string<InnerMatcherT>(inner: InnerMatcherT) -> IsEncodedStringMatcher<InnerMatcherT>
 where
-    InnerMatcherT: Matcher<ActualT = String>,
+    InnerMatcherT: for<'a> Matcher<&'a str>,
 {
-    IsEncodedStringMatcher { inner, phantom: Default::default() }
+    IsEncodedStringMatcher { inner }
 }
 
-struct IsEncodedStringMatcher<ActualT, InnerMatcherT> {
+#[derive(MatcherBase)]
+pub struct IsEncodedStringMatcher<InnerMatcherT> {
     inner: InnerMatcherT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<'a, ActualT: AsRef<[u8]> + Debug + 'a, InnerMatcherT> Matcher
-    for IsEncodedStringMatcher<ActualT, InnerMatcherT>
+impl<ActualT: AsRef<[u8]> + Debug + Copy, InnerMatcherT> Matcher<ActualT>
+    for IsEncodedStringMatcher<InnerMatcherT>
 where
-    InnerMatcherT: Matcher<ActualT = String>,
+    InnerMatcherT: for<'a> Matcher<&'a str>,
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
-        String::from_utf8(actual.as_ref().to_vec())
-            .map(|s| self.inner.matches(&s))
+    fn matches(&self, actual: ActualT) -> MatcherResult {
+        std::str::from_utf8(actual.as_ref())
+            .map(|s| self.inner.matches(s))
             .unwrap_or(MatcherResult::NoMatch)
     }
 
@@ -90,10 +86,10 @@
         }
     }
 
-    fn explain_match(&self, actual: &Self::ActualT) -> Description {
-        match String::from_utf8(actual.as_ref().to_vec()) {
+    fn explain_match(&self, actual: ActualT) -> Description {
+        match std::str::from_utf8(actual.as_ref()) {
             Ok(s) => {
-                format!("which is a UTF-8 encoded string {}", self.inner.explain_match(&s)).into()
+                format!("which is a UTF-8 encoded string {}", self.inner.explain_match(s)).into()
             }
             Err(e) => format!("which is not a UTF-8 encoded string: {e}").into(),
         }
@@ -132,27 +128,27 @@
 
     #[test]
     fn has_correct_description_in_matched_case() -> Result<()> {
-        let matcher = is_utf8_string::<&[u8], _>(eq("A string"));
+        let matcher = is_utf8_string(eq("A string"));
 
         verify_that!(
-            matcher.describe(MatcherResult::Match),
+            Matcher::<&[u8]>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("is a UTF-8 encoded string which is equal to \"A string\""))
         )
     }
 
     #[test]
     fn has_correct_description_in_not_matched_case() -> Result<()> {
-        let matcher = is_utf8_string::<&[u8], _>(eq("A string"));
+        let matcher = is_utf8_string(eq("A string"));
 
         verify_that!(
-            matcher.describe(MatcherResult::NoMatch),
+            Matcher::<&[u8]>::describe(&matcher, MatcherResult::NoMatch),
             displays_as(eq("is not a UTF-8 encoded string which is equal to \"A string\""))
         )
     }
 
     #[test]
     fn has_correct_explanation_in_matched_case() -> Result<()> {
-        let explanation = is_utf8_string(eq("A string")).explain_match(&"A string".as_bytes());
+        let explanation = is_utf8_string(eq("A string")).explain_match("A string".as_bytes());
 
         verify_that!(
             explanation,
@@ -162,15 +158,14 @@
 
     #[test]
     fn has_correct_explanation_when_byte_array_is_not_utf8_encoded() -> Result<()> {
-        let explanation = is_utf8_string(eq("A string")).explain_match(&&[192, 128, 0, 64]);
+        let explanation = is_utf8_string(eq("A string")).explain_match([192, 128, 0, 64]);
 
         verify_that!(explanation, displays_as(starts_with("which is not a UTF-8 encoded string: ")))
     }
 
     #[test]
     fn has_correct_explanation_when_inner_matcher_does_not_match() -> Result<()> {
-        let explanation =
-            is_utf8_string(eq("A string")).explain_match(&"Another string".as_bytes());
+        let explanation = is_utf8_string(eq("A string")).explain_match("Another string".as_bytes());
 
         verify_that!(
             explanation,
diff --git a/crates/googletest/src/matchers/is_matcher.rs b/crates/googletest/src/matchers/is_matcher.rs
index 336ce53..3748858 100644
--- a/crates/googletest/src/matchers/is_matcher.rs
+++ b/crates/googletest/src/matchers/is_matcher.rs
@@ -16,34 +16,29 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches precisely values matched by `inner`.
 ///
 /// The returned matcher produces a description prefixed by the string
 /// `description`. This is useful in contexts where the test assertion failure
 /// output must include the additional description.
-pub fn is<'a, ActualT: Debug + 'a, InnerMatcherT: Matcher<ActualT = ActualT> + 'a>(
-    description: &'a str,
-    inner: InnerMatcherT,
-) -> impl Matcher<ActualT = ActualT> + 'a {
-    IsMatcher { description, inner, phantom: Default::default() }
+pub fn is<InnerMatcherT>(description: &str, inner: InnerMatcherT) -> IsMatcher<'_, InnerMatcherT> {
+    IsMatcher { description, inner }
 }
 
-struct IsMatcher<'a, ActualT, InnerMatcherT> {
+#[derive(MatcherBase)]
+pub struct IsMatcher<'a, InnerMatcherT> {
     description: &'a str,
     inner: InnerMatcherT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<'a, ActualT: Debug, InnerMatcherT: Matcher<ActualT = ActualT>> Matcher
-    for IsMatcher<'a, ActualT, InnerMatcherT>
+impl<'a, ActualT: Debug + Copy, InnerMatcherT: Matcher<ActualT>> Matcher<ActualT>
+    for IsMatcher<'a, InnerMatcherT>
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
+    fn matches(&self, actual: ActualT) -> MatcherResult {
         self.inner.matches(actual)
     }
 
@@ -64,7 +59,7 @@
         }
     }
 
-    fn explain_match(&self, actual: &Self::ActualT) -> Description {
+    fn explain_match(&self, actual: ActualT) -> Description {
         self.inner.explain_match(actual)
     }
 }
diff --git a/crates/googletest/src/matchers/is_nan_matcher.rs b/crates/googletest/src/matchers/is_nan_matcher.rs
index 0af4338..f6fae89 100644
--- a/crates/googletest/src/matchers/is_nan_matcher.rs
+++ b/crates/googletest/src/matchers/is_nan_matcher.rs
@@ -14,22 +14,21 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
 use num_traits::float::Float;
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a floating point value which is NaN.
-pub fn is_nan<T: Float + Debug>() -> impl Matcher<ActualT = T> {
-    IsNanMatcher::<T>(Default::default())
+pub fn is_nan() -> IsNanMatcher {
+    IsNanMatcher
 }
 
-struct IsNanMatcher<T>(PhantomData<T>);
+#[derive(MatcherBase)]
+pub struct IsNanMatcher;
 
-impl<T: Float + Debug> Matcher for IsNanMatcher<T> {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
+impl<T: Float + Debug + Copy> Matcher<T> for IsNanMatcher {
+    fn matches(&self, actual: T) -> MatcherResult {
         actual.is_nan().into()
     }
 
@@ -40,7 +39,6 @@
 
 #[cfg(test)]
 mod tests {
-    use super::is_nan;
     use crate::prelude::*;
 
     #[test]
diff --git a/crates/googletest/src/matchers/le_matcher.rs b/crates/googletest/src/matchers/le_matcher.rs
index cfc5781..980c516 100644
--- a/crates/googletest/src/matchers/le_matcher.rs
+++ b/crates/googletest/src/matchers/le_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a value less than or equal to (in the sense of `<=`) `expected`.
 ///
@@ -74,24 +74,20 @@
 ///
 /// You can find the standard library `PartialOrd` implementation in
 /// <https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html#implementors>
-pub fn le<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug>(
-    expected: ExpectedT,
-) -> impl Matcher<ActualT = ActualT> {
-    LeMatcher::<ActualT, _> { expected, phantom: Default::default() }
+pub fn le<ExpectedT>(expected: ExpectedT) -> LeMatcher<ExpectedT> {
+    LeMatcher { expected }
 }
 
-struct LeMatcher<ActualT, ExpectedT> {
+#[derive(MatcherBase)]
+pub struct LeMatcher<ExpectedT> {
     expected: ExpectedT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug> Matcher
-    for LeMatcher<ActualT, ExpectedT>
+impl<ActualT: Debug + PartialOrd<ExpectedT> + Copy, ExpectedT: Debug> Matcher<ActualT>
+    for LeMatcher<ExpectedT>
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
-        (*actual <= self.expected).into()
+    fn matches(&self, actual: ActualT) -> MatcherResult {
+        (actual <= self.expected).into()
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -104,8 +100,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::le;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
     use std::ffi::OsString;
@@ -120,7 +115,7 @@
     #[test]
     fn le_does_not_match_bigger_i32() -> Result<()> {
         let matcher = le(0);
-        let result = matcher.matches(&1);
+        let result = matcher.matches(1);
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
@@ -132,7 +127,7 @@
     #[test]
     fn le_does_not_match_bigger_str() -> Result<()> {
         let matcher = le("a");
-        let result = matcher.matches(&"z");
+        let result = matcher.matches("z");
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
@@ -186,7 +181,7 @@
         /// A custom "number" that is lower than all other numbers. The only
         /// things we define about this "special" number is `PartialOrd` and
         /// `PartialEq` against `u32`.
-        #[derive(Debug)]
+        #[derive(Debug, Clone, Copy)]
         struct VeryLowNumber {}
 
         impl std::cmp::PartialEq<u32> for VeryLowNumber {
diff --git a/crates/googletest/src/matchers/len_matcher.rs b/crates/googletest/src/matchers/len_matcher.rs
index be903c9..a48d32c 100644
--- a/crates/googletest/src/matchers/len_matcher.rs
+++ b/crates/googletest/src/matchers/len_matcher.rs
@@ -13,16 +13,15 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use crate::matcher_support::count_elements::count_elements;
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a container whose number of elements matches `expected`.
 ///
 /// This matches against a container over which one can iterate. This includes
-/// the standard Rust containers, arrays, and (when dereferenced) slices. More
-/// precisely, a shared borrow of the actual type must implement
-/// [`IntoIterator`].
+/// the standard Rust containers, arrays, and slices. More
+/// precisely, the actual type must implement [`IntoIterator`].
 ///
 /// ```
 /// # use googletest::prelude::*;
@@ -49,26 +48,21 @@
 /// # }
 /// # should_pass().unwrap();
 /// ```
-pub fn len<T: Debug + ?Sized, E: Matcher<ActualT = usize>>(expected: E) -> impl Matcher<ActualT = T>
-where
-    for<'a> &'a T: IntoIterator,
-{
-    LenMatcher { expected, phantom: Default::default() }
+pub fn len<E>(expected: E) -> LenMatcher<E> {
+    LenMatcher { expected }
 }
 
-struct LenMatcher<T: ?Sized, E> {
+#[derive(MatcherBase)]
+pub struct LenMatcher<E> {
     expected: E,
-    phantom: PhantomData<T>,
 }
 
-impl<T: Debug + ?Sized, E: Matcher<ActualT = usize>> Matcher for LenMatcher<T, E>
+impl<T: Debug + Copy, E: Matcher<usize>> Matcher<T> for LenMatcher<E>
 where
-    for<'a> &'a T: IntoIterator,
+    T: IntoIterator,
 {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
-        self.expected.matches(&count_elements(actual))
+    fn matches(&self, actual: T) -> MatcherResult {
+        self.expected.matches(count_elements(actual))
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -83,25 +77,23 @@
         }
     }
 
-    fn explain_match(&self, actual: &T) -> Description {
+    fn explain_match(&self, actual: T) -> Description {
         let actual_size = count_elements(actual);
-        format!("which has length {}, {}", actual_size, self.expected.explain_match(&actual_size))
+        format!("which has length {}, {}", actual_size, self.expected.explain_match(actual_size))
             .into()
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use super::len;
     use crate::description::Description;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
     use std::collections::{
         BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque,
     };
     use std::fmt::Debug;
-    use std::marker::PhantomData;
 
     #[test]
     fn len_matcher_match_vec() -> Result<()> {
@@ -112,7 +104,7 @@
     #[test]
     fn len_matcher_match_array_reference() -> Result<()> {
         let value = &[1, 2, 3];
-        verify_that!(*value, len(eq(3)))
+        verify_that!(value, len(eq(3)))
     }
 
     #[test]
@@ -125,7 +117,7 @@
     fn len_matcher_match_slice_of_vec() -> Result<()> {
         let value = vec![1, 2, 3];
         let slice = value.as_slice();
-        verify_that!(*slice, len(eq(3)))
+        verify_that!(slice, len(eq(3)))
     }
 
     #[test]
@@ -178,11 +170,10 @@
 
     #[test]
     fn len_matcher_explain_match() -> Result<()> {
-        struct TestMatcher<T>(PhantomData<T>);
-        impl<T: Debug> Matcher for TestMatcher<T> {
-            type ActualT = T;
-
-            fn matches(&self, _: &T) -> MatcherResult {
+        #[derive(MatcherBase)]
+        struct TestMatcher;
+        impl<T: Debug + Copy> Matcher<T> for TestMatcher {
+            fn matches(&self, _: T) -> MatcherResult {
                 false.into()
             }
 
@@ -190,12 +181,12 @@
                 "called described".into()
             }
 
-            fn explain_match(&self, _: &T) -> Description {
+            fn explain_match(&self, _: T) -> Description {
                 "called explain_match".into()
             }
         }
         verify_that!(
-            len(TestMatcher(Default::default())).explain_match(&[1, 2, 3]),
+            len(TestMatcher).explain_match([1, 2, 3]),
             displays_as(eq("which has length 3, called explain_match"))
         )
     }
diff --git a/crates/googletest/src/matchers/lt_matcher.rs b/crates/googletest/src/matchers/lt_matcher.rs
index 08bc563..1758e83 100644
--- a/crates/googletest/src/matchers/lt_matcher.rs
+++ b/crates/googletest/src/matchers/lt_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a value less (in the sense of `<`) than `expected`.
 ///
@@ -74,24 +74,20 @@
 ///
 /// You can find the standard library `PartialOrd` implementation in
 /// <https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html#implementors>
-pub fn lt<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug>(
-    expected: ExpectedT,
-) -> impl Matcher<ActualT = ActualT> {
-    LtMatcher::<ActualT, _> { expected, phantom: Default::default() }
+pub fn lt<ExpectedT>(expected: ExpectedT) -> LtMatcher<ExpectedT> {
+    LtMatcher { expected }
 }
 
-struct LtMatcher<ActualT, ExpectedT> {
+#[derive(MatcherBase)]
+pub struct LtMatcher<ExpectedT> {
     expected: ExpectedT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug> Matcher
-    for LtMatcher<ActualT, ExpectedT>
+impl<ActualT: Debug + PartialOrd<ExpectedT> + Copy, ExpectedT: Debug> Matcher<ActualT>
+    for LtMatcher<ExpectedT>
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
-        (*actual < self.expected).into()
+    fn matches(&self, actual: ActualT) -> MatcherResult {
+        (actual < self.expected).into()
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -106,8 +102,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::lt;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
     use std::ffi::OsString;
@@ -122,14 +117,14 @@
     #[test]
     fn lt_does_not_match_equal_i32() -> Result<()> {
         let matcher = lt(10);
-        let result = matcher.matches(&10);
+        let result = matcher.matches(10);
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
     #[test]
     fn lt_does_not_match_lower_i32() -> Result<()> {
         let matcher = lt(-50);
-        let result = matcher.matches(&50);
+        let result = matcher.matches(50);
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
@@ -141,7 +136,7 @@
     #[test]
     fn lt_does_not_match_bigger_str() -> Result<()> {
         let matcher = lt("ab");
-        let result = matcher.matches(&"az");
+        let result = matcher.matches("az");
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
@@ -195,7 +190,7 @@
         /// A custom "number" that is smaller than all other numbers. The only
         /// things we define about this "special" number is `PartialOrd` and
         /// `PartialEq` against `u32`.
-        #[derive(Debug)]
+        #[derive(Debug, Clone, Copy)]
         struct VeryLowNumber {}
 
         impl std::cmp::PartialEq<u32> for VeryLowNumber {
diff --git a/crates/googletest/src/matchers/matches_pattern.rs b/crates/googletest/src/matchers/matches_pattern.rs
index 106a5d7..7dc9ce3 100644
--- a/crates/googletest/src/matchers/matches_pattern.rs
+++ b/crates/googletest/src/matchers/matches_pattern.rs
@@ -84,7 +84,7 @@
 ///     a_nested_struct: MyInnerStruct { a_field: "Something to believe in".into() },
 /// };
 /// verify_that!(my_struct, matches_pattern!(MyStruct {
-///     a_nested_struct: matches_pattern!(MyInnerStruct {
+///      a_nested_struct: matches_pattern!(MyInnerStruct {
 ///         a_field: starts_with("Something"),
 ///     }),
 /// }))
@@ -138,12 +138,33 @@
 /// #     .unwrap();
 /// ```
 ///
+/// If an inner matcher is `eq(...)`, it can be omitted:
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug)]
+/// struct MyStruct {
+///     a_field: String,
+///     another_field: String,
+/// }
+///
+/// let my_struct = MyStruct {
+///     a_field: "this".into(),
+///     another_field: "that".into()
+/// };
+/// verify_that!(my_struct, matches_pattern!(MyStruct {
+///     a_field: "this",
+///     another_field: "that",
+/// }))
+/// #     .unwrap();
+/// ```
+///
 /// **Important**: The method should be pure function with a deterministic
 /// output and no side effects. In particular, in the event of an assertion
 /// failure, it will be invoked a second time, with the assertion failure output
 /// reflecting the *second* invocation.
 ///
-/// These may also include extra parameters you pass in:
+/// These may also include extra litteral parameters you pass in:
 ///
 /// ```
 /// # use googletest::prelude::*;
@@ -157,13 +178,14 @@
 /// }
 ///
 /// # let my_struct = MyStruct { a_field: "Something to believe in".into() };
-/// verify_that!(my_struct, matches_pattern!(MyStruct {
-///     append_to_a_field("a suffix"): ends_with("a suffix"),
+/// verify_that!(my_struct, matches_pattern!(&MyStruct {
+///     append_to_a_field("a suffix"): ref ends_with("a suffix"),
 /// }))
 /// #     .unwrap();
 /// ```
 ///
-/// If the method returns a reference, precede it with a `*`:
+/// You can precede both field and property matchers with a `ref` to match the
+/// result by reference:
 ///
 /// ```
 /// # use googletest::prelude::*;
@@ -173,12 +195,34 @@
 /// # }
 /// #
 /// impl MyStruct {
-///     fn get_a_field_ref(&self) -> &String { &self.a_field }
+///     fn get_a_field_ref(&self) -> String { self.a_field.clone() }
+/// }
+///
+/// # let my_struct = MyStruct { a_field: "Something to believe in".into() };
+/// verify_that!(my_struct, matches_pattern!(&MyStruct {
+///     get_a_field_ref(): ref starts_with("Something"),
+/// }))
+/// #    .unwrap();
+/// ```
+///
+/// Note that if the `actual` is of type `&ActualT` and the pattern type is
+/// `ActualT`, this is automatically performed. This behavior is similar to the
+/// reference binding mode in pattern matching.
+///
+/// ```
+/// # use googletest::prelude::*;
+/// # #[derive(Debug)]
+/// # struct MyStruct {
+/// #     a_field: String,
+/// # }
+/// #
+/// impl MyStruct {
+///     fn get_a_field_ref(&self) -> String { self.a_field.clone() }
 /// }
 ///
 /// # let my_struct = MyStruct { a_field: "Something to believe in".into() };
 /// verify_that!(my_struct, matches_pattern!(MyStruct {
-///     *get_a_field_ref(): starts_with("Something"),
+///     get_a_field_ref(): starts_with("Something"),
 /// }))
 /// #    .unwrap();
 /// ```
@@ -194,7 +238,7 @@
 /// let my_struct = MyTupleStruct("Something".into(), "Some other thing".into());
 /// verify_that!(
 ///     my_struct,
-///     matches_pattern!(MyTupleStruct(eq("Something"), eq("Some other thing")))
+///     matches_pattern!(&MyTupleStruct(ref eq("Something"), ref eq("Some other thing")))
 /// )
 /// #    .unwrap();
 /// ```
@@ -210,42 +254,34 @@
 /// }
 ///
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(MyEnum::A(123), matches_pattern!(MyEnum::A(eq(123))))?; // Passes
+/// verify_that!(MyEnum::A(123), matches_pattern!(&MyEnum::A(eq(123))))?; // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail() -> Result<()> {
-/// verify_that!(MyEnum::B, matches_pattern!(MyEnum::A(eq(123))))?; // Fails - wrong enum variant
+/// verify_that!(MyEnum::B, matches_pattern!(&MyEnum::A(eq(123))))?; // Fails - wrong enum variant
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
 /// # should_fail().unwrap_err();
 /// ```
 ///
-/// This macro does not support plain (non-struct) tuples. Use the macro
-/// [`tuple`] for that purpose.
+/// This macro does not support plain (non-struct) tuples. But it should not be
+/// necessary as tuple of matchers are matchers of tuple. In other words, if
+/// `MatcherU: Matcher<U>` and `MatcherT: Matcher<T>`, then `(MatcherU,
+/// MatcherT): Matcher<(U, T)>`.
 ///
 /// Trailing commas are allowed (but not required) in both ordinary and tuple
 /// structs.
 ///
-/// Unfortunately, this matcher does *not* work with methods returning string
-/// slices:
+/// Note that the default format (rustfmt) can format macros if the macro
+/// argument is parseable Rust code. This is mostly true for this macro with two
+/// exceptions:
+///  * property matching
+///  * `ref` keyword with named fields
 ///
-/// ```compile_fail
-/// # use googletest::prelude::*;
-/// # #[derive(Debug)]
-/// pub struct MyStruct {
-///     a_string: String,
-/// }
-/// impl MyStruct {
-///     pub fn get_a_string(&self) -> &str { &self.a_string }
-/// }
-///
-/// let value = MyStruct { a_string: "A string".into() };
-/// verify_that!(value, matches_pattern!( MyStruct {
-///     get_a_string(): eq("A string"),   // Does not compile
-/// }))
-/// #    .unwrap();
-/// ```
+/// An option for formatting large is to avoid these exceptions (by removing the
+/// parenthesis of properties and the `ref` keywords), run `rustfmt` and add
+/// them back.
 #[macro_export]
 #[doc(hidden)]
 macro_rules! __matches_pattern {
@@ -258,7 +294,17 @@
 #[macro_export]
 macro_rules! matches_pattern_internal {
     (
-        [$($struct_name:tt)*],
+        @name [$($struct_name:tt)*],
+        { $field_name:ident : ref $matcher:expr $(,)? }
+    ) => {
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(field!($($struct_name)*.$field_name, ref $matcher))
+        )
+    };
+
+    (
+        @name [$($struct_name:tt)*],
         { $field_name:ident : $matcher:expr $(,)? }
     ) => {
         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
@@ -268,7 +314,17 @@
     };
 
     (
-        [$($struct_name:tt)*],
+        @name [$($struct_name:tt)*],
+        { $property_name:ident($($argument:expr),* $(,)?) : ref $matcher:expr $(,)? }
+    ) => {
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(property!($($struct_name)*.$property_name($($argument),*), ref $matcher))
+        )
+    };
+
+    (
+        @name [$($struct_name:tt)*],
         { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
     ) => {
         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
@@ -278,88 +334,123 @@
     };
 
     (
-        [$($struct_name:tt)*],
-        { * $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(property!(* $($struct_name)*.$property_name($($argument),*), $matcher))
-        )
-    };
-
-    (
-        [$($struct_name:tt)*],
-        { $field_name:ident : $matcher:expr, $($rest:tt)* }
+        @name [$($struct_name:tt)*],
+        { $field_name:ident : ref $matcher:expr, $($rest:tt)* }
     ) => {
         $crate::matches_pattern_internal!(
-            all!(field!($($struct_name)*.$field_name, $matcher)),
+            @fields (field!($($struct_name)*.$field_name, ref $matcher)),
             [$($struct_name)*],
             { $($rest)* }
         )
     };
 
     (
-        [$($struct_name:tt)*],
+        @name [$($struct_name:tt)*],
+        { $field_name:ident : $matcher:expr, $($rest:tt)* }
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (field!($($struct_name)*.$field_name, $matcher)),
+            [$($struct_name)*],
+            { $($rest)* }
+        )
+    };
+
+    (
+        @name [$($struct_name:tt)*],
+        { $property_name:ident($($argument:expr),* $(,)?) : ref $matcher:expr, $($rest:tt)* }
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (property!($($struct_name)*.$property_name($($argument),*), ref $matcher)),
+            [$($struct_name)*],
+            { $($rest)* }
+        )
+    };
+
+    (
+        @name [$($struct_name:tt)*],
         { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
     ) => {
         $crate::matches_pattern_internal!(
-            all!(property!($($struct_name)*.$property_name($($argument),*), $matcher)),
+            @fields (property!($($struct_name)*.$property_name($($argument),*), $matcher)),
             [$($struct_name)*],
             { $($rest)* }
         )
     };
 
     (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
-        { * $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
+        { $field_name:ident : ref $matcher:expr $(,)? }
     ) => {
-        $crate::matches_pattern_internal!(
-            all!(property!(* $($struct_name)*.$property_name($($argument),*), $matcher)),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(
+                $($processed)*,
+                field!($($struct_name)*.$field_name, ref $matcher)
+            ))
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         { $field_name:ident : $matcher:expr $(,)? }
     ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(stringify!($($struct_name)*), all!(
-            $($processed)*,
-            field!($($struct_name)*.$field_name, $matcher)
-        ))
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(
+                $($processed)*,
+                field!($($struct_name)*.$field_name, $matcher)
+            ))
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        { $property_name:ident($($argument:expr),* $(,)?) : ref $matcher:expr $(,)? }
+    ) => {
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(
+                $($processed)*,
+                property!($($struct_name)*.$property_name($($argument),*), ref $matcher)
+            ))
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
     ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(stringify!($($struct_name)*), all!(
-            $($processed)*,
-            property!($($struct_name)*.$property_name($($argument),*), $matcher)
-        ))
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(
+                $($processed)*,
+                property!($($struct_name)*.$property_name($($argument),*), $matcher)
+            ))
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
-        { * $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
+        { $field_name:ident : ref $matcher:expr, $($rest:tt)* }
     ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(stringify!($($struct_name)*), all!(
-            $($processed)*,
-            property!(* $($struct_name)*.$property_name($($argument),*), $matcher)
-        ))
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.$field_name, ref $matcher)
+            ),
+            [$($struct_name)*],
+            { $($rest)* }
+        )
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         { $field_name:ident : $matcher:expr, $($rest:tt)* }
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.$field_name, $matcher)
             ),
@@ -369,12 +460,27 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        { $property_name:ident($($argument:expr),* $(,)?) : ref $matcher:expr, $($rest:tt)* }
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                property!(ref $($struct_name)*.$property_name($($argument),*), $matcher)
+            ),
+            [$($struct_name)*],
+            { $($rest)* }
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 property!($($struct_name)*.$property_name($($argument),*), $matcher)
             ),
@@ -384,32 +490,26 @@
     };
 
     (
-        all!($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { * $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
+        @name [$($struct_name:tt)*],
     ) => {
-        $crate::matches_pattern_internal!(
-            all!(
-                $($processed)*,
-                property!(* $($struct_name)*.$property_name($($argument),*), $matcher)
-            ),
-            [$($struct_name)*],
-            { $($rest)* }
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::pattern_only(
+            |v| matches!(v, $($struct_name)*),
+            concat!("is ", stringify!($($struct_name)*)),
+            concat!("is not ", stringify!($($struct_name)*)))
+    };
+
+    (
+        @name [$($struct_name:tt)*],
+        (ref $matcher:expr $(,)?)
+    ) => {
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(field!($($struct_name)*.0, ref $matcher))
         )
     };
 
     (
-        [$($struct_name:tt)*],
-    ) => {
-        $crate::matchers::predicate(|v| matches!(v, $($struct_name)*))
-            .with_description(
-                concat!("is ", stringify!($($struct_name)*)),
-                concat!("is not ", stringify!($($struct_name)*)),
-            )
-    };
-
-    (
-        [$($struct_name:tt)*],
+        @name [$($struct_name:tt)*],
         ($matcher:expr $(,)?)
     ) => {
         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
@@ -419,11 +519,25 @@
     };
 
     (
-        [$($struct_name:tt)*],
+        @name [$($struct_name:tt)*],
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                field!($($struct_name)*.0, ref $matcher)
+            ),
+            [$($struct_name)*],
+            1,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @name [$($struct_name:tt)*],
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 field!($($struct_name)*.0, $matcher)
             ),
             [$($struct_name)*],
@@ -433,28 +547,61 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        $field:tt,
+        (ref $matcher:expr $(,)?)
+    ) => {
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(
+                $($processed)*,
+                field!($($struct_name)*.$field, ref $matcher)
+            ))
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         $field:tt,
         ($matcher:expr $(,)?)
     ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(stringify!($($struct_name)*), all!(
-            $($processed)*,
-            field!($($struct_name)*.$field, $matcher)
-        ))
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!($($struct_name)*),
+            all!(
+                $($processed)*,
+                field!($($struct_name)*.$field, $matcher)
+            ))
     };
 
     // We need to repeat this once for every supported field position, unfortunately. There appears
     // to be no way in declarative macros to compute $field + 1 and have the result evaluated to a
     // token which can be used as a tuple index.
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        1,
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.1, ref $matcher)
+            ),
+            [$($struct_name)*],
+            2,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         1,
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.1, $matcher)
             ),
@@ -465,13 +612,30 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        2,
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.2, ref $matcher)
+            ),
+            [$($struct_name)*],
+            3,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         2,
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.2, $matcher)
             ),
@@ -482,13 +646,30 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        3,
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.3, ref $matcher)
+            ),
+            [$($struct_name)*],
+            4,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         3,
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.3, $matcher)
             ),
@@ -499,13 +680,30 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        4,
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.4, ref $matcher)
+            ),
+            [$($struct_name)*],
+            5,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         4,
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.4, $matcher)
             ),
@@ -516,13 +714,30 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        5,
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.5, ref $matcher)
+            ),
+            [$($struct_name)*],
+            6,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         5,
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.5, $matcher)
             ),
@@ -533,13 +748,30 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        6,
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.6, ref $matcher)
+            ),
+            [$($struct_name)*],
+            7,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         6,
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.6, $matcher)
             ),
@@ -550,13 +782,30 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        7,
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.7, ref $matcher)
+            ),
+            [$($struct_name)*],
+            8,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         7,
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.7, $matcher)
             ),
@@ -567,13 +816,30 @@
     };
 
     (
-        all!($($processed:tt)*),
+        @fields ($($processed:tt)*),
+        [$($struct_name:tt)*],
+        8,
+        (ref $matcher:expr, $($rest:tt)*)
+    ) => {
+        $crate::matches_pattern_internal!(
+            @fields (
+                $($processed)*,
+                field!($($struct_name)*.8, ref $matcher)
+            ),
+            [$($struct_name)*],
+            9,
+            ($($rest)*)
+        )
+    };
+
+    (
+        @fields ($($processed:tt)*),
         [$($struct_name:tt)*],
         8,
         ($matcher:expr, $($rest:tt)*)
     ) => {
         $crate::matches_pattern_internal!(
-            all!(
+            @fields (
                 $($processed)*,
                 field!($($struct_name)*.8, $matcher)
             ),
@@ -583,14 +849,14 @@
         )
     };
 
-    ([$($struct_name:tt)*], $first:tt $($rest:tt)*) => {
-        $crate::matches_pattern_internal!([$($struct_name)* $first], $($rest)*)
+    (@name [$($struct_name:tt)*], $first:tt $($rest:tt)*) => {
+        $crate::matches_pattern_internal!(@name [$($struct_name)* $first], $($rest)*)
     };
 
     ($first:tt $($rest:tt)*) => {{
         #[allow(unused)]
         use $crate::matchers::{all, field, property};
-        $crate::matches_pattern_internal!([$first], $($rest)*)
+        $crate::matches_pattern_internal!(@name [$first], $($rest)*)
     }};
 }
 
@@ -600,3 +866,59 @@
 macro_rules! __pat {
     ($($t:tt)*) => { $crate::matches_pattern_internal!($($t)*) }
 }
+
+#[doc(hidden)]
+pub mod internal {
+    use crate::matcher::{Matcher, MatcherBase};
+    use std::fmt::Debug;
+
+    // Specialized implementation of the `predicate` matcher to support ref binding
+    // mode for `matches_pattern`.
+    pub fn pattern_only<T>(
+        matcher_function: fn(&T) -> bool,
+        match_description: &'static str,
+        no_match_description: &'static str,
+    ) -> PatternOnlyMatcher<T> {
+        PatternOnlyMatcher { matcher_function, match_description, no_match_description }
+    }
+
+    #[derive(MatcherBase)]
+    #[doc(hidden)]
+    pub struct PatternOnlyMatcher<T> {
+        matcher_function: fn(&T) -> bool,
+        match_description: &'static str,
+        no_match_description: &'static str,
+    }
+
+    impl<'a, T: Debug> Matcher<&'a T> for PatternOnlyMatcher<T> {
+        fn matches(&self, actual: &'a T) -> crate::matcher::MatcherResult {
+            (self.matcher_function)(actual).into()
+        }
+
+        fn describe(
+            &self,
+            matcher_result: crate::matcher::MatcherResult,
+        ) -> crate::description::Description {
+            match matcher_result {
+                crate::matcher::MatcherResult::Match => self.match_description.into(),
+                crate::matcher::MatcherResult::NoMatch => self.no_match_description.into(),
+            }
+        }
+    }
+
+    impl<T: Debug + Copy> Matcher<T> for PatternOnlyMatcher<T> {
+        fn matches(&self, actual: T) -> crate::matcher::MatcherResult {
+            (self.matcher_function)(&actual).into()
+        }
+
+        fn describe(
+            &self,
+            matcher_result: crate::matcher::MatcherResult,
+        ) -> crate::description::Description {
+            match matcher_result {
+                crate::matcher::MatcherResult::Match => self.match_description.into(),
+                crate::matcher::MatcherResult::NoMatch => self.no_match_description.into(),
+            }
+        }
+    }
+}
diff --git a/crates/googletest/src/matchers/matches_regex_matcher.rs b/crates/googletest/src/matchers/matches_regex_matcher.rs
index 32b053b..2e00fb6 100644
--- a/crates/googletest/src/matchers/matches_regex_matcher.rs
+++ b/crates/googletest/src/matchers/matches_regex_matcher.rs
@@ -13,10 +13,9 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use regex::Regex;
 use std::fmt::Debug;
-use std::marker::PhantomData;
 use std::ops::Deref;
 
 /// Matches a string the entirety of which which matches the given regular
@@ -60,38 +59,31 @@
 // compiler treats it as a Matcher<str> only and the code
 //   verify_that!("Some value".to_string(), matches_regex(".*value"))?;
 // doesn't compile.
-pub fn matches_regex<ActualT: ?Sized, PatternT: Deref<Target = str>>(
+pub fn matches_regex<PatternT: Deref<Target = str>>(
     pattern: PatternT,
-) -> MatchesRegexMatcher<ActualT, PatternT> {
+) -> MatchesRegexMatcher<PatternT> {
     let adjusted_pattern = format!("^{}$", pattern.deref());
     let regex = Regex::new(adjusted_pattern.as_str()).unwrap();
-    MatchesRegexMatcher {
-        regex,
-        pattern,
-        _adjusted_pattern: adjusted_pattern,
-        phantom: Default::default(),
-    }
+    MatchesRegexMatcher { regex, pattern, _adjusted_pattern: adjusted_pattern }
 }
 
 /// A matcher matching a string-like type matching a given regular expression.
 ///
 /// Intended only to be used from the function [`matches_regex`] only.
 /// Should not be referenced by code outside this library.
-pub struct MatchesRegexMatcher<ActualT: ?Sized, PatternT: Deref<Target = str>> {
+#[derive(MatcherBase)]
+pub struct MatchesRegexMatcher<PatternT: Deref<Target = str>> {
     regex: Regex,
     pattern: PatternT,
     _adjusted_pattern: String,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<PatternT, ActualT> Matcher for MatchesRegexMatcher<ActualT, PatternT>
+impl<PatternT, ActualT> Matcher<ActualT> for MatchesRegexMatcher<PatternT>
 where
     PatternT: Deref<Target = str>,
-    ActualT: AsRef<str> + Debug + ?Sized,
+    ActualT: AsRef<str> + Debug + Copy,
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
+    fn matches(&self, actual: ActualT) -> MatcherResult {
         self.regex.is_match(actual.as_ref()).into()
     }
 
@@ -109,8 +101,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::{matches_regex, MatchesRegexMatcher};
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
 
     #[test]
@@ -201,10 +192,10 @@
 
     #[test]
     fn matches_regex_displays_quoted_debug_of_pattern() -> Result<()> {
-        let matcher: MatchesRegexMatcher<&str, _> = matches_regex("\n");
+        let matcher = matches_regex("\n");
 
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("matches the regular expression \"\\n\""))
         )
     }
diff --git a/crates/googletest/src/matchers/mod.rs b/crates/googletest/src/matchers/mod.rs
index 1e028b9..16ca900 100644
--- a/crates/googletest/src/matchers/mod.rs
+++ b/crates/googletest/src/matchers/mod.rs
@@ -17,17 +17,18 @@
 mod all_matcher;
 mod any_matcher;
 mod anything_matcher;
+mod bool_matcher;
 mod char_count_matcher;
 mod conjunction_matcher;
 mod container_eq_matcher;
 mod contains_matcher;
 mod contains_regex_matcher;
+mod derefs_to_matcher;
 mod disjunction_matcher;
 mod display_matcher;
 mod each_matcher;
 mod elements_are_matcher;
 mod empty_matcher;
-mod eq_deref_of_matcher;
 mod eq_matcher;
 mod err_matcher;
 mod field_matcher;
@@ -50,6 +51,7 @@
 mod pointwise_matcher;
 mod predicate_matcher;
 mod property_matcher;
+mod result_of_matcher;
 mod some_matcher;
 mod str_matcher;
 mod subset_of_matcher;
@@ -58,14 +60,15 @@
 mod unordered_elements_are_matcher;
 
 pub use anything_matcher::anything;
+pub use bool_matcher::{is_false, is_true};
 pub use char_count_matcher::char_count;
 pub use container_eq_matcher::container_eq;
 pub use contains_matcher::{contains, ContainsMatcher};
 pub use contains_regex_matcher::contains_regex;
+pub use derefs_to_matcher::derefs_to;
 pub use display_matcher::displays_as;
 pub use each_matcher::each;
 pub use empty_matcher::empty;
-pub use eq_deref_of_matcher::eq_deref_of;
 pub use eq_matcher::{eq, EqMatcher};
 pub use err_matcher::err;
 pub use ge_matcher::ge;
@@ -95,8 +98,8 @@
 pub use crate::{
     __all as all, __any as any, __contains_each as contains_each, __elements_are as elements_are,
     __field as field, __is_contained_in as is_contained_in, __matches_pattern as matches_pattern,
-    __pat as pat, __pointwise as pointwise, __property as property,
-    __unordered_elements_are as unordered_elements_are,
+    __pat as pat, __pointwise as pointwise, __property as property, __result_of as result_of,
+    __result_of_ref as result_of_ref, __unordered_elements_are as unordered_elements_are,
 };
 
 // Types and functions used by macros matchers.
@@ -105,16 +108,16 @@
 // should only be used through their respective macros.
 #[doc(hidden)]
 pub mod __internal_unstable_do_not_depend_on_these {
-    pub use super::all_matcher::internal::AllMatcher;
-    pub use super::any_matcher::internal::AnyMatcher;
     pub use super::conjunction_matcher::ConjunctionMatcher;
     pub use super::disjunction_matcher::DisjunctionMatcher;
     pub use super::elements_are_matcher::internal::ElementsAre;
     pub use super::field_matcher::internal::field_matcher;
     pub use super::is_matcher::is;
+    pub use super::matches_pattern::internal::pattern_only;
     pub use super::pointwise_matcher::internal::PointwiseMatcher;
     pub use super::property_matcher::internal::{property_matcher, property_ref_matcher};
+    pub use super::result_of_matcher::internal::{result_of, result_of_ref};
     pub use super::unordered_elements_are_matcher::internal::{
-        Requirements, UnorderedElementsAreMatcher, UnorderedElementsOfMapAreMatcher,
+        Requirements, UnorderedElementsAreMatcher,
     };
 }
diff --git a/crates/googletest/src/matchers/near_matcher.rs b/crates/googletest/src/matchers/near_matcher.rs
index ca7cbdf..de1eb3d 100644
--- a/crates/googletest/src/matchers/near_matcher.rs
+++ b/crates/googletest/src/matchers/near_matcher.rs
@@ -14,7 +14,7 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
 use num_traits::{Float, FloatConst};
 use std::fmt::Debug;
@@ -110,6 +110,7 @@
 /// # }
 /// # should_pass().unwrap();
 /// ```
+#[track_caller]
 pub fn near<T: Debug + Float + Copy>(expected: T, max_abs_error: T) -> NearMatcher<T> {
     if max_abs_error.is_nan() {
         panic!("max_abs_error must not be NaN");
@@ -139,6 +140,7 @@
 
 /// A matcher which matches floating-point numbers approximately equal to its
 /// expected value.
+#[derive(MatcherBase)]
 pub struct NearMatcher<T: Debug> {
     expected: T,
     max_abs_error: T,
@@ -166,15 +168,13 @@
     }
 }
 
-impl<T: Debug + Float> Matcher for NearMatcher<T> {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
+impl<T: Debug + Float + Copy> Matcher<T> for NearMatcher<T> {
+    fn matches(&self, actual: T) -> MatcherResult {
         if self.nans_are_equal && self.expected.is_nan() && actual.is_nan() {
             return MatcherResult::Match;
         }
 
-        let delta = *actual - self.expected;
+        let delta = actual - self.expected;
         if delta >= -self.max_abs_error && delta <= self.max_abs_error {
             MatcherResult::Match
         } else {
@@ -196,15 +196,14 @@
 
 #[cfg(test)]
 mod tests {
-    use super::{approx_eq, near};
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
 
     #[test]
     fn matches_value_inside_range() -> Result<()> {
         let matcher = near(1.0f64, 0.1f64);
 
-        let result = matcher.matches(&1.0f64);
+        let result = matcher.matches(1.0f64);
 
         verify_that!(result, eq(MatcherResult::Match))
     }
@@ -213,7 +212,7 @@
     fn matches_value_at_low_end_of_range() -> Result<()> {
         let matcher = near(1.0f64, 0.1f64);
 
-        let result = matcher.matches(&0.9f64);
+        let result = matcher.matches(0.9f64);
 
         verify_that!(result, eq(MatcherResult::Match))
     }
@@ -222,7 +221,7 @@
     fn matches_value_at_high_end_of_range() -> Result<()> {
         let matcher = near(1.0f64, 0.25f64);
 
-        let result = matcher.matches(&1.25f64);
+        let result = matcher.matches(1.25f64);
 
         verify_that!(result, eq(MatcherResult::Match))
     }
@@ -231,7 +230,7 @@
     fn does_not_match_value_below_low_end_of_range() -> Result<()> {
         let matcher = near(1.0f64, 0.1f64);
 
-        let result = matcher.matches(&0.899999f64);
+        let result = matcher.matches(0.899999f64);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
@@ -240,7 +239,7 @@
     fn does_not_match_value_above_high_end_of_range() -> Result<()> {
         let matcher = near(1.0f64, 0.1f64);
 
-        let result = matcher.matches(&1.100001f64);
+        let result = matcher.matches(1.100001f64);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
@@ -249,7 +248,7 @@
     fn nan_is_not_near_a_number() -> Result<()> {
         let matcher = near(0.0f64, f64::MAX);
 
-        let result = matcher.matches(&f64::NAN);
+        let result = matcher.matches(f64::NAN);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
@@ -283,7 +282,7 @@
     fn inf_is_not_near_inf() -> Result<()> {
         let matcher = near(f64::INFINITY, f64::MAX);
 
-        let result = matcher.matches(&f64::INFINITY);
+        let result = matcher.matches(f64::INFINITY);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
@@ -292,7 +291,7 @@
     fn inf_is_not_near_a_number() -> Result<()> {
         let matcher = near(f64::INFINITY, f64::MAX);
 
-        let result = matcher.matches(&f64::MIN);
+        let result = matcher.matches(f64::MIN);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
@@ -301,7 +300,7 @@
     fn any_two_numbers_are_within_inf_of_each_other() -> Result<()> {
         let matcher = near(f64::MIN, f64::INFINITY);
 
-        let result = matcher.matches(&f64::MAX);
+        let result = matcher.matches(f64::MAX);
 
         verify_that!(result, eq(MatcherResult::Match))
     }
diff --git a/crates/googletest/src/matchers/none_matcher.rs b/crates/googletest/src/matchers/none_matcher.rs
index af28932..b7a3555 100644
--- a/crates/googletest/src/matchers/none_matcher.rs
+++ b/crates/googletest/src/matchers/none_matcher.rs
@@ -13,9 +13,8 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use std::fmt::Debug;
-use std::marker::PhantomData;
 
 /// Matches an `Option` containing `None`.
 ///
@@ -32,19 +31,29 @@
 /// # should_pass().unwrap();
 /// # should_fail().unwrap_err();
 /// ```
-pub fn none<T: Debug>() -> impl Matcher<ActualT = Option<T>> {
-    NoneMatcher::<T> { phantom: Default::default() }
+pub fn none() -> NoneMatcher {
+    NoneMatcher
 }
 
-struct NoneMatcher<T> {
-    phantom: PhantomData<T>,
+#[derive(MatcherBase)]
+pub struct NoneMatcher;
+
+impl<T: Debug + Copy> Matcher<Option<T>> for NoneMatcher {
+    fn matches(&self, actual: Option<T>) -> MatcherResult {
+        actual.is_none().into()
+    }
+
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        match matcher_result {
+            MatcherResult::Match => "is none".into(),
+            MatcherResult::NoMatch => "is some(_)".into(),
+        }
+    }
 }
 
-impl<T: Debug> Matcher for NoneMatcher<T> {
-    type ActualT = Option<T>;
-
-    fn matches(&self, actual: &Option<T>) -> MatcherResult {
-        (actual.is_none()).into()
+impl<'a, T: Debug> Matcher<&'a Option<T>> for NoneMatcher {
+    fn matches(&self, actual: &'a Option<T>) -> MatcherResult {
+        actual.is_none().into()
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -57,15 +66,14 @@
 
 #[cfg(test)]
 mod tests {
-    use super::none;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
 
     #[test]
     fn none_matches_option_with_none() -> Result<()> {
-        let matcher = none::<i32>();
+        let matcher = none();
 
-        let result = matcher.matches(&None);
+        let result = matcher.matches(None::<i32>);
 
         verify_that!(result, eq(MatcherResult::Match))
     }
@@ -74,8 +82,47 @@
     fn none_does_not_match_option_with_value() -> Result<()> {
         let matcher = none();
 
-        let result = matcher.matches(&Some(0));
+        let result = matcher.matches(Some(0));
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
+
+    #[test]
+    fn none_matches_option_by_ref() -> Result<()> {
+        verify_that!(None::<String>, none())
+    }
+    #[test]
+    fn none_does_not_match_option_with_value_by_ref() -> Result<()> {
+        verify_that!(Some("123".to_string()), not(none()))
+    }
+
+    #[test]
+    fn none_describe_match_option_by_ref() -> Result<()> {
+        verify_that!(
+            Matcher::<&Option<String>>::describe(&none(), MatcherResult::Match),
+            displays_as(eq("is none"))
+        )
+    }
+    #[test]
+    fn none_describe_no_match_option_by_ref() -> Result<()> {
+        verify_that!(
+            Matcher::<&Option<String>>::describe(&none(), MatcherResult::NoMatch),
+            displays_as(eq("is some(_)"))
+        )
+    }
+
+    #[test]
+    fn none_describe_match_option() -> Result<()> {
+        verify_that!(
+            Matcher::<Option<i32>>::describe(&none(), MatcherResult::Match),
+            displays_as(eq("is none"))
+        )
+    }
+    #[test]
+    fn none_describe_no_match_option() -> Result<()> {
+        verify_that!(
+            Matcher::<Option<i32>>::describe(&none(), MatcherResult::NoMatch),
+            displays_as(eq("is some(_)"))
+        )
+    }
 }
diff --git a/crates/googletest/src/matchers/not_matcher.rs b/crates/googletest/src/matchers/not_matcher.rs
index f03d4ce..fa5f192 100644
--- a/crates/googletest/src/matchers/not_matcher.rs
+++ b/crates/googletest/src/matchers/not_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches the actual value exactly when the inner matcher does _not_ match.
 ///
@@ -33,28 +33,24 @@
 /// # should_pass().unwrap();
 /// # should_fail().unwrap_err();
 /// ```
-pub fn not<T: Debug, InnerMatcherT: Matcher<ActualT = T>>(
-    inner: InnerMatcherT,
-) -> impl Matcher<ActualT = T> {
-    NotMatcher::<T, _> { inner, phantom: Default::default() }
+pub fn not<InnerMatcherT>(inner: InnerMatcherT) -> NotMatcher<InnerMatcherT> {
+    NotMatcher { inner }
 }
 
-struct NotMatcher<T, InnerMatcherT> {
+#[derive(MatcherBase)]
+pub struct NotMatcher<InnerMatcherT> {
     inner: InnerMatcherT,
-    phantom: PhantomData<T>,
 }
 
-impl<T: Debug, InnerMatcherT: Matcher<ActualT = T>> Matcher for NotMatcher<T, InnerMatcherT> {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
+impl<T: Debug + Copy, InnerMatcherT: Matcher<T>> Matcher<T> for NotMatcher<InnerMatcherT> {
+    fn matches(&self, actual: T) -> MatcherResult {
         match self.inner.matches(actual) {
             MatcherResult::Match => MatcherResult::NoMatch,
             MatcherResult::NoMatch => MatcherResult::Match,
         }
     }
 
-    fn explain_match(&self, actual: &T) -> Description {
+    fn explain_match(&self, actual: T) -> Description {
         self.inner.explain_match(actual)
     }
 
@@ -69,8 +65,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::not;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
 
@@ -78,7 +73,7 @@
     fn matches_when_inner_matcher_does_not_match() -> Result<()> {
         let matcher = not(eq(1));
 
-        let result = matcher.matches(&0);
+        let result = matcher.matches(0);
 
         verify_that!(result, eq(MatcherResult::Match))
     }
@@ -87,14 +82,14 @@
     fn does_not_match_when_inner_matcher_matches() -> Result<()> {
         let matcher = not(eq(1));
 
-        let result = matcher.matches(&1);
+        let result = matcher.matches(1);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
     #[test]
     fn match_explanation_references_actual_value() -> Result<()> {
-        let result = verify_that!([1], not(container_eq([1])));
+        let result = verify_that!(&[1], not(container_eq([1])));
 
         verify_that!(
             result,
diff --git a/crates/googletest/src/matchers/ok_matcher.rs b/crates/googletest/src/matchers/ok_matcher.rs
index 8425b93..f399673 100644
--- a/crates/googletest/src/matchers/ok_matcher.rs
+++ b/crates/googletest/src/matchers/ok_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a `Result` containing `Ok` with a value matched by `inner`.
 ///
@@ -38,28 +38,55 @@
 /// # should_fail_1().unwrap_err();
 /// # should_fail_2().unwrap_err();
 /// ```
-pub fn ok<T: Debug, E: Debug>(
-    inner: impl Matcher<ActualT = T>,
-) -> impl Matcher<ActualT = std::result::Result<T, E>> {
-    OkMatcher::<T, E, _> { inner, phantom_t: Default::default(), phantom_e: Default::default() }
+pub fn ok<InnerMatcherT>(inner: InnerMatcherT) -> OkMatcher<InnerMatcherT> {
+    OkMatcher { inner }
 }
 
-struct OkMatcher<T, E, InnerMatcherT> {
+#[derive(MatcherBase)]
+pub struct OkMatcher<InnerMatcherT> {
     inner: InnerMatcherT,
-    phantom_t: PhantomData<T>,
-    phantom_e: PhantomData<E>,
 }
 
-impl<T: Debug, E: Debug, InnerMatcherT: Matcher<ActualT = T>> Matcher
-    for OkMatcher<T, E, InnerMatcherT>
+impl<T: Debug + Copy, E: Debug + Copy, InnerMatcherT: Matcher<T>> Matcher<std::result::Result<T, E>>
+    for OkMatcher<InnerMatcherT>
 {
-    type ActualT = std::result::Result<T, E>;
+    fn matches(&self, actual: std::result::Result<T, E>) -> MatcherResult {
+        actual.map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
+    }
 
-    fn matches(&self, actual: &Self::ActualT) -> MatcherResult {
+    fn explain_match(&self, actual: std::result::Result<T, E>) -> Description {
+        match actual {
+            Ok(o) => {
+                Description::new().text("which is a success").nested(self.inner.explain_match(o))
+            }
+            Err(_) => "which is an error".into(),
+        }
+    }
+
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        match matcher_result {
+            MatcherResult::Match => format!(
+                "is a success containing a value, which {}",
+                self.inner.describe(MatcherResult::Match)
+            )
+            .into(),
+            MatcherResult::NoMatch => format!(
+                "is an error or a success containing a value, which {}",
+                self.inner.describe(MatcherResult::NoMatch)
+            )
+            .into(),
+        }
+    }
+}
+
+impl<'a, T: Debug, E: Debug, InnerMatcherT: Matcher<&'a T>> Matcher<&'a std::result::Result<T, E>>
+    for OkMatcher<InnerMatcherT>
+{
+    fn matches(&self, actual: &'a std::result::Result<T, E>) -> MatcherResult {
         actual.as_ref().map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
     }
 
-    fn explain_match(&self, actual: &Self::ActualT) -> Description {
+    fn explain_match(&self, actual: &'a std::result::Result<T, E>) -> Description {
         match actual {
             Ok(o) => {
                 Description::new().text("which is a success").nested(self.inner.explain_match(o))
@@ -86,8 +113,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::ok;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
 
@@ -96,7 +122,7 @@
         let matcher = ok(eq(1));
         let value: std::result::Result<i32, i32> = Ok(1);
 
-        let result = matcher.matches(&value);
+        let result = matcher.matches(value);
 
         verify_that!(result, eq(MatcherResult::Match))
     }
@@ -106,7 +132,7 @@
         let matcher = ok(eq(1));
         let value: std::result::Result<i32, i32> = Ok(0);
 
-        let result = matcher.matches(&value);
+        let result = matcher.matches(value);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
@@ -116,12 +142,30 @@
         let matcher = ok(eq(1));
         let value: std::result::Result<i32, i32> = Err(1);
 
-        let result = matcher.matches(&value);
+        let result = matcher.matches(value);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
     #[test]
+    fn ok_matches_result_with_value_by_ref() -> Result<()> {
+        let result: std::result::Result<String, String> = Ok("123".into());
+        verify_that!(result, ok(eq("123")))
+    }
+
+    #[test]
+    fn ok_does_not_match_result_with_wrong_value_by_ref() -> Result<()> {
+        let result: std::result::Result<String, String> = Ok("321".into());
+        verify_that!(result, not(ok(eq("123"))))
+    }
+
+    #[test]
+    fn ok_does_not_match_result_with_err_by_ref() -> Result<()> {
+        let result: std::result::Result<String, String> = Err("123".into());
+        verify_that!(result, not(ok(eq("123"))))
+    }
+
+    #[test]
     fn ok_full_error_message() -> Result<()> {
         let result = verify_that!(Ok::<i32, i32>(1), ok(eq(2)));
 
@@ -140,15 +184,107 @@
     }
 
     #[test]
-    fn ok_describe_matches() -> Result<()> {
-        let matcher = super::OkMatcher::<i32, i32, _> {
-            inner: eq(1),
-            phantom_t: Default::default(),
-            phantom_e: Default::default(),
-        };
+    fn ok_describe_match() -> Result<()> {
+        let matcher = ok(eq(1));
         verify_that!(
-            matcher.describe(MatcherResult::Match),
+            Matcher::<std::result::Result<i32, i32>>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("is a success containing a value, which is equal to 1"))
         )
     }
+
+    #[test]
+    fn ok_describe_no_match() -> Result<()> {
+        let matcher = ok(eq(1));
+        verify_that!(
+            Matcher::<std::result::Result<i32, i32>>::describe(&matcher, MatcherResult::NoMatch),
+            displays_as(eq("is an error or a success containing a value, which isn't equal to 1"))
+        )
+    }
+
+    #[test]
+    fn ok_describe_match_by_ref() -> Result<()> {
+        let matcher = ok(eq(&1));
+        verify_that!(
+            Matcher::<&std::result::Result<i32, String>>::describe(&matcher, MatcherResult::Match),
+            displays_as(eq("is a success containing a value, which is equal to 1"))
+        )
+    }
+
+    #[test]
+    fn ok_describe_no_match_by_ref() -> Result<()> {
+        let matcher = ok(eq(&1));
+        verify_that!(
+            Matcher::<&std::result::Result<i32, String>>::describe(
+                &matcher,
+                MatcherResult::NoMatch
+            ),
+            displays_as(eq("is an error or a success containing a value, which isn't equal to 1"))
+        )
+    }
+
+    #[test]
+    fn ok_explain_match_ok_success() -> Result<()> {
+        let actual = Ok(1);
+        let matcher = ok(eq(1));
+
+        verify_that!(
+            Matcher::<std::result::Result<i32, i32>>::explain_match(&matcher, actual),
+            displays_as(eq("which is a success\n  which is equal to 1"))
+        )
+    }
+
+    #[test]
+    fn ok_explain_match_ok_fail() -> Result<()> {
+        let actual = Ok(1);
+        let matcher = ok(eq(2));
+
+        verify_that!(
+            Matcher::<std::result::Result<i32, i32>>::explain_match(&matcher, actual),
+            displays_as(eq("which is a success\n  which isn't equal to 2"))
+        )
+    }
+
+    #[test]
+    fn ok_explain_match_ok_err() -> Result<()> {
+        let actual = Err(1);
+        let matcher = ok(eq(2));
+
+        verify_that!(
+            Matcher::<std::result::Result<i32, i32>>::explain_match(&matcher, actual),
+            displays_as(eq("which is an error"))
+        )
+    }
+
+    #[test]
+    fn ok_explain_match_ok_success_by_ref() -> Result<()> {
+        let actual = Ok("123".to_string());
+        let matcher = ok(eq("123"));
+
+        verify_that!(
+            Matcher::<&std::result::Result<String, String>>::explain_match(&matcher, &actual),
+            displays_as(eq("which is a success\n  which is equal to \"123\""))
+        )
+    }
+
+    #[test]
+    fn ok_explain_match_ok_fail_by_ref() -> Result<()> {
+        let actual = Ok("321".to_string());
+        let matcher = ok(eq("123"));
+
+        verify_that!(
+            Matcher::<&std::result::Result<String, String>>::explain_match(&matcher, &actual),
+            displays_as(eq("which is a success\n  which isn't equal to \"123\""))
+        )
+    }
+
+    #[test]
+    fn ok_explain_match_ok_err_by_ref() -> Result<()> {
+        let actual = Err("123".to_string());
+        let matcher = ok(eq("123"));
+
+        verify_that!(
+            Matcher::<&std::result::Result<String, String>>::explain_match(&matcher, &actual),
+            displays_as(eq("which is an error"))
+        )
+    }
 }
diff --git a/crates/googletest/src/matchers/points_to_matcher.rs b/crates/googletest/src/matchers/points_to_matcher.rs
index 2c516d0..0653e03 100644
--- a/crates/googletest/src/matchers/points_to_matcher.rs
+++ b/crates/googletest/src/matchers/points_to_matcher.rs
@@ -13,55 +13,46 @@
 // limitations under the License.
 
 use crate::description::Description;
-use crate::matcher::{Matcher, MatcherResult};
+use crate::matcher::{Matcher, MatcherBase, MatcherResult};
 use std::fmt::Debug;
-use std::marker::PhantomData;
-use std::ops::Deref;
 
-/// Matches a (smart) pointer pointing to a value matched by the [`Matcher`]
+/// Matches a reference pointing to a value matched by the [`Matcher`]
 /// `expected`.
 ///
-/// This allows easily matching smart pointers such as `Box`, `Rc`, and `Arc`.
+/// This is useful for combining matchers, especially when working with
+/// iterators.
+///
 /// For example:
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(Box::new(123), points_to(eq(123)))?;
+/// verify_that!(&123, points_to(eq(123)))?;
+/// verify_that!(vec![1,2,3], each(points_to(gt(0))))?;
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
 /// ```
-pub fn points_to<ExpectedT, MatcherT, ActualT>(
-    expected: MatcherT,
-) -> impl Matcher<ActualT = ActualT>
-where
-    ExpectedT: Debug,
-    MatcherT: Matcher<ActualT = ExpectedT>,
-    ActualT: Deref<Target = ExpectedT> + Debug + ?Sized,
-{
-    PointsToMatcher { expected, phantom: Default::default() }
+pub fn points_to<MatcherT>(expected: MatcherT) -> PointsToMatcher<MatcherT> {
+    PointsToMatcher { expected }
 }
 
-struct PointsToMatcher<ActualT: ?Sized, MatcherT> {
+#[derive(MatcherBase)]
+pub struct PointsToMatcher<MatcherT> {
     expected: MatcherT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ExpectedT, MatcherT, ActualT> Matcher for PointsToMatcher<ActualT, MatcherT>
+impl<'a, ExpectedT, MatcherT> Matcher<&'a ExpectedT> for PointsToMatcher<MatcherT>
 where
-    ExpectedT: Debug,
-    MatcherT: Matcher<ActualT = ExpectedT>,
-    ActualT: Deref<Target = ExpectedT> + Debug + ?Sized,
+    ExpectedT: Debug + Copy,
+    MatcherT: Matcher<ExpectedT>,
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
-        self.expected.matches(actual.deref())
+    fn matches(&self, actual: &'a ExpectedT) -> MatcherResult {
+        self.expected.matches(*actual)
     }
 
-    fn explain_match(&self, actual: &ActualT) -> Description {
-        self.expected.explain_match(actual.deref())
+    fn explain_match(&self, actual: &'a ExpectedT) -> Description {
+        self.expected.explain_match(*actual)
     }
 
     fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -71,36 +62,24 @@
 
 #[cfg(test)]
 mod tests {
-    use super::points_to;
     use crate::prelude::*;
     use indoc::indoc;
-    use std::rc::Rc;
 
     #[test]
-    fn points_to_matches_box_of_int_with_int() -> Result<()> {
-        verify_that!(Box::new(123), points_to(eq(123)))
-    }
-
-    #[test]
-    fn points_to_matches_rc_of_int_with_int() -> Result<()> {
-        verify_that!(Rc::new(123), points_to(eq(123)))
-    }
-
-    #[test]
-    fn points_to_matches_box_of_owned_string_with_string_reference() -> Result<()> {
-        verify_that!(Rc::new("A string".to_string()), points_to(eq("A string")))
+    fn points_to_matches_ref() -> Result<()> {
+        verify_that!(&123, points_to(eq(123)))
     }
 
     #[test]
     fn match_explanation_references_actual_value() -> Result<()> {
-        let result = verify_that!(&vec![1], points_to(container_eq([])));
+        let result = verify_that!(&1, points_to(eq(0)));
 
         verify_that!(
             result,
             err(displays_as(contains_substring(indoc!(
                 "
-                    Actual: [1],
-                      which contains the unexpected element 1
+                    Actual: 1,
+                      which isn't equal to 0
                 "
             ))))
         )
diff --git a/crates/googletest/src/matchers/pointwise_matcher.rs b/crates/googletest/src/matchers/pointwise_matcher.rs
index 01e70c0..a3a0d74 100644
--- a/crates/googletest/src/matchers/pointwise_matcher.rs
+++ b/crates/googletest/src/matchers/pointwise_matcher.rs
@@ -27,13 +27,14 @@
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
 /// let value = vec![1, 2, 3];
-/// verify_that!(value, pointwise!(le, [1, 3, 3]))?; // Passes
-/// verify_that!(value, pointwise!(le, vec![1, 3, 3]))?; // Passes
+/// verify_that!(value, pointwise!(le, [&1, &2, &3]))?; // Passes
+/// verify_that!(value, pointwise!(|e| points_to(le(e)), [1, 2, 3]))?; // Passes
+/// verify_that!(value, pointwise!(|e| points_to(le(e)), vec![1, 3, 3]))?; // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail() -> Result<()> {
 /// #     let value = vec![1, 2, 3];
-/// verify_that!(value, pointwise!(le, [1, 1, 3]))?; // Fails
+/// verify_that!(value, pointwise!(|e| points_to(le(e)), [1, 1, 3]))?; // Fails
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -46,7 +47,7 @@
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
 /// let value = vec![1.00001, 2.000001, 3.00001];
-/// verify_that!(value, pointwise!(|v| near(v, 0.001), [1.0, 2.0, 3.0]))?;
+/// verify_that!(value, pointwise!(|v| points_to(near(v, 0.001)), [1.0, 2.0, 3.0]))?;
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -59,12 +60,11 @@
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
 /// let value = vec![1.00001, 2.000001, 3.00001];
-/// verify_that!(value, pointwise!(|v, t| near(v, t), [1.0, 2.0, 3.0], [0.001, 0.0001, 0.01]))?;
-/// verify_that!(value, pointwise!(near, [1.0, 2.0, 3.0], [0.001, 0.0001, 0.01]))?; // Same as above
+/// verify_that!(value, pointwise!(|v, t| points_to(near(v, t)), [1.0, 2.0, 3.0], [0.001, 0.0001, 0.01]))?;
 /// verify_that!(
 ///     value,
 ///     pointwise!(
-///         |v, t, u| near(v, t * u),
+///         |v, t, u| points_to(near(v, t * u)),
 ///         [1.0, 2.0, 3.0],
 ///         [0.001, 0.0001, 0.01],
 ///         [0.5, 0.5, 1.0]
@@ -79,25 +79,20 @@
 /// that all of the containers have the same size. This matcher does not check
 /// whether the sizes match.
 ///
-/// The actual value must be a container such as a `Vec`, an array, or a
-/// dereferenced slice. More precisely, a shared borrow of the actual value must
-/// implement [`IntoIterator`].
+/// The actual value must be a container such as a `&Vec`, an array, or a
+/// slice. More precisely, the actual value must implement [`IntoIterator`].
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
 /// let value = vec![1, 2, 3];
-/// verify_that!(*value.as_slice(), pointwise!(le, [1, 3, 3]))?; // Passes
+/// verify_that!(value, pointwise!(|i| points_to(le(i)), [1, 3, 3]))?; // Passes
 /// verify_that!([1, 2, 3], pointwise!(le, [1, 3, 3]))?; // Passes
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
 /// ```
 ///
-/// This matcher does not support matching directly against an [`Iterator`]. To
-/// match against an iterator, use [`Iterator::collect`] to build a [`Vec`]
-/// first.
-///
 /// The second argument can be any value implementing `IntoIterator`, such as a
 /// `Vec` or an array. The container does not have to have the same type as the
 /// actual value, but the value type must be the same.
@@ -119,13 +114,13 @@
 #[doc(hidden)]
 macro_rules! __pointwise {
     ($matcher:expr, $container:expr) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::PointwiseMatcher;
-        PointwiseMatcher::new($container.into_iter().map($matcher).collect())
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::PointwiseMatcher::new(
+            $container.into_iter().map($matcher).collect(),
+        )
     }};
 
     ($matcher:expr, $left_container:expr, $right_container:expr) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::PointwiseMatcher;
-        PointwiseMatcher::new(
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::PointwiseMatcher::new(
             $left_container
                 .into_iter()
                 .zip($right_container.into_iter())
@@ -135,8 +130,7 @@
     }};
 
     ($matcher:expr, $left_container:expr, $middle_container:expr, $right_container:expr) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::PointwiseMatcher;
-        PointwiseMatcher::new(
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::PointwiseMatcher::new(
             $left_container
                 .into_iter()
                 .zip($right_container.into_iter().zip($middle_container.into_iter()))
@@ -152,33 +146,31 @@
 #[doc(hidden)]
 pub mod internal {
     use crate::description::Description;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::{Matcher, MatcherBase, MatcherResult};
     use crate::matcher_support::zipped_iterator::zip;
-    use std::{fmt::Debug, marker::PhantomData};
+    use std::fmt::Debug;
 
     /// This struct is meant to be used only through the `pointwise` macro.
     ///
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
-    pub struct PointwiseMatcher<ContainerT: ?Sized, MatcherT> {
+    #[derive(MatcherBase)]
+    pub struct PointwiseMatcher<MatcherT> {
         matchers: Vec<MatcherT>,
-        phantom: PhantomData<ContainerT>,
     }
 
-    impl<ContainerT: ?Sized, MatcherT> PointwiseMatcher<ContainerT, MatcherT> {
+    impl<MatcherT> PointwiseMatcher<MatcherT> {
         pub fn new(matchers: Vec<MatcherT>) -> Self {
-            Self { matchers, phantom: Default::default() }
+            Self { matchers }
         }
     }
 
-    impl<T: Debug, MatcherT: Matcher<ActualT = T>, ContainerT: ?Sized + Debug> Matcher
-        for PointwiseMatcher<ContainerT, MatcherT>
+    impl<T: Debug + Copy, MatcherT: Matcher<T>, ContainerT: Copy + Debug> Matcher<ContainerT>
+        for PointwiseMatcher<MatcherT>
     where
-        for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
+        ContainerT: IntoIterator<Item = T>,
     {
-        type ActualT = ContainerT;
-
-        fn matches(&self, actual: &ContainerT) -> MatcherResult {
+        fn matches(&self, actual: ContainerT) -> MatcherResult {
             let mut zipped_iterator = zip(actual.into_iter(), self.matchers.iter());
             for (element, matcher) in zipped_iterator.by_ref() {
                 if matcher.matches(element).is_no_match() {
@@ -192,7 +184,7 @@
             }
         }
 
-        fn explain_match(&self, actual: &ContainerT) -> Description {
+        fn explain_match(&self, actual: ContainerT) -> Description {
             // TODO(b/260819741) This code duplicates elements_are_matcher.rs. Consider
             // extract as a separate library. (or implement pointwise! with
             // elements_are)
diff --git a/crates/googletest/src/matchers/predicate_matcher.rs b/crates/googletest/src/matchers/predicate_matcher.rs
index 5bc067d..1ba81c4 100644
--- a/crates/googletest/src/matchers/predicate_matcher.rs
+++ b/crates/googletest/src/matchers/predicate_matcher.rs
@@ -14,43 +14,37 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Creates a matcher based on the predicate provided.
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(3, predicate(|x: &i32| x % 2 == 1))?;  // Passes
+/// verify_that!(3, predicate(|x: i32| x % 2 == 1))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
 /// ```
 ///
-/// The predicate should take the subject type by reference and return a
+/// The predicate should take the subject type and return a
 /// boolean.
 ///
 /// Note: even if the Rust compiler should be able to infer the type of
 /// the closure argument, it is likely that it won't.
 /// See <https://github.com/rust-lang/rust/issues/12679> for update on this issue.
 /// This is easily fixed by explicitly declaring the type of the argument
-pub fn predicate<T: Debug + ?Sized, P>(
-    predicate: P,
-) -> PredicateMatcher<T, P, NoDescription, NoDescription>
-where
-    for<'a> P: Fn(&'a T) -> bool,
-{
+pub fn predicate<P>(predicate: P) -> PredicateMatcher<P, NoDescription, NoDescription> {
     PredicateMatcher {
         predicate,
         positive_description: NoDescription,
         negative_description: NoDescription,
-        phantom: Default::default(),
     }
 }
 
-impl<T, P> PredicateMatcher<T, P, NoDescription, NoDescription> {
+impl<P> PredicateMatcher<P, NoDescription, NoDescription> {
     /// Configures this instance to provide a more meaningful description.
     ///
     /// For example, to make sure the error message is more useful
@@ -58,7 +52,7 @@
     /// ```
     /// # use googletest::matchers::{predicate, PredicateMatcher};
     /// # let _ =
-    /// predicate(|x: &i32| x % 2 == 1)
+    /// predicate(|x: i32| x % 2 == 1)
     ///     .with_description("is odd", "is even")
     /// # ;
     /// ```
@@ -70,24 +64,19 @@
         self,
         positive_description: D1,
         negative_description: D2,
-    ) -> PredicateMatcher<T, P, D1, D2> {
-        PredicateMatcher {
-            predicate: self.predicate,
-            positive_description,
-            negative_description,
-            phantom: Default::default(),
-        }
+    ) -> PredicateMatcher<P, D1, D2> {
+        PredicateMatcher { predicate: self.predicate, positive_description, negative_description }
     }
 }
 
 /// A matcher which applies `predicate` on the value.
 ///
 /// See [`predicate`].
-pub struct PredicateMatcher<T: ?Sized, P, D1, D2> {
+#[derive(MatcherBase)]
+pub struct PredicateMatcher<P, D1, D2> {
     predicate: P,
     positive_description: D1,
     negative_description: D2,
-    phantom: PhantomData<T>,
 }
 
 /// A trait to allow [`PredicateMatcher::with_description`] to accept multiple
@@ -124,13 +113,11 @@
 #[doc(hidden)]
 pub struct NoDescription;
 
-impl<T: Debug, P> Matcher for PredicateMatcher<T, P, NoDescription, NoDescription>
+impl<T: Debug + Copy, P> Matcher<T> for PredicateMatcher<P, NoDescription, NoDescription>
 where
-    for<'a> P: Fn(&'a T) -> bool,
+    P: Fn(T) -> bool,
 {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
+    fn matches(&self, actual: T) -> MatcherResult {
         (self.predicate)(actual).into()
     }
 
@@ -142,14 +129,12 @@
     }
 }
 
-impl<T: Debug, P, D1: PredicateDescription, D2: PredicateDescription> Matcher
-    for PredicateMatcher<T, P, D1, D2>
+impl<T: Debug + Copy, P, D1: PredicateDescription, D2: PredicateDescription> Matcher<T>
+    for PredicateMatcher<P, D1, D2>
 where
-    for<'a> P: Fn(&'a T) -> bool,
+    P: Fn(T) -> bool,
 {
-    type ActualT = T;
-
-    fn matches(&self, actual: &T) -> MatcherResult {
+    fn matches(&self, actual: T) -> MatcherResult {
         (self.predicate)(actual).into()
     }
 
@@ -163,12 +148,10 @@
 
 #[cfg(test)]
 mod tests {
-    use super::predicate;
-    use crate::matcher::Matcher;
     use crate::prelude::*;
 
     // Simple matcher with a description
-    fn is_odd() -> impl Matcher<ActualT = i32> {
+    fn is_odd() -> impl Matcher<i32> {
         predicate(|x| x % 2 == 1).with_description("is odd", "is even")
     }
 
@@ -179,16 +162,16 @@
 
     #[test]
     fn predicate_matcher_odd_explain_match_matches() -> Result<()> {
-        verify_that!(is_odd().explain_match(&1), displays_as(eq("which is odd")))
+        verify_that!(is_odd().explain_match(1), displays_as(eq("which is odd")))
     }
 
     #[test]
     fn predicate_matcher_odd_explain_match_does_not_match() -> Result<()> {
-        verify_that!(is_odd().explain_match(&2), displays_as(eq("which is even")))
+        verify_that!(is_odd().explain_match(2), displays_as(eq("which is even")))
     }
 
     // Simple Matcher without description
-    fn is_even() -> impl Matcher<ActualT = i32> {
+    fn is_even() -> impl Matcher<i32> {
         predicate(|x| x % 2 == 0)
     }
 
@@ -199,18 +182,18 @@
 
     #[test]
     fn predicate_matcher_even_explain_match_matches() -> Result<()> {
-        verify_that!(is_even().explain_match(&2), displays_as(eq("which matches")))
+        verify_that!(is_even().explain_match(2), displays_as(eq("which matches")))
     }
 
     #[test]
     fn predicate_matcher_even_explain_match_does_not_match() -> Result<()> {
-        verify_that!(is_even().explain_match(&1), displays_as(eq("which does not match")))
+        verify_that!(is_even().explain_match(1), displays_as(eq("which does not match")))
     }
 
     #[test]
     fn predicate_matcher_generator_lambda() -> Result<()> {
         let is_divisible_by = |quotient| {
-            predicate(move |x: &i32| x % quotient == 0).with_description(
+            predicate(move |x: i32| x % quotient == 0).with_description(
                 move || format!("is divisible by {quotient}"),
                 move || format!("is not divisible by {quotient}"),
             )
@@ -220,12 +203,12 @@
 
     #[test]
     fn predicate_matcher_inline() -> Result<()> {
-        verify_that!(2048, predicate(|x: &i32| x.count_ones() == 1))
+        verify_that!(2048, predicate(|x: i32| x.count_ones() == 1))
     }
 
     #[test]
     fn predicate_matcher_function_pointer() -> Result<()> {
         use std::time::Duration;
-        verify_that!(Duration::new(0, 0), predicate(Duration::is_zero))
+        verify_that!(&Duration::new(0, 0), predicate(Duration::is_zero))
     }
 }
diff --git a/crates/googletest/src/matchers/property_matcher.rs b/crates/googletest/src/matchers/property_matcher.rs
index 19b4862..98c51a6 100644
--- a/crates/googletest/src/matchers/property_matcher.rs
+++ b/crates/googletest/src/matchers/property_matcher.rs
@@ -35,7 +35,26 @@
 /// }
 ///
 /// let value = vec![MyStruct { a_field: 100 }];
-/// verify_that!(value, contains(property!(MyStruct.get_a_field(), eq(100))))
+/// verify_that!(value, contains(property!(&MyStruct.get_a_field(), eq(100))))
+/// #    .unwrap();
+/// ```
+///
+///
+/// If the inner matcher is `eq(...)`, it can be omitted:
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug)]
+/// pub struct MyStruct {
+///     a_field: u32,
+/// }
+///
+/// impl MyStruct {
+///     pub fn get_a_field(&self) -> u32 { self.a_field }
+/// }
+///
+/// let value = vec![MyStruct { a_field: 100 }];
+/// verify_that!(value, contains(property!(&MyStruct.get_a_field(), 100)))
 /// #    .unwrap();
 /// ```
 ///
@@ -44,24 +63,7 @@
 /// failure, it will be invoked a second time, with the assertion failure output
 /// reflecting the *second* invocation.
 ///
-/// If the method returns a *reference*, then it must be preceded by a `*`:
-///
-/// ```
-/// # use googletest::prelude::*;
-/// # #[derive(Debug)]
-/// # pub struct MyStruct {
-/// #     a_field: u32,
-/// # }
-/// impl MyStruct {
-///     pub fn get_a_field(&self) -> &u32 { &self.a_field }
-/// }
-///
-/// # let value = vec![MyStruct { a_field: 100 }];
-/// verify_that!(value, contains(property!(*MyStruct.get_a_field(), eq(100))))
-/// #    .unwrap();
-/// ```
-///
-/// The method may also take additional arguments:
+/// The method may also take additional litteral arguments:
 ///
 /// ```
 /// # use googletest::prelude::*;
@@ -74,26 +76,88 @@
 /// }
 ///
 /// # let value = vec![MyStruct { a_field: 100 }];
-/// verify_that!(value, contains(property!(MyStruct.add_to_a_field(50), eq(150))))
+/// verify_that!(value, contains(property!(&MyStruct.add_to_a_field(50), eq(150))))
 /// #    .unwrap();
 /// ```
 ///
-/// Unfortunately, this matcher does *not* work with methods returning string
-/// slices:
+/// The arguments must be litteral as `property!` is not able to capture them.
 ///
-/// ```compile_fail
+/// # Specification of the property pattern
+///
+/// The specification of the field follow the syntax: `(ref)? (&)?
+/// $TYPE.$PROPERTY\($ARGUMENT\)`.
+///
+/// The `&` allows to specify whether this matcher matches against an actual of
+/// type `$TYPE` (`$TYPE` must implement `Copy`) or a `&$TYPE`.
+///
+/// For instance:
+///
+/// ```
 /// # use googletest::prelude::*;
 /// #[derive(Debug)]
-/// pub struct MyStruct {
-///     a_string: String,
-/// }
-/// impl MyStruct {
-///     pub fn get_a_string(&self) -> &str { &self.a_string }
-/// }
+/// pub struct AStruct;
 ///
-/// let value = MyStruct { a_string: "A string".into() };
-/// verify_that!(value, property!(*MyStruct.get_a_string(), eq("A string"))) // Does not compile
-/// #    .unwrap();
+/// impl AStruct {
+///   fn a_property(&self) -> i32 {32}
+/// }
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(AStruct, property!(&AStruct.a_property(), eq(32)))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
+/// ```
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug, Clone, Copy)]
+/// pub struct AStruct;
+///
+/// impl AStruct {
+///   fn a_property(self) -> i32 {32}
+/// }
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(AStruct, property!(AStruct.a_property(), eq(32)))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
+/// ```
+///
+/// The `ref` allows to bind the property returned value by reference, which is
+/// required if the field type does not implement `Copy`.
+///
+/// For instance:
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug)]
+/// pub struct AStruct;
+///
+/// impl AStruct {
+///   fn a_property(&self) -> i32 {32}
+/// }
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(AStruct, property!(&AStruct.a_property(), eq(32)))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
+/// ```
+///
+/// If `property!` is qualified by both `&` and `ref`, they can both be omitted.
+///
+/// ```
+/// # use googletest::prelude::*;
+/// #[derive(Debug)]
+/// pub struct AStruct;
+///
+/// impl AStruct {
+///   fn a_property(&self) -> String {"32".into()}
+/// }
+/// # fn should_pass() -> Result<()> {
+/// verify_that!(AStruct, property!(&AStruct.a_property(), ref eq("32")))?;
+/// verify_that!(AStruct, property!(AStruct.a_property(), eq("32")))?;
+/// #     Ok(())
+/// # }
+/// # should_pass().unwrap();
 /// ```
 ///
 /// This macro is analogous to [`field`][crate::matchers::field], except that it
@@ -112,20 +176,30 @@
 #[doc(hidden)]
 #[macro_export]
 macro_rules! property_internal {
-    ($($t:ident)::+.$method:tt($($argument:tt),* $(,)?), $m:expr) => {{
-         use $crate::matchers::__internal_unstable_do_not_depend_on_these::property_matcher;
-        property_matcher(
-            |o: &$($t)::+| o.$method($($argument),*),
-            &stringify!($method($($argument),*)),
-            $m)
-    }};
 
-    (* $($t:ident)::+.$method:tt($($argument:tt),* $(,)?), $m:expr) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::property_ref_matcher;
-        property_ref_matcher(
+    (&$($t:ident)::+.$method:tt($($argument:tt),* $(,)?), ref $m:expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::property_ref_matcher(
+            |o: &$($t)::+| $($t)::+::$method(o, $($argument),*),
+            &stringify!($method($($argument),*)),
+            $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
+    }};
+    ($($t:ident)::+.$method:tt($($argument:tt),* $(,)?), ref $m:expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::property_ref_matcher(
+            |o: $($t)::+| $($t)::+::$method(o, $($argument),*),
+            &stringify!($method($($argument),*)),
+            $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
+    }};
+    (& $($t:ident)::+.$method:tt($($argument:tt),* $(,)?), $m:expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::property_matcher(
+            |o: &&$($t)::+| o.$method($($argument),*),
+            &stringify!($method($($argument),*)),
+            $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
+    }};
+    ($($t:ident)::+.$method:tt($($argument:tt),* $(,)?), $m:expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::property_matcher(
             |o: &$($t)::+| o.$method($($argument),*),
             &stringify!($method($($argument),*)),
-            $m)
+            $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
     }};
 }
 
@@ -136,37 +210,65 @@
 pub mod internal {
     use crate::{
         description::Description,
-        matcher::{Matcher, MatcherResult},
+        matcher::{Matcher, MatcherBase, MatcherResult},
     };
-    use std::{fmt::Debug, marker::PhantomData};
+    use std::fmt::Debug;
 
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
-    pub fn property_matcher<OuterT: Debug, InnerT: Debug, MatcherT: Matcher<ActualT = InnerT>>(
-        extractor: impl Fn(&OuterT) -> InnerT,
+    pub fn property_matcher<OuterT: Debug, InnerT: Debug, MatcherT>(
+        extractor: fn(&OuterT) -> InnerT,
         property_desc: &'static str,
         inner: MatcherT,
-    ) -> impl Matcher<ActualT = OuterT> {
-        PropertyMatcher { extractor, property_desc, inner, phantom: Default::default() }
+    ) -> PropertyMatcher<OuterT, InnerT, MatcherT> {
+        PropertyMatcher { extractor, property_desc, inner }
     }
 
-    struct PropertyMatcher<OuterT, ExtractorT, MatcherT> {
-        extractor: ExtractorT,
+    #[derive(MatcherBase)]
+    pub struct PropertyMatcher<OuterT, InnerT, MatcherT> {
+        extractor: fn(&OuterT) -> InnerT,
         property_desc: &'static str,
         inner: MatcherT,
-        phantom: PhantomData<OuterT>,
     }
 
-    impl<InnerT, OuterT, ExtractorT, MatcherT> Matcher for PropertyMatcher<OuterT, ExtractorT, MatcherT>
+    impl<InnerT, OuterT, MatcherT> Matcher<OuterT> for PropertyMatcher<OuterT, InnerT, MatcherT>
+    where
+        InnerT: Debug + Copy,
+        OuterT: Debug + Copy,
+        MatcherT: Matcher<InnerT>,
+    {
+        fn matches(&self, actual: OuterT) -> MatcherResult {
+            self.inner.matches((self.extractor)(&actual))
+        }
+
+        fn describe(&self, matcher_result: MatcherResult) -> Description {
+            format!(
+                "has property `{}`, which {}",
+                self.property_desc,
+                self.inner.describe(matcher_result)
+            )
+            .into()
+        }
+
+        fn explain_match(&self, actual: OuterT) -> Description {
+            let actual_inner = (self.extractor)(&actual);
+            format!(
+                "whose property `{}` is `{:#?}`, {}",
+                self.property_desc,
+                actual_inner,
+                self.inner.explain_match(actual_inner)
+            )
+            .into()
+        }
+    }
+
+    impl<'a, InnerT, OuterT, MatcherT> Matcher<&'a OuterT> for PropertyMatcher<OuterT, InnerT, MatcherT>
     where
         InnerT: Debug,
         OuterT: Debug,
-        ExtractorT: Fn(&OuterT) -> InnerT,
-        MatcherT: Matcher<ActualT = InnerT>,
+        MatcherT: for<'b> Matcher<&'b InnerT>,
     {
-        type ActualT = OuterT;
-
-        fn matches(&self, actual: &OuterT) -> MatcherResult {
+        fn matches(&self, actual: &'a OuterT) -> MatcherResult {
             self.inner.matches(&(self.extractor)(actual))
         }
 
@@ -179,7 +281,7 @@
             .into()
         }
 
-        fn explain_match(&self, actual: &OuterT) -> Description {
+        fn explain_match(&self, actual: &'a OuterT) -> Description {
             let actual_inner = (self.extractor)(actual);
             format!(
                 "whose property `{}` is `{:#?}`, {}",
@@ -193,32 +295,36 @@
 
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
-    pub fn property_ref_matcher<OuterT, InnerT, MatcherT>(
-        extractor: fn(&OuterT) -> &InnerT,
+    pub fn property_ref_matcher<OuterT, InnerT, ExtractorT, MatcherT>(
+        extractor: ExtractorT,
         property_desc: &'static str,
         inner: MatcherT,
-    ) -> impl Matcher<ActualT = OuterT>
+    ) -> PropertyRefMatcher<ExtractorT, MatcherT>
     where
         OuterT: Debug,
-        InnerT: Debug + ?Sized,
-        MatcherT: Matcher<ActualT = InnerT>,
+        InnerT: Debug,
+        MatcherT: for<'a> Matcher<&'a InnerT>,
+        ExtractorT: Fn(OuterT) -> InnerT,
     {
         PropertyRefMatcher { extractor, property_desc, inner }
     }
 
-    struct PropertyRefMatcher<InnerT: ?Sized, OuterT, MatcherT> {
-        extractor: fn(&OuterT) -> &InnerT,
+    #[derive(MatcherBase)]
+    pub struct PropertyRefMatcher<ExtractorT, MatcherT> {
+        extractor: ExtractorT,
         property_desc: &'static str,
         inner: MatcherT,
     }
 
-    impl<InnerT: Debug + ?Sized, OuterT: Debug, MatcherT: Matcher<ActualT = InnerT>> Matcher
-        for PropertyRefMatcher<InnerT, OuterT, MatcherT>
+    impl<
+            InnerT: Debug,
+            OuterT: Debug + Copy,
+            MatcherT: for<'a> Matcher<&'a InnerT>,
+            ExtractorT: Fn(OuterT) -> InnerT,
+        > Matcher<OuterT> for PropertyRefMatcher<ExtractorT, MatcherT>
     {
-        type ActualT = OuterT;
-
-        fn matches(&self, actual: &OuterT) -> MatcherResult {
-            self.inner.matches((self.extractor)(actual))
+        fn matches(&self, actual: OuterT) -> MatcherResult {
+            self.inner.matches(&(self.extractor)(actual))
         }
 
         fn describe(&self, matcher_result: MatcherResult) -> Description {
@@ -230,13 +336,13 @@
             .into()
         }
 
-        fn explain_match(&self, actual: &OuterT) -> Description {
+        fn explain_match(&self, actual: OuterT) -> Description {
             let actual_inner = (self.extractor)(actual);
             format!(
                 "whose property `{}` is `{:#?}`, {}",
                 self.property_desc,
                 actual_inner,
-                self.inner.explain_match(actual_inner)
+                self.inner.explain_match(&actual_inner)
             )
             .into()
         }
diff --git a/crates/googletest/src/matchers/result_of_matcher.rs b/crates/googletest/src/matchers/result_of_matcher.rs
new file mode 100644
index 0000000..c75fe66
--- /dev/null
+++ b/crates/googletest/src/matchers/result_of_matcher.rs
@@ -0,0 +1,440 @@
+// Copyright 2024 Google LLC
+//
+// 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.
+
+/// Matches a value where the result of `callable` applied to the value matches
+/// the inner matcher.
+///
+/// The `callable` will be called twice, so make sure it is pure.
+/// ```
+/// use googletest::prelude::*;
+/// fn should_pass() -> googletest::Result<()> {
+///    verify_that!(100, result_of!(|value| value + 1, eq(101)))?; // Passes
+///    Ok(())
+/// }
+///
+/// fn should_fail() -> googletest::Result<()> {
+///    verify_that!(100, result_of!(|value| value * 2, eq(100)))?; // Fails
+///    Ok(())
+/// }
+/// should_pass().unwrap();
+/// should_fail().unwrap_err();
+/// ```
+#[macro_export]
+macro_rules! __result_of {
+    ($function: expr, $matcher: expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::result_of(
+            $function,
+            $matcher,
+            stringify!($function),
+        )
+    }};
+}
+
+/// Matches a value where the reference to the result of `callable` applied to
+/// the value matches the inner matcher.
+///
+/// The `callable` will be called twice, so make sure it is pure.
+/// ```
+/// use googletest::prelude::*;
+/// fn should_pass_1() -> googletest::Result<()> {
+///    verify_that!("hello", result_of_ref!(|s: &str| s.to_uppercase(), eq("HELLO")))?; // Passes
+///    Ok(())
+/// }
+///
+/// fn should_pass_2() -> googletest::Result<()> {
+///    verify_that!(100, result_of_ref!(|value| value + 1, eq(&101)))?; // Passes
+///    Ok(())
+/// }
+///
+/// fn should_fail() -> googletest::Result<()> {
+///    verify_that!("world", result_of_ref!(|s: &str| s.to_uppercase(), eq("HELLO")))?; // Passes
+///    Ok(())
+/// }
+/// should_pass_1().unwrap();
+/// should_pass_2().unwrap();
+/// should_fail().unwrap_err();
+/// ```
+#[macro_export]
+macro_rules! __result_of_ref {
+    ($function: expr, $matcher: expr) => {{
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::result_of_ref(
+            $function,
+            $matcher,
+            stringify!($function),
+        )
+    }};
+}
+
+/// Items for use only by the declarative macros in this module.
+///
+/// **For internal use only. API stability is not guaranteed!**
+#[doc(hidden)]
+pub mod internal {
+    use crate::description::Description;
+    use crate::matcher::{Matcher, MatcherBase, MatcherResult};
+    use std::fmt::Debug;
+
+    pub fn result_of<Callable, InnerMatcher>(
+        callable: Callable,
+        inner_matcher: InnerMatcher,
+        callable_description: &'static str,
+    ) -> ResultOfMatcher<Callable, InnerMatcher> {
+        ResultOfMatcher { callable, inner_matcher, callable_description }
+    }
+
+    #[derive(MatcherBase)]
+    pub struct ResultOfMatcher<Callable, InnerMatcher> {
+        callable: Callable,
+        inner_matcher: InnerMatcher,
+        callable_description: &'static str,
+    }
+
+    impl<I: Copy + Debug, T: Debug + Copy, CallableT: Fn(I) -> T, InnerMatcherT: Matcher<T>>
+        Matcher<I> for ResultOfMatcher<CallableT, InnerMatcherT>
+    {
+        fn matches(&self, actual: I) -> MatcherResult {
+            self.inner_matcher.matches((self.callable)(actual))
+        }
+
+        fn describe(&self, matcher_result: MatcherResult) -> Description {
+            Description::new()
+                .text(format!("by applying {},", self.callable_description))
+                .nested(self.inner_matcher.describe(matcher_result))
+        }
+
+        fn explain_match(&self, actual: I) -> Description {
+            let actual_result = (self.callable)(actual);
+            Description::new()
+                .text(format!("which, results into {actual_result:?}",))
+                .nested(self.describe(self.matches(actual)))
+        }
+    }
+
+    pub fn result_of_ref<Callable, InnerMatcher>(
+        callable: Callable,
+        inner_matcher: InnerMatcher,
+        callable_description: &'static str,
+    ) -> ResultOfRefMatcher<Callable, InnerMatcher> {
+        ResultOfRefMatcher { callable, inner_matcher, callable_description }
+    }
+    #[derive(MatcherBase)]
+    pub struct ResultOfRefMatcher<Callable, InnerMatcher> {
+        callable: Callable,
+        inner_matcher: InnerMatcher,
+        callable_description: &'static str,
+    }
+
+    impl<
+            I: Copy + Debug,
+            T: Debug,
+            Callable: Fn(I) -> T,
+            InnerMatcherT: for<'a> Matcher<&'a T>,
+        > Matcher<I> for ResultOfRefMatcher<Callable, InnerMatcherT>
+    {
+        fn matches(&self, actual: I) -> MatcherResult {
+            self.inner_matcher.matches(&(self.callable)(actual))
+        }
+
+        fn describe(&self, matcher_result: MatcherResult) -> Description {
+            Description::new()
+                .text(format!("by applying {},", self.callable_description))
+                .nested(self.inner_matcher.describe(matcher_result))
+        }
+
+        fn explain_match(&self, actual: I) -> Description {
+            let actual_result = (self.callable)(actual);
+            Description::new()
+                .text(format!("which, results into {actual_result:?}",))
+                .nested(self.describe(self.matches(actual)))
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::prelude::*;
+    use indoc::indoc;
+
+    #[test]
+    fn result_of_match_with_value() -> Result<()> {
+        verify_that!(1, result_of!(|value| value + 1, eq(2)))
+    }
+
+    #[test]
+    fn result_of_match_with_value_function() -> Result<()> {
+        fn inc_by_one(value: i32) -> i32 {
+            value + 1
+        }
+        verify_that!(1, result_of!(inc_by_one, eq(2)))
+    }
+
+    #[test]
+    fn result_of_match_with_different_value() -> Result<()> {
+        let result = verify_that!(0, result_of!(|value| value - 1, eq(2)));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                "
+                Value of: 0
+                Expected: by applying |value| value - 1,
+                  is equal to 2
+                Actual: 0,
+                  which, results into -1
+                    by applying |value| value - 1,
+                      isn't equal to 2
+                "
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_match_with_different_value_block_closure() -> Result<()> {
+        let result = verify_that!(0, result_of!(|value| { value - 1 }, eq(2)));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                "
+                Value of: 0
+                Expected: by applying |value| { value - 1 },
+                  is equal to 2
+                Actual: 0,
+                  which, results into -1
+                    by applying |value| { value - 1 },
+                      isn't equal to 2
+                "
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_match_with_different_value_multiline_closure() -> Result<()> {
+        let result = verify_that!(
+            0,
+            result_of!(
+                |value| {
+                    let dec = value - 1;
+                    let inc = dec + 1;
+                    inc - 2
+                },
+                eq(2)
+            )
+        );
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                "
+                Value of: 0
+                Expected: by applying |value| { let dec = value - 1; let inc = dec + 1; inc - 2 },
+                  is equal to 2
+                Actual: 0,
+                  which, results into -2
+                    by applying |value| { let dec = value - 1; let inc = dec + 1; inc - 2 },
+                      isn't equal to 2
+                "
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_match_with_different_value_function() -> Result<()> {
+        fn dec_by_one(value: i32) -> i32 {
+            value - 1
+        }
+        let result = verify_that!(0, result_of!(dec_by_one, eq(2)));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                "
+                Value of: 0
+                Expected: by applying dec_by_one,
+                  is equal to 2
+                Actual: 0,
+                  which, results into -1
+                    by applying dec_by_one,
+                      isn't equal to 2
+                "
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_ref_match_with_string_reference() -> Result<()> {
+        verify_that!("hello", result_of_ref!(|s: &str| s.to_uppercase(), eq("HELLO")))
+    }
+
+    #[test]
+    fn result_of_ref_match_with_string_reference_function() -> Result<()> {
+        fn to_upper_case<S: AsRef<str>>(s: S) -> String {
+            s.as_ref().to_uppercase()
+        }
+        verify_that!("hello", result_of_ref!(to_upper_case, eq("HELLO")))
+    }
+
+    #[test]
+    fn result_of_ref_match_with_copy_types() -> Result<()> {
+        verify_that!(100, result_of_ref!(|value| value + 1, eq(&101)))
+    }
+
+    #[test]
+    fn result_of_ref_match_with_different_value() -> Result<()> {
+        let result = verify_that!("world", result_of_ref!(|s: &str| s.to_uppercase(), eq("HELLO")));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                r#"
+                Value of: "world"
+                Expected: by applying |s: &str| s.to_uppercase(),
+                  is equal to "HELLO"
+                Actual: "world",
+                  which, results into "WORLD"
+                    by applying |s: &str| s.to_uppercase(),
+                      isn't equal to "HELLO""#
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_ref_match_with_different_value_block_closure() -> Result<()> {
+        let result =
+            verify_that!("world", result_of_ref!(|s: &str| { s.to_uppercase() }, eq("HELLO")));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                r#"
+            Value of: "world"
+            Expected: by applying |s: &str| { s.to_uppercase() },
+              is equal to "HELLO"
+            Actual: "world",
+              which, results into "WORLD"
+                by applying |s: &str| { s.to_uppercase() },
+                  isn't equal to "HELLO"
+            "#
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_ref_match_with_different_value_function() -> Result<()> {
+        fn to_upper_case<S: AsRef<str>>(s: S) -> String {
+            s.as_ref().to_uppercase()
+        }
+        let result = verify_that!("world", result_of_ref!(to_upper_case, eq("HELLO")));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                r#"
+            Value of: "world"
+            Expected: by applying to_upper_case,
+              is equal to "HELLO"
+            Actual: "world",
+              which, results into "WORLD"
+                by applying to_upper_case,
+                  isn't equal to "HELLO"
+            "#
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_ref_match_different_with_closure_variable() -> Result<()> {
+        let to_upper_case = |s: &str| s.to_uppercase();
+        let result = verify_that!("world", result_of_ref!(to_upper_case, eq("HELLO")));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                r#"
+                Value of: "world"
+                Expected: by applying to_upper_case,
+                  is equal to "HELLO"
+                Actual: "world",
+                  which, results into "WORLD"
+                    by applying to_upper_case,
+                      isn't equal to "HELLO"
+            "#
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_ref_match_different_with_method_literal() -> Result<()> {
+        let result = verify_that!("world", result_of_ref!(str::to_uppercase, eq("HELLO")));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                r#"
+                Value of: "world"
+                Expected: by applying str::to_uppercase,
+                  is equal to "HELLO"
+                Actual: "world",
+                  which, results into "WORLD"
+                    by applying str::to_uppercase,
+                      isn't equal to "HELLO"
+            "#
+            ))))
+        )
+    }
+
+    #[test]
+    fn result_of_ref_match_different_with_function_return_closure() -> Result<()> {
+        fn upper_case() -> impl Fn(&str) -> String {
+            |s: &str| s.to_uppercase()
+        }
+        let result = verify_that!("world", result_of_ref!(upper_case(), eq("HELLO")));
+        verify_that!(
+            result,
+            err(displays_as(contains_substring(indoc!(
+                r#"
+            Value of: "world"
+            Expected: by applying upper_case(),
+              is equal to "HELLO"
+            Actual: "world",
+              which, results into "WORLD"
+                by applying upper_case(),
+                  isn't equal to "HELLO"
+            "#
+            ))))
+        )
+    }
+
+    #[test]
+    fn test_describe_simple() -> Result<()> {
+        let matcher = result_of!(|x| x + 1, eq(2));
+        let description = matcher.describe(matcher.matches(0));
+        verify_that!(
+            description,
+            displays_as(eq(indoc!(
+                r#"
+        by applying |x| x + 1,
+          isn't equal to 2"#
+            )))
+        )
+    }
+
+    #[test]
+    fn test_describe_complicated() -> Result<()> {
+        let matcher = result_of_ref!(
+            |s: &str| s.chars().collect::<Vec<_>>(),
+            each(predicate(char::is_ascii_alphabetic))
+        );
+        let description = matcher.describe(matcher.matches("A quick brown fox"));
+        verify_that!(
+            description,
+            displays_as(eq(indoc!(
+                r#"
+        by applying |s: &str| s.chars().collect::<Vec<_>>(),
+          contains no element that matches"#
+            )))
+        )
+    }
+}
diff --git a/crates/googletest/src/matchers/some_matcher.rs b/crates/googletest/src/matchers/some_matcher.rs
index 905aa17..8c926f9 100644
--- a/crates/googletest/src/matchers/some_matcher.rs
+++ b/crates/googletest/src/matchers/some_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches an `Option` containing a value matched by `inner`.
 ///
@@ -38,23 +38,51 @@
 /// # should_fail_1().unwrap_err();
 /// # should_fail_2().unwrap_err();
 /// ```
-pub fn some<T: Debug>(inner: impl Matcher<ActualT = T>) -> impl Matcher<ActualT = Option<T>> {
-    SomeMatcher { inner, phantom: Default::default() }
+pub fn some<Inner>(inner: Inner) -> SomeMatcher<Inner> {
+    SomeMatcher { inner }
 }
 
-struct SomeMatcher<T, InnerMatcherT> {
+#[derive(MatcherBase)]
+pub struct SomeMatcher<InnerMatcherT> {
     inner: InnerMatcherT,
-    phantom: PhantomData<T>,
 }
 
-impl<T: Debug, InnerMatcherT: Matcher<ActualT = T>> Matcher for SomeMatcher<T, InnerMatcherT> {
-    type ActualT = Option<T>;
+impl<T: Debug + Copy, InnerMatcherT: Matcher<T>> Matcher<Option<T>> for SomeMatcher<InnerMatcherT> {
+    fn matches(&self, actual: Option<T>) -> MatcherResult {
+        actual.map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
+    }
 
-    fn matches(&self, actual: &Option<T>) -> MatcherResult {
+    fn explain_match(&self, actual: Option<T>) -> Description {
+        match (self.matches(actual), actual) {
+            (_, Some(t)) => {
+                Description::new().text("which has a value").nested(self.inner.explain_match(t))
+            }
+            (_, None) => "which is None".into(),
+        }
+    }
+
+    fn describe(&self, matcher_result: MatcherResult) -> Description {
+        match matcher_result {
+            MatcherResult::Match => {
+                format!("has a value which {}", self.inner.describe(MatcherResult::Match)).into()
+            }
+            MatcherResult::NoMatch => format!(
+                "is None or has a value which {}",
+                self.inner.describe(MatcherResult::NoMatch)
+            )
+            .into(),
+        }
+    }
+}
+
+impl<'a, T: Debug, InnerMatcherT: Matcher<&'a T>> Matcher<&'a Option<T>>
+    for SomeMatcher<InnerMatcherT>
+{
+    fn matches(&self, actual: &'a Option<T>) -> MatcherResult {
         actual.as_ref().map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
     }
 
-    fn explain_match(&self, actual: &Option<T>) -> Description {
+    fn explain_match(&self, actual: &'a Option<T>) -> Description {
         match (self.matches(actual), actual) {
             (_, Some(t)) => {
                 Description::new().text("which has a value").nested(self.inner.explain_match(t))
@@ -79,8 +107,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::some;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
 
@@ -88,7 +115,7 @@
     fn some_matches_option_with_value() -> Result<()> {
         let matcher = some(eq(1));
 
-        let result = matcher.matches(&Some(1));
+        let result = matcher.matches(Some(1));
 
         verify_that!(result, eq(MatcherResult::Match))
     }
@@ -97,21 +124,36 @@
     fn some_does_not_match_option_with_wrong_value() -> Result<()> {
         let matcher = some(eq(1));
 
-        let result = matcher.matches(&Some(0));
+        let result = matcher.matches(Some(0));
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
     #[test]
     fn some_does_not_match_option_with_none() -> Result<()> {
-        let matcher = some(eq::<i32, _>(1));
+        let matcher = some(eq(1));
 
-        let result = matcher.matches(&None);
+        let result = matcher.matches(None::<i32>);
 
         verify_that!(result, eq(MatcherResult::NoMatch))
     }
 
     #[test]
+    fn some_matches_option_with_by_ref_value() -> Result<()> {
+        verify_that!(Some("123".to_string()), some(eq("123")))
+    }
+
+    #[test]
+    fn some_does_not_match_option_with_wrong_by_ref_value() -> Result<()> {
+        verify_that!(Some("321".to_string()), not(some(eq("123"))))
+    }
+
+    #[test]
+    fn some_does_not_match_option_with_by_ref_none() -> Result<()> {
+        verify_that!(None::<String>, not(some(eq("123"))))
+    }
+
+    #[test]
     fn some_full_error_message() -> Result<()> {
         let result = verify_that!(Some(2), some(eq(1)));
         verify_that!(
@@ -131,7 +173,7 @@
     #[test]
     fn some_describe_matches() -> Result<()> {
         verify_that!(
-            some(eq::<i32, _>(1)).describe(MatcherResult::Match),
+            Matcher::<Option<i32>>::describe(&some(eq(1)), MatcherResult::Match),
             displays_as(eq("has a value which is equal to 1"))
         )
     }
@@ -139,20 +181,36 @@
     #[test]
     fn some_describe_does_not_match() -> Result<()> {
         verify_that!(
-            some(eq::<i32, _>(1)).describe(MatcherResult::NoMatch),
+            Matcher::<Option<i32>>::describe(&some(eq(1)), MatcherResult::NoMatch),
             displays_as(eq("is None or has a value which isn't equal to 1"))
         )
     }
 
     #[test]
+    fn some_describe_matches_of_by_ref() -> Result<()> {
+        verify_that!(
+            Matcher::<Option<&String>>::describe(&some(eq("123")), MatcherResult::Match),
+            displays_as(eq("has a value which is equal to \"123\""))
+        )
+    }
+
+    #[test]
+    fn some_describe_does_not_match_of_by_ref() -> Result<()> {
+        verify_that!(
+            Matcher::<Option<&String>>::describe(&some(eq("123")), MatcherResult::NoMatch),
+            displays_as(eq("is None or has a value which isn't equal to \"123\""))
+        )
+    }
+
+    #[test]
     fn some_explain_match_with_none() -> Result<()> {
-        verify_that!(some(eq::<i32, _>(1)).explain_match(&None), displays_as(eq("which is None")))
+        verify_that!(some(eq(1)).explain_match(None::<i32>), displays_as(eq("which is None")))
     }
 
     #[test]
     fn some_explain_match_with_some_success() -> Result<()> {
         verify_that!(
-            some(eq(1)).explain_match(&Some(1)),
+            some(eq(1)).explain_match(Some(1)),
             displays_as(eq("which has a value\n  which is equal to 1"))
         )
     }
@@ -160,8 +218,32 @@
     #[test]
     fn some_explain_match_with_some_fail() -> Result<()> {
         verify_that!(
-            some(eq(1)).explain_match(&Some(2)),
+            some(eq(1)).explain_match(Some(2)),
             displays_as(eq("which has a value\n  which isn't equal to 1"))
         )
     }
+
+    #[test]
+    fn some_explain_match_with_none_by_ref() -> Result<()> {
+        verify_that!(
+            some(eq("123")).explain_match(&None::<String>),
+            displays_as(eq("which is None"))
+        )
+    }
+
+    #[test]
+    fn some_explain_match_with_some_success_by_ref() -> Result<()> {
+        verify_that!(
+            some(eq("123")).explain_match(&Some("123".to_string())),
+            displays_as(eq("which has a value\n  which is equal to \"123\""))
+        )
+    }
+
+    #[test]
+    fn some_explain_match_with_some_fail_by_ref() -> Result<()> {
+        verify_that!(
+            some(eq("123")).explain_match(&Some("321".to_string())),
+            displays_as(eq("which has a value\n  which isn't equal to \"123\""))
+        )
+    }
 }
diff --git a/crates/googletest/src/matchers/str_matcher.rs b/crates/googletest/src/matchers/str_matcher.rs
index b624d44..aa58d4c 100644
--- a/crates/googletest/src/matchers/str_matcher.rs
+++ b/crates/googletest/src/matchers/str_matcher.rs
@@ -14,16 +14,15 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
     matcher_support::{
         edit_distance,
         summarize_diff::{create_diff, create_diff_reversed},
     },
-    matchers::{eq_deref_of_matcher::EqDerefOfMatcher, eq_matcher::EqMatcher},
+    matchers::eq_matcher::EqMatcher,
 };
 use std::borrow::Cow;
 use std::fmt::Debug;
-use std::marker::PhantomData;
 use std::ops::Deref;
 
 /// Matches a string containing a given substring.
@@ -59,11 +58,10 @@
 /// > and expected values when matching strings while
 /// > [`ignoring_ascii_case`][StrMatcherConfigurator::ignoring_ascii_case] is
 /// > set.
-pub fn contains_substring<A: ?Sized, T>(expected: T) -> StrMatcher<A, T> {
+pub fn contains_substring<T>(expected: T) -> StrMatcher<T> {
     StrMatcher {
         configuration: Configuration { mode: MatchMode::Contains, ..Default::default() },
         expected,
-        phantom: Default::default(),
     }
 }
 
@@ -99,11 +97,10 @@
 ///
 /// See the [`StrMatcherConfigurator`] extension trait for more options on how
 /// the string is matched.
-pub fn starts_with<A: ?Sized, T>(expected: T) -> StrMatcher<A, T> {
+pub fn starts_with<T>(expected: T) -> StrMatcher<T> {
     StrMatcher {
         configuration: Configuration { mode: MatchMode::StartsWith, ..Default::default() },
         expected,
-        phantom: Default::default(),
     }
 }
 
@@ -139,11 +136,10 @@
 ///
 /// See the [`StrMatcherConfigurator`] extension trait for more options on how
 /// the string is matched.
-pub fn ends_with<A: ?Sized, T>(expected: T) -> StrMatcher<A, T> {
+pub fn ends_with<T>(expected: T) -> StrMatcher<T> {
     StrMatcher {
         configuration: Configuration { mode: MatchMode::EndsWith, ..Default::default() },
         expected,
-        phantom: Default::default(),
     }
 }
 
@@ -152,7 +148,7 @@
 /// Matchers which match against string values and, through configuration,
 /// specialise to [`StrMatcher`] implement this trait. That includes
 /// [`EqMatcher`] and [`StrMatcher`].
-pub trait StrMatcherConfigurator<ActualT: ?Sized, ExpectedT> {
+pub trait StrMatcherConfigurator<ExpectedT> {
     /// Configures the matcher to ignore any leading whitespace in either the
     /// actual or the expected value.
     ///
@@ -171,7 +167,7 @@
     /// When all other configuration options are left as the defaults, this is
     /// equivalent to invoking [`str::trim_start`] on both the expected and
     /// actual value.
-    fn ignoring_leading_whitespace(self) -> StrMatcher<ActualT, ExpectedT>;
+    fn ignoring_leading_whitespace(self) -> StrMatcher<ExpectedT>;
 
     /// Configures the matcher to ignore any trailing whitespace in either the
     /// actual or the expected value.
@@ -191,7 +187,7 @@
     /// When all other configuration options are left as the defaults, this is
     /// equivalent to invoking [`str::trim_end`] on both the expected and
     /// actual value.
-    fn ignoring_trailing_whitespace(self) -> StrMatcher<ActualT, ExpectedT>;
+    fn ignoring_trailing_whitespace(self) -> StrMatcher<ExpectedT>;
 
     /// Configures the matcher to ignore both leading and trailing whitespace in
     /// either the actual or the expected value.
@@ -215,7 +211,7 @@
     /// When all other configuration options are left as the defaults, this is
     /// equivalent to invoking [`str::trim`] on both the expected and actual
     /// value.
-    fn ignoring_outer_whitespace(self) -> StrMatcher<ActualT, ExpectedT>;
+    fn ignoring_outer_whitespace(self) -> StrMatcher<ExpectedT>;
 
     /// Configures the matcher to ignore ASCII case when comparing values.
     ///
@@ -237,7 +233,7 @@
     ///
     /// This is **not guaranteed** to match strings with differing upper/lower
     /// case characters outside of the codepoints 0-127 covered by ASCII.
-    fn ignoring_ascii_case(self) -> StrMatcher<ActualT, ExpectedT>;
+    fn ignoring_ascii_case(self) -> StrMatcher<ExpectedT>;
 
     /// Configures the matcher to match only strings which otherwise satisfy the
     /// conditions a number times matched by the matcher `times`.
@@ -272,10 +268,7 @@
     /// This is only meaningful when the matcher was constructed with
     /// [`contains_substring`]. This method will panic when it is used with any
     /// other matcher construction.
-    fn times(
-        self,
-        times: impl Matcher<ActualT = usize> + 'static,
-    ) -> StrMatcher<ActualT, ExpectedT>;
+    fn times(self, times: impl Matcher<usize> + 'static) -> StrMatcher<ExpectedT>;
 }
 
 /// A matcher which matches equality or containment of a string-like value in a
@@ -287,20 +280,18 @@
 ///  * [`contains_substring`],
 ///  * [`starts_with`],
 ///  * [`ends_with`].
-pub struct StrMatcher<ActualT: ?Sized, ExpectedT> {
+#[derive(MatcherBase)]
+pub struct StrMatcher<ExpectedT> {
     expected: ExpectedT,
     configuration: Configuration,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ExpectedT, ActualT> Matcher for StrMatcher<ActualT, ExpectedT>
+impl<ExpectedT, ActualT> Matcher<ActualT> for StrMatcher<ExpectedT>
 where
     ExpectedT: Deref<Target = str> + Debug,
-    ActualT: AsRef<str> + Debug + ?Sized,
+    ActualT: AsRef<str> + Debug + Copy,
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
+    fn matches(&self, actual: ActualT) -> MatcherResult {
         self.configuration.do_strings_match(self.expected.deref(), actual.as_ref()).into()
     }
 
@@ -308,15 +299,15 @@
         self.configuration.describe(matcher_result, self.expected.deref())
     }
 
-    fn explain_match(&self, actual: &ActualT) -> Description {
+    fn explain_match(&self, actual: ActualT) -> Description {
         self.configuration.explain_match(self.expected.deref(), actual.as_ref())
     }
 }
 
-impl<ActualT: ?Sized, ExpectedT, MatcherT: Into<StrMatcher<ActualT, ExpectedT>>>
-    StrMatcherConfigurator<ActualT, ExpectedT> for MatcherT
+impl<ExpectedT, MatcherT: Into<StrMatcher<ExpectedT>>> StrMatcherConfigurator<ExpectedT>
+    for MatcherT
 {
-    fn ignoring_leading_whitespace(self) -> StrMatcher<ActualT, ExpectedT> {
+    fn ignoring_leading_whitespace(self) -> StrMatcher<ExpectedT> {
         let existing = self.into();
         StrMatcher {
             configuration: existing.configuration.ignoring_leading_whitespace(),
@@ -324,7 +315,7 @@
         }
     }
 
-    fn ignoring_trailing_whitespace(self) -> StrMatcher<ActualT, ExpectedT> {
+    fn ignoring_trailing_whitespace(self) -> StrMatcher<ExpectedT> {
         let existing = self.into();
         StrMatcher {
             configuration: existing.configuration.ignoring_trailing_whitespace(),
@@ -332,20 +323,17 @@
         }
     }
 
-    fn ignoring_outer_whitespace(self) -> StrMatcher<ActualT, ExpectedT> {
+    fn ignoring_outer_whitespace(self) -> StrMatcher<ExpectedT> {
         let existing = self.into();
         StrMatcher { configuration: existing.configuration.ignoring_outer_whitespace(), ..existing }
     }
 
-    fn ignoring_ascii_case(self) -> StrMatcher<ActualT, ExpectedT> {
+    fn ignoring_ascii_case(self) -> StrMatcher<ExpectedT> {
         let existing = self.into();
         StrMatcher { configuration: existing.configuration.ignoring_ascii_case(), ..existing }
     }
 
-    fn times(
-        self,
-        times: impl Matcher<ActualT = usize> + 'static,
-    ) -> StrMatcher<ActualT, ExpectedT> {
+    fn times(self, times: impl Matcher<usize> + 'static) -> StrMatcher<ExpectedT> {
         let existing = self.into();
         if !matches!(existing.configuration.mode, MatchMode::Contains) {
             panic!("The times() configurator is only meaningful with contains_substring().");
@@ -354,25 +342,19 @@
     }
 }
 
-impl<A: ?Sized, T: Deref<Target = str>> From<EqMatcher<A, T>> for StrMatcher<A, T> {
-    fn from(value: EqMatcher<A, T>) -> Self {
+impl<T: Deref<Target = str>> From<EqMatcher<T>> for StrMatcher<T> {
+    fn from(value: EqMatcher<T>) -> Self {
         Self::with_default_config(value.expected)
     }
 }
 
-impl<A: ?Sized, T: Deref<Target = str>> From<EqDerefOfMatcher<A, T>> for StrMatcher<A, T> {
-    fn from(value: EqDerefOfMatcher<A, T>) -> Self {
-        Self::with_default_config(value.expected)
-    }
-}
-
-impl<A: ?Sized, T> StrMatcher<A, T> {
+impl<T> StrMatcher<T> {
     /// Returns a [`StrMatcher`] with a default configuration to match against
     /// the given expected value.
     ///
     /// This default configuration is sensitive to whitespace and case.
     fn with_default_config(expected: T) -> Self {
-        Self { expected, configuration: Default::default(), phantom: Default::default() }
+        Self { expected, configuration: Default::default() }
     }
 }
 
@@ -387,7 +369,7 @@
     ignore_leading_whitespace: bool,
     ignore_trailing_whitespace: bool,
     case_policy: CasePolicy,
-    times: Option<Box<dyn Matcher<ActualT = usize>>>,
+    times: Option<Box<dyn Matcher<usize>>>,
 }
 
 #[derive(Clone)]
@@ -461,13 +443,13 @@
             // Split returns an iterator over the "boundaries" left and right of the
             // substring to be matched, of which there is one more than the number of
             // substrings.
-            matches!(times.matches(&(actual.split(expected).count() - 1)), MatcherResult::Match)
+            matches!(times.matches(actual.split(expected).count() - 1), MatcherResult::Match)
         } else {
             actual.contains(expected)
         }
     }
 
-    // StrMatcher::describe redirects immediately to this function.
+    // StrMatcher::<str>::describe redirects immediately to this function.
     fn describe(&self, matcher_result: MatcherResult, expected: &str) -> Description {
         let mut addenda: Vec<Cow<'static, str>> = Vec::with_capacity(3);
         match (self.ignore_leading_whitespace, self.ignore_trailing_whitespace) {
@@ -551,7 +533,11 @@
             MatchMode::EndsWith => create_diff_reversed(actual, expected, self.mode.to_diff_mode()),
         };
 
-        format!("{default_explanation}\n{diff}").into()
+        if diff.is_empty() {
+            format!("{default_explanation}").into()
+        } else {
+            format!("{default_explanation}\n\n{diff}").into()
+        }
     }
 
     fn ignoring_leading_whitespace(self) -> Self {
@@ -570,7 +556,7 @@
         Self { case_policy: CasePolicy::IgnoreAscii, ..self }
     }
 
-    fn times(self, times: impl Matcher<ActualT = usize> + 'static) -> Self {
+    fn times(self, times: impl Matcher<usize> + 'static) -> Self {
         Self { times: Some(Box::new(times)), ..self }
     }
 }
@@ -589,8 +575,7 @@
 
 #[cfg(test)]
 mod tests {
-    use super::{contains_substring, ends_with, starts_with, StrMatcher, StrMatcherConfigurator};
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
 
@@ -713,23 +698,13 @@
     }
 
     #[test]
-    fn allows_ignoring_ascii_case_from_eq_deref_of_str_slice() -> Result<()> {
-        verify_that!("A string", eq_deref_of("A STRING").ignoring_ascii_case())
-    }
-
-    #[test]
-    fn allows_ignoring_ascii_case_from_eq_deref_of_owned_string() -> Result<()> {
-        verify_that!("A string", eq_deref_of("A STRING".to_string()).ignoring_ascii_case())
-    }
-
-    #[test]
     fn matches_string_containing_expected_value_in_contains_mode() -> Result<()> {
         verify_that!("Some string", contains_substring("str"))
     }
 
     #[test]
-    fn matches_string_containing_expected_value_in_contains_mode_while_ignoring_ascii_case()
-    -> Result<()> {
+    fn matches_string_containing_expected_value_in_contains_mode_while_ignoring_ascii_case(
+    ) -> Result<()> {
         verify_that!("Some string", contains_substring("STR").ignoring_ascii_case())
     }
 
@@ -810,48 +785,45 @@
 
     #[test]
     fn describes_itself_for_matching_result() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = StrMatcher::with_default_config("A string");
+        let matcher = StrMatcher::with_default_config("A string");
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("is equal to \"A string\""))
         )
     }
 
     #[test]
     fn describes_itself_for_non_matching_result() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = StrMatcher::with_default_config("A string");
+        let matcher = StrMatcher::with_default_config("A string");
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::NoMatch),
+            Matcher::<&str>::describe(&matcher, MatcherResult::NoMatch),
             displays_as(eq("isn't equal to \"A string\""))
         )
     }
 
     #[test]
     fn describes_itself_for_matching_result_ignoring_leading_whitespace() -> Result<()> {
-        let matcher: StrMatcher<&str, _> =
-            StrMatcher::with_default_config("A string").ignoring_leading_whitespace();
+        let matcher = StrMatcher::with_default_config("A string").ignoring_leading_whitespace();
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("is equal to \"A string\" (ignoring leading whitespace)"))
         )
     }
 
     #[test]
     fn describes_itself_for_non_matching_result_ignoring_leading_whitespace() -> Result<()> {
-        let matcher: StrMatcher<&str, _> =
-            StrMatcher::with_default_config("A string").ignoring_leading_whitespace();
+        let matcher = StrMatcher::with_default_config("A string").ignoring_leading_whitespace();
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::NoMatch),
+            Matcher::<&str>::describe(&matcher, MatcherResult::NoMatch),
             displays_as(eq("isn't equal to \"A string\" (ignoring leading whitespace)"))
         )
     }
 
     #[test]
     fn describes_itself_for_matching_result_ignoring_trailing_whitespace() -> Result<()> {
-        let matcher: StrMatcher<&str, _> =
-            StrMatcher::with_default_config("A string").ignoring_trailing_whitespace();
+        let matcher = StrMatcher::with_default_config("A string").ignoring_trailing_whitespace();
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("is equal to \"A string\" (ignoring trailing whitespace)"))
         )
     }
@@ -859,32 +831,30 @@
     #[test]
     fn describes_itself_for_matching_result_ignoring_leading_and_trailing_whitespace() -> Result<()>
     {
-        let matcher: StrMatcher<&str, _> =
-            StrMatcher::with_default_config("A string").ignoring_outer_whitespace();
+        let matcher = StrMatcher::with_default_config("A string").ignoring_outer_whitespace();
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("is equal to \"A string\" (ignoring leading and trailing whitespace)"))
         )
     }
 
     #[test]
     fn describes_itself_for_matching_result_ignoring_ascii_case() -> Result<()> {
-        let matcher: StrMatcher<&str, _> =
-            StrMatcher::with_default_config("A string").ignoring_ascii_case();
+        let matcher = StrMatcher::with_default_config("A string").ignoring_ascii_case();
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("is equal to \"A string\" (ignoring ASCII case)"))
         )
     }
 
     #[test]
-    fn describes_itself_for_matching_result_ignoring_ascii_case_and_leading_whitespace()
-    -> Result<()> {
-        let matcher: StrMatcher<&str, _> = StrMatcher::with_default_config("A string")
+    fn describes_itself_for_matching_result_ignoring_ascii_case_and_leading_whitespace(
+    ) -> Result<()> {
+        let matcher = StrMatcher::with_default_config("A string")
             .ignoring_leading_whitespace()
             .ignoring_ascii_case();
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq(
                 "is equal to \"A string\" (ignoring leading whitespace, ignoring ASCII case)"
             ))
@@ -893,63 +863,63 @@
 
     #[test]
     fn describes_itself_for_matching_result_in_contains_mode() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = contains_substring("A string");
+        let matcher = contains_substring("A string");
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("contains a substring \"A string\""))
         )
     }
 
     #[test]
     fn describes_itself_for_non_matching_result_in_contains_mode() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = contains_substring("A string");
+        let matcher = contains_substring("A string");
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::NoMatch),
+            Matcher::<&str>::describe(&matcher, MatcherResult::NoMatch),
             displays_as(eq("does not contain a substring \"A string\""))
         )
     }
 
     #[test]
     fn describes_itself_with_count_number() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = contains_substring("A string").times(gt(2));
+        let matcher = contains_substring("A string").times(gt(2));
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("contains a substring \"A string\" (count is greater than 2)"))
         )
     }
 
     #[test]
     fn describes_itself_for_matching_result_in_starts_with_mode() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = starts_with("A string");
+        let matcher = starts_with("A string");
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("starts with prefix \"A string\""))
         )
     }
 
     #[test]
     fn describes_itself_for_non_matching_result_in_starts_with_mode() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = starts_with("A string");
+        let matcher = starts_with("A string");
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::NoMatch),
+            Matcher::<&str>::describe(&matcher, MatcherResult::NoMatch),
             displays_as(eq("does not start with \"A string\""))
         )
     }
 
     #[test]
     fn describes_itself_for_matching_result_in_ends_with_mode() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = ends_with("A string");
+        let matcher = ends_with("A string");
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&str>::describe(&matcher, MatcherResult::Match),
             displays_as(eq("ends with suffix \"A string\""))
         )
     }
 
     #[test]
     fn describes_itself_for_non_matching_result_in_ends_with_mode() -> Result<()> {
-        let matcher: StrMatcher<&str, _> = ends_with("A string");
+        let matcher = ends_with("A string");
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::NoMatch),
+            Matcher::<&str>::describe(&matcher, MatcherResult::NoMatch),
             displays_as(eq("does not end with \"A string\""))
         )
     }
@@ -1019,8 +989,8 @@
     }
 
     #[test]
-    fn match_explanation_for_starts_with_includes_both_versions_of_differing_last_line()
-    -> Result<()> {
+    fn match_explanation_for_starts_with_includes_both_versions_of_differing_last_line(
+    ) -> Result<()> {
         let result = verify_that!(
             indoc!(
                 "
@@ -1121,8 +1091,8 @@
     }
 
     #[test]
-    fn match_explanation_for_contains_substring_shows_diff_when_first_and_last_line_are_incomplete()
-    -> Result<()> {
+    fn match_explanation_for_contains_substring_shows_diff_when_first_and_last_line_are_incomplete(
+    ) -> Result<()> {
         let result = verify_that!(
             indoc!(
                 "
diff --git a/crates/googletest/src/matchers/subset_of_matcher.rs b/crates/googletest/src/matchers/subset_of_matcher.rs
index 24c00d8..2beaf2d 100644
--- a/crates/googletest/src/matchers/subset_of_matcher.rs
+++ b/crates/googletest/src/matchers/subset_of_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a container all of whose items are in the given container
 /// `superset`.
@@ -24,23 +24,23 @@
 /// The element type `ElementT` must implement `PartialEq` to allow element
 /// comparison.
 ///
-/// `ActualT` and `ExpectedT` can each be any container a reference to which
+/// `ActualT` and `ExpectedT` can each be any container which
 /// implements `IntoIterator`. For instance, `T` can be a common container like
-/// `Vec` or arrays. They need not be the same container type.
+/// `&Vec` or arrays. They need not be the same container type.
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # use std::collections::HashSet;
 /// # fn should_pass_1() -> Result<()> {
 /// let value = vec![1, 2, 3];
-/// verify_that!(value, subset_of([1, 2, 3, 4]))?;  // Passes
+/// verify_that!(value, subset_of([&1, &2, &3, &4]))?;  // Passes
 /// let array_value = [1, 2, 3];
 /// verify_that!(array_value, subset_of([1, 2, 3, 4]))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail() -> Result<()> {
 /// # let value = vec![1, 2, 3];
-/// verify_that!(value, subset_of([1, 2]))?;  // Fails: 3 is not in the superset
+/// verify_that!(value, subset_of([&1, &2]))?;  // Fails: 3 is not in the superset
 /// #     Ok(())
 /// # }
 /// # should_pass_1().unwrap();
@@ -48,7 +48,7 @@
 ///
 /// # fn should_pass_2() -> Result<()> {
 /// let value: HashSet<i32> = [1, 2, 3].into();
-/// verify_that!(value, subset_of([1, 2, 3]))?;  // Passes
+/// verify_that!(value, subset_of([&1, &2, &3]))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # should_pass_2().unwrap();
@@ -60,20 +60,8 @@
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
 /// let value: Vec<i32> = vec![0, 0, 1];
-/// verify_that!(value, subset_of([0, 1]))?;  // Passes
-/// verify_that!(value, subset_of([0, 1, 1]))?;  // Passes
-/// #     Ok(())
-/// # }
-/// # should_pass().unwrap();
-/// ```
-///
-/// One can also verify the contents of a slice by dereferencing it:
-///
-/// ```
-/// # use googletest::prelude::*;
-/// # fn should_pass() -> Result<()> {
-/// let value = &[1, 2, 3];
-/// verify_that!(*value, subset_of([1, 2, 3]))?;
+/// verify_that!(value, subset_of([&0, &1]))?;  // Passes
+/// verify_that!(value, subset_of([&0, &1, &1]))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -83,43 +71,35 @@
 /// runtime proportional to the *product* of the sizes of the actual and
 /// expected containers as well as the time to check equality of each pair of
 /// items. It should not be used on especially large containers.
-pub fn subset_of<ElementT: Debug + PartialEq, ActualT: Debug + ?Sized, ExpectedT: Debug>(
-    superset: ExpectedT,
-) -> impl Matcher<ActualT = ActualT>
-where
-    for<'a> &'a ActualT: IntoIterator<Item = &'a ElementT>,
-    for<'a> &'a ExpectedT: IntoIterator<Item = &'a ElementT>,
-{
-    SubsetOfMatcher::<ActualT, _> { superset, phantom: Default::default() }
+pub fn subset_of<ExpectedT>(superset: ExpectedT) -> SubsetOfMatcher<ExpectedT> {
+    SubsetOfMatcher { superset }
 }
 
-struct SubsetOfMatcher<ActualT: ?Sized, ExpectedT> {
+#[derive(MatcherBase)]
+pub struct SubsetOfMatcher<ExpectedT> {
     superset: ExpectedT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ElementT: Debug + PartialEq, ActualT: Debug + ?Sized, ExpectedT: Debug> Matcher
-    for SubsetOfMatcher<ActualT, ExpectedT>
+impl<ElementT: Debug + PartialEq + Copy, ActualT: Debug + Copy, ExpectedT: Debug> Matcher<ActualT>
+    for SubsetOfMatcher<ExpectedT>
 where
-    for<'a> &'a ActualT: IntoIterator<Item = &'a ElementT>,
+    ActualT: IntoIterator<Item = ElementT>,
     for<'a> &'a ExpectedT: IntoIterator<Item = &'a ElementT>,
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
+    fn matches(&self, actual: ActualT) -> MatcherResult {
         for actual_item in actual {
-            if self.expected_is_missing(actual_item) {
+            if self.expected_is_missing(&actual_item) {
                 return MatcherResult::NoMatch;
             }
         }
         MatcherResult::Match
     }
 
-    fn explain_match(&self, actual: &ActualT) -> Description {
+    fn explain_match(&self, actual: ActualT) -> Description {
         let unexpected_elements = actual
             .into_iter()
             .enumerate()
-            .filter(|&(_, actual_item)| self.expected_is_missing(actual_item))
+            .filter(|item| self.expected_is_missing(&item.1))
             .map(|(idx, actual_item)| format!("{actual_item:#?} at #{idx}"))
             .collect::<Vec<_>>();
 
@@ -138,18 +118,17 @@
     }
 }
 
-impl<ActualT: ?Sized, ElementT: PartialEq, ExpectedT> SubsetOfMatcher<ActualT, ExpectedT>
+impl<ElementT: PartialEq, ExpectedT> SubsetOfMatcher<ExpectedT>
 where
     for<'a> &'a ExpectedT: IntoIterator<Item = &'a ElementT>,
 {
     fn expected_is_missing(&self, needle: &ElementT) -> bool {
-        !self.superset.into_iter().any(|item| *item == *needle)
+        !self.superset.into_iter().any(|item| item == needle)
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use super::subset_of;
     use crate::prelude::*;
     use indoc::indoc;
     use std::collections::HashSet;
@@ -163,54 +142,54 @@
     #[test]
     fn subset_of_matches_vec_with_one_element() -> Result<()> {
         let value = vec![1];
-        verify_that!(value, subset_of([1]))
+        verify_that!(value, subset_of([&1]))
     }
 
     #[test]
     fn subset_of_matches_vec_with_two_elements() -> Result<()> {
         let value = vec![1, 2];
-        verify_that!(value, subset_of([1, 2]))
+        verify_that!(value, subset_of([&1, &2]))
     }
 
     #[test]
     fn subset_of_matches_vec_when_expected_has_excess_element() -> Result<()> {
         let value = vec![1, 2];
-        verify_that!(value, subset_of([1, 2, 3]))
+        verify_that!(value, subset_of([&1, &2, &3]))
     }
 
     #[test]
     fn subset_of_matches_vec_when_expected_has_excess_element_first() -> Result<()> {
         let value = vec![1, 2];
-        verify_that!(value, subset_of([3, 1, 2]))
+        verify_that!(value, subset_of([&3, &1, &2]))
     }
 
     #[test]
     fn subset_of_matches_slice_with_one_element() -> Result<()> {
         let value = &[1];
-        verify_that!(*value, subset_of([1]))
+        verify_that!(value, subset_of([&1]))
     }
 
     #[test]
     fn subset_of_matches_hash_set_with_one_element() -> Result<()> {
         let value: HashSet<i32> = [1].into();
-        verify_that!(value, subset_of([1]))
+        verify_that!(value, subset_of([&1]))
     }
 
     #[test]
     fn subset_of_does_not_match_when_first_element_does_not_match() -> Result<()> {
         let value = vec![0];
-        verify_that!(value, not(subset_of([1])))
+        verify_that!(value, not(subset_of([&1])))
     }
 
     #[test]
     fn subset_of_does_not_match_when_second_element_does_not_match() -> Result<()> {
         let value = vec![2, 0];
-        verify_that!(value, not(subset_of([2])))
+        verify_that!(value, not(subset_of([&2])))
     }
 
     #[test]
     fn subset_of_shows_correct_message_when_first_item_does_not_match() -> Result<()> {
-        let result = verify_that!(vec![0, 2, 3], subset_of([1, 2, 3]));
+        let result = verify_that!(vec![0, 2, 3], subset_of([&1, &2, &3]));
 
         verify_that!(
             result,
@@ -231,7 +210,7 @@
 
     #[test]
     fn subset_of_shows_correct_message_when_second_item_does_not_match() -> Result<()> {
-        let result = verify_that!(vec![1, 0, 3], subset_of([1, 2, 3]));
+        let result = verify_that!(vec![1, 0, 3], subset_of([&1, &2, &3]));
 
         verify_that!(
             result,
@@ -252,7 +231,7 @@
 
     #[test]
     fn subset_of_shows_correct_message_when_first_two_items_do_not_match() -> Result<()> {
-        let result = verify_that!(vec![0, 0, 3], subset_of([1, 2, 3]));
+        let result = verify_that!(vec![0, 0, 3], subset_of([&1, &2, &3]));
 
         verify_that!(
             result,
diff --git a/crates/googletest/src/matchers/superset_of_matcher.rs b/crates/googletest/src/matchers/superset_of_matcher.rs
index d1e9d72..8d28e45 100644
--- a/crates/googletest/src/matchers/superset_of_matcher.rs
+++ b/crates/googletest/src/matchers/superset_of_matcher.rs
@@ -14,9 +14,9 @@
 
 use crate::{
     description::Description,
-    matcher::{Matcher, MatcherResult},
+    matcher::{Matcher, MatcherBase, MatcherResult},
 };
-use std::{fmt::Debug, marker::PhantomData};
+use std::fmt::Debug;
 
 /// Matches a container containing all of the items in the given container
 /// `subset`.
@@ -24,24 +24,24 @@
 /// The element type `ElementT` must implement `PartialEq` to allow element
 /// comparison.
 ///
-/// `ActualT` and `ExpectedT` can each be any container a reference to which
-/// implements `IntoIterator`. For instance, `ActualT` and `ExpectedT` can be a
-/// common container like `Vec` or arrays. They need not be the same container
-/// type.
+/// `ActualT` and `ExpectedT` can each be any container which implements
+/// `IntoIterator`. For instance, `ActualT` and `ExpectedT` can be a
+/// common container like `&Vec`, arrays or slices. They need not be the same
+/// container type.
 ///
 /// ```
 /// # use googletest::prelude::*;
 /// # use std::collections::HashSet;
 /// # fn should_pass_1() -> Result<()> {
 /// let value = vec![1, 2, 3];
-/// verify_that!(value, superset_of([1, 2]))?;  // Passes
+/// verify_that!(value, superset_of([&1, &2]))?;  // Passes
 /// let array_value = [1, 2, 3];
 /// verify_that!(array_value, superset_of([1, 2]))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail() -> Result<()> {
 /// # let value = vec![1, 2, 3];
-/// verify_that!(value, superset_of([1, 2, 4]))?;  // Fails: 4 is not in the subset
+/// verify_that!(value, superset_of([&1, &2, &4]))?;  // Fails: 4 is not in the subset
 /// #     Ok(())
 /// # }
 /// # should_pass_1().unwrap();
@@ -49,7 +49,7 @@
 ///
 /// # fn should_pass_2() -> Result<()> {
 /// let value: HashSet<i32> = [1, 2, 3].into();
-/// verify_that!(value, superset_of([1, 2, 3]))?;  // Passes
+/// verify_that!(value, superset_of([&1, &2, &3]))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # should_pass_2().unwrap();
@@ -61,20 +61,8 @@
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
 /// let value: Vec<i32> = vec![0, 0, 1];
-/// verify_that!(value, superset_of([0, 1]))?;  // Passes
-/// verify_that!(value, superset_of([0, 1, 1]))?;  // Passes
-/// #     Ok(())
-/// # }
-/// # should_pass().unwrap();
-/// ```
-///
-/// One can also verify the contents of a slice by dereferencing it:
-///
-/// ```
-/// # use googletest::prelude::*;
-/// # fn should_pass() -> Result<()> {
-/// let value = &[1, 2, 3];
-/// verify_that!(*value, superset_of([1, 2, 3]))?;
+/// verify_that!(value, superset_of([&0, &1]))?;  // Passes
+/// verify_that!(value, superset_of([&0, &1, &1]))?;  // Passes
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -84,30 +72,22 @@
 /// runtime proportional to the *product* of the sizes of the actual and
 /// expected containers as well as the time to check equality of each pair of
 /// items. It should not be used on especially large containers.
-pub fn superset_of<ElementT: Debug + PartialEq, ActualT: Debug + ?Sized, ExpectedT: Debug>(
-    subset: ExpectedT,
-) -> impl Matcher<ActualT = ActualT>
-where
-    for<'a> &'a ActualT: IntoIterator<Item = &'a ElementT>,
-    for<'a> &'a ExpectedT: IntoIterator<Item = &'a ElementT>,
-{
-    SupersetOfMatcher::<ActualT, _> { subset, phantom: Default::default() }
+pub fn superset_of<ExpectedT>(subset: ExpectedT) -> SupersetOfMatcher<ExpectedT> {
+    SupersetOfMatcher { subset }
 }
 
-struct SupersetOfMatcher<ActualT: ?Sized, ExpectedT> {
+#[derive(MatcherBase)]
+pub struct SupersetOfMatcher<ExpectedT> {
     subset: ExpectedT,
-    phantom: PhantomData<ActualT>,
 }
 
-impl<ElementT: Debug + PartialEq, ActualT: Debug + ?Sized, ExpectedT: Debug> Matcher
-    for SupersetOfMatcher<ActualT, ExpectedT>
+impl<ElementT: Debug + Copy + PartialEq, ActualT: Debug + Copy, ExpectedT: Debug> Matcher<ActualT>
+    for SupersetOfMatcher<ExpectedT>
 where
-    for<'a> &'a ActualT: IntoIterator<Item = &'a ElementT>,
+    ActualT: IntoIterator<Item = ElementT>,
     for<'a> &'a ExpectedT: IntoIterator<Item = &'a ElementT>,
 {
-    type ActualT = ActualT;
-
-    fn matches(&self, actual: &ActualT) -> MatcherResult {
+    fn matches(&self, actual: ActualT) -> MatcherResult {
         for expected_item in &self.subset {
             if actual_is_missing(actual, expected_item) {
                 return MatcherResult::NoMatch;
@@ -116,11 +96,11 @@
         MatcherResult::Match
     }
 
-    fn explain_match(&self, actual: &ActualT) -> Description {
+    fn explain_match(&self, actual: ActualT) -> Description {
         let missing_items: Vec<_> = self
             .subset
             .into_iter()
-            .filter(|expected_item| actual_is_missing(actual, expected_item))
+            .filter(|expected_item| actual_is_missing(actual, *expected_item))
             .map(|expected_item| format!("{expected_item:#?}"))
             .collect();
         match missing_items.len() {
@@ -138,19 +118,14 @@
     }
 }
 
-fn actual_is_missing<ElementT: PartialEq, ActualT: ?Sized>(
-    actual: &ActualT,
-    needle: &ElementT,
-) -> bool
+fn actual_is_missing<ElementT: PartialEq, ActualT>(actual: ActualT, needle: &ElementT) -> bool
 where
-    for<'a> &'a ActualT: IntoIterator<Item = &'a ElementT>,
+    ActualT: IntoIterator<Item = ElementT>,
 {
-    !actual.into_iter().any(|item| *item == *needle)
+    !actual.into_iter().any(|item| &item == needle)
 }
-
 #[cfg(test)]
 mod tests {
-    use super::superset_of;
     use crate::prelude::*;
     use indoc::indoc;
     use std::collections::HashSet;
@@ -164,54 +139,54 @@
     #[test]
     fn superset_of_matches_vec_with_one_element() -> Result<()> {
         let value = vec![1];
-        verify_that!(value, superset_of([1]))
+        verify_that!(value, superset_of([&1]))
     }
 
     #[test]
     fn superset_of_matches_vec_with_two_items() -> Result<()> {
         let value = vec![1, 2];
-        verify_that!(value, superset_of([1, 2]))
+        verify_that!(value, superset_of([&1, &2]))
     }
 
     #[test]
     fn superset_of_matches_vec_when_actual_has_excess_element() -> Result<()> {
         let value = vec![1, 2, 3];
-        verify_that!(value, superset_of([1, 2]))
+        verify_that!(value, superset_of([&1, &2]))
     }
 
     #[test]
     fn superset_of_matches_vec_when_actual_has_excess_element_first() -> Result<()> {
         let value = vec![3, 1, 2];
-        verify_that!(value, superset_of([1, 2]))
+        verify_that!(value, superset_of([&1, &2]))
     }
 
     #[test]
     fn superset_of_matches_slice_with_one_element() -> Result<()> {
         let value = &[1];
-        verify_that!(*value, superset_of([1]))
+        verify_that!(value, superset_of([&1]))
     }
 
     #[test]
     fn superset_of_matches_hash_set_with_one_element() -> Result<()> {
         let value: HashSet<i32> = [1].into();
-        verify_that!(value, superset_of([1]))
+        verify_that!(value, superset_of([&1]))
     }
 
     #[test]
     fn superset_of_does_not_match_when_first_element_does_not_match() -> Result<()> {
         let value = vec![0];
-        verify_that!(value, not(superset_of([1])))
+        verify_that!(value, not(superset_of([&1])))
     }
 
     #[test]
     fn superset_of_does_not_match_when_second_element_does_not_match() -> Result<()> {
         let value = vec![2];
-        verify_that!(value, not(superset_of([2, 0])))
+        verify_that!(value, not(superset_of([&2, &0])))
     }
 
     #[test]
     fn superset_of_shows_correct_message_when_first_item_does_not_match() -> Result<()> {
-        let result = verify_that!(vec![0, 2, 3], superset_of([1, 2, 3]));
+        let result = verify_that!(vec![0, 2, 3], superset_of([&1, &2, &3]));
 
         verify_that!(
             result,
@@ -232,7 +207,7 @@
 
     #[test]
     fn superset_of_shows_correct_message_when_second_item_does_not_match() -> Result<()> {
-        let result = verify_that!(vec![1, 0, 3], superset_of([1, 2, 3]));
+        let result = verify_that!(vec![1, 0, 3], superset_of([&1, &2, &3]));
 
         verify_that!(
             result,
@@ -253,7 +228,7 @@
 
     #[test]
     fn superset_of_shows_correct_message_when_first_two_items_do_not_match() -> Result<()> {
-        let result = verify_that!(vec![0, 0, 3], superset_of([1, 2, 3]));
+        let result = verify_that!(vec![0, 0, 3], superset_of([&1, &2, &3]));
 
         verify_that!(
             result,
diff --git a/crates/googletest/src/matchers/tuple_matcher.rs b/crates/googletest/src/matchers/tuple_matcher.rs
index af55cbf..4822d52 100644
--- a/crates/googletest/src/matchers/tuple_matcher.rs
+++ b/crates/googletest/src/matchers/tuple_matcher.rs
@@ -23,16 +23,16 @@
 pub mod internal {
     use crate::{
         description::Description,
-        matcher::{Matcher, MatcherResult},
+        matcher::{Matcher, MatcherBase, MatcherResult},
     };
     use std::fmt::Debug;
 
+    impl MatcherBase for () {}
+
     // This implementation is provided for completeness, but is completely trivial.
     // The only actual value which can be supplied is (), which must match.
-    impl Matcher for () {
-        type ActualT = ();
-
-        fn matches(&self, _: &Self::ActualT) -> MatcherResult {
+    impl Matcher<()> for () {
+        fn matches(&self, _: ()) -> MatcherResult {
             MatcherResult::Match
         }
 
@@ -44,18 +44,75 @@
         }
     }
 
+    impl Matcher<&()> for () {
+        fn matches(&self, _: &()) -> MatcherResult {
+            MatcherResult::Match
+        }
+
+        fn describe(&self, matcher_result: MatcherResult) -> Description {
+            <Self as Matcher<()>>::describe(self, matcher_result)
+        }
+    }
+
     /// Generates a tuple matcher for tuples of a specific length.
     ///
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
     macro_rules! tuple_matcher_n {
         ($([$field_number:tt, $matcher_type:ident, $field_type:ident]),*) => {
-            impl<$($field_type: Debug, $matcher_type: Matcher<ActualT = $field_type>),*>
-                Matcher for ($($matcher_type,)*)
-            {
-                type ActualT = ($($field_type,)*);
+            impl<$($matcher_type: MatcherBase),*> MatcherBase for ($($matcher_type,)*){}
 
-                fn matches(&self, actual: &($($field_type,)*)) -> MatcherResult {
+            impl<$($field_type: Debug + Copy, $matcher_type: Matcher<$field_type>),*>
+                Matcher<($($field_type,)*)> for ($($matcher_type,)*)
+            {
+                fn matches(&self, actual:  ($($field_type,)*)) -> MatcherResult {
+                    $(match self.$field_number.matches(actual.$field_number) {
+                        MatcherResult::Match => {},
+                        MatcherResult::NoMatch => {
+                            return MatcherResult::NoMatch;
+                        }
+                    })*
+                    MatcherResult::Match
+                }
+
+                fn explain_match(&self, actual:  ($($field_type,)*)) -> Description  {
+                    let mut explanation = Description::new().text("which").nested(
+                        self.describe(self.matches(actual)));
+                    $(match self.$field_number.matches(actual.$field_number) {
+                        MatcherResult::Match => {},
+                        MatcherResult::NoMatch => {
+                            explanation = explanation
+                                .text(format!(concat!("Element #", $field_number, " is {:?},"),
+                                    actual.$field_number))
+                                .nested(self.$field_number.explain_match(actual.$field_number));
+                        }
+                    })*
+                    explanation
+                }
+
+                fn describe(&self, matcher_result: MatcherResult) -> Description {
+                    match matcher_result {
+                        MatcherResult::Match => {
+                            let mut description = Description::new().text(
+                                "is a tuple whose values respectively match:");
+                            $(description = description.nested(
+                                self.$field_number.describe(matcher_result));)*
+                            description
+                        }
+                        MatcherResult::NoMatch => {
+                            let mut description = Description::new().text(
+                                "is a tuple whose values do not respectively match:");
+                            $(description = description.nested(
+                                self.$field_number.describe(MatcherResult::Match));)*
+                            description
+                        }
+                    }
+                }
+            }
+            impl<'a, $($field_type: Debug, $matcher_type: Matcher<&'a $field_type>),*>
+                Matcher<&'a ($($field_type,)*)> for ($($matcher_type,)*)
+            {
+                fn matches(&self, actual:  &'a ($($field_type,)*)) -> MatcherResult {
                     $(match self.$field_number.matches(&actual.$field_number) {
                         MatcherResult::Match => {},
                         MatcherResult::NoMatch => {
@@ -65,13 +122,22 @@
                     MatcherResult::Match
                 }
 
-                fn explain_match(&self, actual: &($($field_type,)*)) -> Description {
-                    let mut explanation = Description::new().text("which").nested(self.describe(self.matches(actual)));
+                fn explain_match(&self, actual:  &'a ($($field_type,)*)) -> Description  {
+                    let mut explanation = Description::new()
+                        .text("which")
+                        .nested(
+                            Matcher::<&'a ($($field_type,)*)>::describe(
+                                self, self.matches(actual)));
                     $(match self.$field_number.matches(&actual.$field_number) {
                         MatcherResult::Match => {},
                         MatcherResult::NoMatch => {
                             explanation = explanation
-                                .text(format!(concat!("Element #", $field_number, " is {:?},"), actual.$field_number))
+                                .text(format!(
+                                    concat!(
+                                        "Element #",
+                                        $field_number,
+                                        " is {:?},"),
+                                        actual.$field_number))
                                 .nested(self.$field_number.explain_match(&actual.$field_number));
                         }
                     })*
@@ -81,13 +147,17 @@
                 fn describe(&self, matcher_result: MatcherResult) -> Description {
                     match matcher_result {
                         MatcherResult::Match => {
-                            let mut description = Description::new().text("is a tuple whose values respectively match:");
-                            $(description = description.nested(self.$field_number.describe(matcher_result));)*
+                            let mut description = Description::new().text(
+                                "is a tuple whose values respectively match:");
+                            $(description = description.nested(
+                                self.$field_number.describe(matcher_result));)*
                             description
                         }
                         MatcherResult::NoMatch => {
-                            let mut description = Description::new().text("is a tuple whose values do not respectively match:");
-                            $(description = description.nested(self.$field_number.describe(MatcherResult::Match));)*
+                            let mut description = Description::new().text(
+                                "is a tuple whose values do not respectively match:");
+                            $(description = description.nested(
+                                self.$field_number.describe(MatcherResult::Match));)*
                             description
                         }
                     }
diff --git a/crates/googletest/src/matchers/unordered_elements_are_matcher.rs b/crates/googletest/src/matchers/unordered_elements_are_matcher.rs
index f4585a4..50951d7 100644
--- a/crates/googletest/src/matchers/unordered_elements_are_matcher.rs
+++ b/crates/googletest/src/matchers/unordered_elements_are_matcher.rs
@@ -22,19 +22,19 @@
 /// ```
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(vec![3, 2, 1], unordered_elements_are![eq(1), ge(2), anything()])?;   // Passes
+/// verify_that!(vec![3, 2, 1], unordered_elements_are![eq(&1), ge(&2), anything()])?;   // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail_1() -> Result<()> {
-/// verify_that!(vec![1], unordered_elements_are![eq(1), ge(2)])?;              // Fails: container has wrong size
+/// verify_that!(vec![1], unordered_elements_are![eq(&1), ge(&2)])?;              // Fails: container has wrong size
 /// #     Ok(())
 /// # }
 /// # fn should_fail_2() -> Result<()> {
-/// verify_that!(vec![3, 2, 1], unordered_elements_are![eq(1), ge(4), eq(2)])?; // Fails: second matcher not matched
+/// verify_that!(vec![3, 2, 1], unordered_elements_are![eq(&1), ge(&4), eq(&2)])?; // Fails: second matcher not matched
 /// #     Ok(())
 /// # }
 /// # fn should_fail_3() -> Result<()> {
-/// verify_that!(vec![3, 2, 1], unordered_elements_are![ge(3), ge(3), ge(3)])?; // Fails: no 1:1 correspondence
+/// verify_that!(vec![3, 2, 1], unordered_elements_are![ge(&3), ge(&3), ge(&3)])?; // Fails: no 1:1 correspondence
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -43,32 +43,15 @@
 /// # should_fail_3().unwrap_err();
 /// ```
 ///
-/// The actual value must be a container such as a `Vec`, an array, or a
-/// dereferenced slice. More precisely, a shared borrow of the actual value must
-/// implement [`IntoIterator`].
-///
-/// This can also match against [`HashMap`][std::collections::HashMap] and
-/// similar collections. The arguments are a sequence of pairs of matchers
-/// corresponding to the keys and their respective values.
-///
-/// ```
-/// # use googletest::prelude::*;
-/// # use std::collections::HashMap;
-/// let value: HashMap<u32, &'static str> =
-///     HashMap::from_iter([(1, "One"), (2, "Two"), (3, "Three")]);
-/// verify_that!(
-///     value,
-///     unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))]
-/// )
-/// #     .unwrap();
-/// ```
+/// The actual value must be a container such as a `&Vec`, an array, or a
+/// slice. More precisely, the actual value must implement [`IntoIterator`].
 ///
 /// This can also be omitted in [`verify_that!`] macros and replaced with curly
 /// brackets.
 ///
 /// ```
 /// # use googletest::prelude::*;
-///  verify_that!(vec![1, 2], {eq(2), eq(1)})
+///  verify_that!(vec![1, 2], {eq(&2), eq(&1)})
 /// #     .unwrap();
 /// ```
 ///
@@ -86,12 +69,18 @@
 /// ```
 /// # use googletest::prelude::*;
 /// verify_that!(vec![vec![1,2], vec![3]],
-///   {unordered_elements_are![eq(2), eq(1)], unordered_elements_are![eq(3)]})
+///   {unordered_elements_are![eq(&2), eq(&1)], unordered_elements_are![eq(&3)]})
 /// # .unwrap();
 /// ```
 ///
-/// This matcher does not support matching directly against an [`Iterator`]. To
-/// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
+///  If an inner matcher is `eq(...)`, it can be omitted:
+///
+/// ```
+/// # use googletest::prelude::*;
+///
+/// verify_that!(vec![1,2,3], unordered_elements_are![lt(&2), gt(&1), &3])
+/// #     .unwrap();
+/// ```
 ///
 /// The matcher proceeds in three stages:
 ///
@@ -119,29 +108,23 @@
 #[doc(hidden)]
 macro_rules! __unordered_elements_are {
     ($(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsAreMatcher, Requirements
-        };
-        UnorderedElementsAreMatcher::new([], Requirements::PerfectMatch)
-    }};
-
-    // TODO: Consider an alternative map-like syntax here similar to that used in
-    // https://crates.io/crates/maplit.
-    ($(($key_matcher:expr, $value_matcher:expr)),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsOfMapAreMatcher, Requirements
-        };
-        UnorderedElementsOfMapAreMatcher::new(
-            [$((Box::new($key_matcher), Box::new($value_matcher))),*],
-            Requirements::PerfectMatch
-        )
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::
+        UnorderedElementsAreMatcher::new(
+            [],
+            $crate::matchers::__internal_unstable_do_not_depend_on_these::
+            Requirements::PerfectMatch)
     }};
 
     ($($matcher:expr),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsAreMatcher, Requirements
-        };
-        UnorderedElementsAreMatcher::new([$(Box::new($matcher)),*], Requirements::PerfectMatch)
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::
+        UnorderedElementsAreMatcher::new(
+            [$(Box::new(
+                $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!(
+                    $matcher
+                )
+            )),*],
+            $crate::matchers::__internal_unstable_do_not_depend_on_these::
+            Requirements::PerfectMatch)
     }};
 }
 
@@ -160,20 +143,20 @@
 /// ```
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(vec![3, 2, 1], contains_each![eq(2), ge(3)])?;   // Passes
-/// verify_that!(vec![3, 2, 1], contains_each![ge(2), ge(2)])?;   // Passes
+/// verify_that!(vec![3, 2, 1], contains_each![eq(&2), ge(&3)])?;   // Passes
+/// verify_that!(vec![3, 2, 1], contains_each![ge(&2), ge(&2)])?;   // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail_1() -> Result<()> {
-/// verify_that!(vec![1], contains_each![eq(1), ge(2)])?;         // Fails: container too small
+/// verify_that!(vec![1], contains_each![eq(&1), ge(&2)])?;         // Fails: container too small
 /// #     Ok(())
 /// # }
 /// # fn should_fail_2() -> Result<()> {
-/// verify_that!(vec![3, 2, 1], contains_each![eq(1), ge(4)])?;   // Fails: second matcher unmatched
+/// verify_that!(vec![3, 2, 1], contains_each![eq(&1), ge(&4)])?;   // Fails: second matcher unmatched
 /// #     Ok(())
 /// # }
 /// # fn should_fail_3() -> Result<()> {
-/// verify_that!(vec![3, 2, 1], contains_each![ge(3), ge(3), ge(3)])?; // Fails: no matching
+/// verify_that!(vec![3, 2, 1], contains_each![ge(&3), ge(&3), ge(&3)])?; // Fails: no matching
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -182,26 +165,18 @@
 /// # should_fail_3().unwrap_err();
 /// ```
 ///
-/// The actual value must be a container such as a `Vec`, an array, or a
-/// dereferenced slice. More precisely, a shared borrow of the actual value must
-/// implement [`IntoIterator`].
+/// The actual value must be a container such as a `&Vec`, an array, or a
+/// slice. More precisely, the actual value must implement [`IntoIterator`].
 ///
-/// This can also match against [`HashMap`][std::collections::HashMap] and
-/// similar collections. The arguments are a sequence of pairs of matchers
-/// corresponding to the keys and their respective values.
+///  If an inner matcher is `eq(...)`, it can be omitted:
 ///
 /// ```
 /// # use googletest::prelude::*;
-/// # use std::collections::HashMap;
-/// let value: HashMap<u32, &'static str> =
-///     HashMap::from_iter([(1, "One"), (2, "Two"), (3, "Three")]);
-/// verify_that!(value, contains_each![(eq(2), eq("Two")), (eq(1), eq("One"))])
+///
+/// verify_that!(vec![1,2,3], contains_each![lt(&2), &3])
 /// #     .unwrap();
 /// ```
 ///
-/// This matcher does not support matching directly against an [`Iterator`]. To
-/// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
-///
 /// The matcher proceeds in three stages:
 ///
 /// 1. It first checks whether the actual value is large enough to possibly be
@@ -225,29 +200,21 @@
 #[doc(hidden)]
 macro_rules! __contains_each {
     ($(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsAreMatcher, Requirements
-        };
-        UnorderedElementsAreMatcher::new([], Requirements::Superset)
-    }};
-
-    // TODO: Consider an alternative map-like syntax here similar to that used in
-    // https://crates.io/crates/maplit.
-    ($(($key_matcher:expr, $value_matcher:expr)),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsOfMapAreMatcher, Requirements
-        };
-        UnorderedElementsOfMapAreMatcher::new(
-            [$((Box::new($key_matcher), Box::new($value_matcher))),*],
-            Requirements::Superset
-        )
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::
+        UnorderedElementsAreMatcher::new(
+            [],
+            $crate::matchers::__internal_unstable_do_not_depend_on_these::Requirements::Superset)
     }};
 
     ($($matcher:expr),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsAreMatcher, Requirements
-        };
-        UnorderedElementsAreMatcher::new([$(Box::new($matcher)),*], Requirements::Superset)
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::
+        UnorderedElementsAreMatcher::new(
+            [$(Box::new(
+                $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!(
+                    $matcher
+                )
+            )),*],
+            $crate::matchers::__internal_unstable_do_not_depend_on_these::Requirements::Superset)
     }}
 }
 
@@ -267,20 +234,20 @@
 /// ```
 /// # use googletest::prelude::*;
 /// # fn should_pass() -> Result<()> {
-/// verify_that!(vec![2, 1], is_contained_in![eq(1), ge(2)])?;   // Passes
-/// verify_that!(vec![2, 1], is_contained_in![ge(1), ge(1)])?;   // Passes
+/// verify_that!(vec![2, 1], is_contained_in![eq(&1), ge(&2)])?;   // Passes
+/// verify_that!(vec![2, 1], is_contained_in![ge(&1), ge(&1)])?;   // Passes
 /// #     Ok(())
 /// # }
 /// # fn should_fail_1() -> Result<()> {
-/// verify_that!(vec![1, 2, 3], is_contained_in![eq(1), ge(2)])?; // Fails: container too large
+/// verify_that!(vec![1, 2, 3], is_contained_in![eq(&1), ge(&2)])?; // Fails: container too large
 /// #     Ok(())
 /// # }
 /// # fn should_fail_2() -> Result<()> {
-/// verify_that!(vec![2, 1], is_contained_in![eq(1), ge(4)])?;    // Fails: second matcher unmatched
+/// verify_that!(vec![2, 1], is_contained_in![eq(&1), ge(&4)])?;    // Fails: second matcher unmatched
 /// #     Ok(())
 /// # }
 /// # fn should_fail_3() -> Result<()> {
-/// verify_that!(vec![3, 1], is_contained_in![ge(3), ge(3), ge(3)])?; // Fails: no matching
+/// verify_that!(vec![3, 1], is_contained_in![ge(&3), ge(&3), ge(&3)])?; // Fails: no matching
 /// #     Ok(())
 /// # }
 /// # should_pass().unwrap();
@@ -289,28 +256,18 @@
 /// # should_fail_3().unwrap_err();
 /// ```
 ///
-/// The actual value must be a container such as a `Vec`, an array, or a
-/// dereferenced slice. More precisely, a shared borrow of the actual value must
-/// implement [`IntoIterator`].
+/// The actual value must be a container such as a `&Vec`, an array, or a slice.
+/// More precisely, the actual value must implement [`IntoIterator`].
 ///
-/// This can also match against [`HashMap`][std::collections::HashMap] and
-/// similar collections. The arguments are a sequence of pairs of matchers
-/// corresponding to the keys and their respective values.
+///  If an inner matcher is `eq(...)`, it can be omitted:
 ///
 /// ```
 /// # use googletest::prelude::*;
-/// # use std::collections::HashMap;
-/// let value: HashMap<u32, &'static str> = HashMap::from_iter([(1, "One"), (2, "Two")]);
-/// verify_that!(
-///     value,
-///     is_contained_in![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))]
-/// )
+///
+/// verify_that!(vec![1,2,3], is_contained_in![lt(&2), &3, &4, gt(&0)])
 /// #     .unwrap();
 /// ```
 ///
-/// This matcher does not support matching directly against an [`Iterator`]. To
-/// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
-///
 /// The matcher proceeds in three stages:
 ///
 /// 1. It first checks whether the actual value is too large to possibly be
@@ -334,29 +291,20 @@
 #[doc(hidden)]
 macro_rules! __is_contained_in {
     ($(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsAreMatcher, Requirements
-        };
-        UnorderedElementsAreMatcher::new([], Requirements::Subset)
-    }};
-
-    // TODO: Consider an alternative map-like syntax here similar to that used in
-    // https://crates.io/crates/maplit.
-    ($(($key_matcher:expr, $value_matcher:expr)),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsOfMapAreMatcher, Requirements
-        };
-        UnorderedElementsOfMapAreMatcher::new(
-            [$((Box::new($key_matcher), Box::new($value_matcher))),*],
-            Requirements::Subset
-        )
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::
+        UnorderedElementsAreMatcher::new(
+            [], $crate::matchers::__internal_unstable_do_not_depend_on_these::Requirements::Subset)
     }};
 
     ($($matcher:expr),* $(,)?) => {{
-        use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
-            UnorderedElementsAreMatcher, Requirements
-        };
-        UnorderedElementsAreMatcher::new([$(Box::new($matcher)),*], Requirements::Subset)
+        $crate::matchers::__internal_unstable_do_not_depend_on_these::
+        UnorderedElementsAreMatcher::new(
+            [$(Box::new(
+                $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!(
+                    $matcher
+                )
+            )),*],
+            $crate::matchers::__internal_unstable_do_not_depend_on_these::Requirements::Subset)
     }}
 }
 
@@ -366,31 +314,25 @@
 #[doc(hidden)]
 pub mod internal {
     use crate::description::Description;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::{Matcher, MatcherBase, MatcherResult};
     use crate::matcher_support::count_elements::count_elements;
     use std::collections::HashSet;
     use std::fmt::{Debug, Display};
-    use std::marker::PhantomData;
 
     /// This struct is meant to be used only through the
     /// `unordered_elements_are![...]` macro.
     ///
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
-    pub struct UnorderedElementsAreMatcher<'a, ContainerT: ?Sized, T: Debug, const N: usize> {
-        elements: [Box<dyn Matcher<ActualT = T> + 'a>; N],
+    #[derive(MatcherBase)]
+    pub struct UnorderedElementsAreMatcher<'a, T: Debug + Copy, const N: usize> {
+        elements: [Box<dyn Matcher<T> + 'a>; N],
         requirements: Requirements,
-        phantom: PhantomData<ContainerT>,
     }
 
-    impl<'a, ContainerT: ?Sized, T: Debug, const N: usize>
-        UnorderedElementsAreMatcher<'a, ContainerT, T, N>
-    {
-        pub fn new(
-            elements: [Box<dyn Matcher<ActualT = T> + 'a>; N],
-            requirements: Requirements,
-        ) -> Self {
-            Self { elements, requirements, phantom: Default::default() }
+    impl<'a, T: Debug + Copy, const N: usize> UnorderedElementsAreMatcher<'a, T, N> {
+        pub fn new(elements: [Box<dyn Matcher<T> + 'a>; N], requirements: Requirements) -> Self {
+            Self { elements, requirements }
         }
     }
 
@@ -403,19 +345,17 @@
     // least one expected element and vice versa.
     // 3. `UnorderedElementsAreMatcher` verifies that a perfect matching exists
     // using Ford-Fulkerson.
-    impl<'a, T: Debug, ContainerT: Debug + ?Sized, const N: usize> Matcher
-        for UnorderedElementsAreMatcher<'a, ContainerT, T, N>
+    impl<'a, T: Debug + Copy, ContainerT: Debug + Copy, const N: usize> Matcher<ContainerT>
+        for UnorderedElementsAreMatcher<'a, T, N>
     where
-        for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
+        ContainerT: IntoIterator<Item = T>,
     {
-        type ActualT = ContainerT;
-
-        fn matches(&self, actual: &ContainerT) -> MatcherResult {
+        fn matches(&self, actual: ContainerT) -> MatcherResult {
             let match_matrix = MatchMatrix::generate(actual, &self.elements);
             match_matrix.is_match_for(self.requirements).into()
         }
 
-        fn explain_match(&self, actual: &ContainerT) -> Description {
+        fn explain_match(&self, actual: ContainerT) -> Description {
             if let Some(size_mismatch_explanation) =
                 self.requirements.explain_size_mismatch(actual, N)
             {
@@ -450,89 +390,8 @@
         }
     }
 
-    type KeyValueMatcher<'a, KeyT, ValueT> =
-        (Box<dyn Matcher<ActualT = KeyT> + 'a>, Box<dyn Matcher<ActualT = ValueT> + 'a>);
-
-    /// This is the analogue to [UnorderedElementsAreMatcher] for maps and
-    /// map-like collections.
-    ///
-    /// **For internal use only. API stablility is not guaranteed!**
-    #[doc(hidden)]
-    pub struct UnorderedElementsOfMapAreMatcher<'a, ContainerT, KeyT, ValueT, const N: usize>
-    where
-        ContainerT: ?Sized,
-        KeyT: Debug,
-        ValueT: Debug,
-    {
-        elements: [KeyValueMatcher<'a, KeyT, ValueT>; N],
-        requirements: Requirements,
-        phantom: PhantomData<ContainerT>,
-    }
-
-    impl<'a, ContainerT, KeyT: Debug, ValueT: Debug, const N: usize>
-        UnorderedElementsOfMapAreMatcher<'a, ContainerT, KeyT, ValueT, N>
-    {
-        pub fn new(
-            elements: [KeyValueMatcher<'a, KeyT, ValueT>; N],
-            requirements: Requirements,
-        ) -> Self {
-            Self { elements, requirements, phantom: Default::default() }
-        }
-    }
-
-    impl<'a, KeyT: Debug, ValueT: Debug, ContainerT: Debug + ?Sized, const N: usize> Matcher
-        for UnorderedElementsOfMapAreMatcher<'a, ContainerT, KeyT, ValueT, N>
-    where
-        for<'b> &'b ContainerT: IntoIterator<Item = (&'b KeyT, &'b ValueT)>,
-    {
-        type ActualT = ContainerT;
-
-        fn matches(&self, actual: &ContainerT) -> MatcherResult {
-            let match_matrix = MatchMatrix::generate_for_map(actual, &self.elements);
-            match_matrix.is_match_for(self.requirements).into()
-        }
-
-        fn explain_match(&self, actual: &ContainerT) -> Description {
-            if let Some(size_mismatch_explanation) =
-                self.requirements.explain_size_mismatch(actual, N)
-            {
-                return size_mismatch_explanation;
-            }
-
-            let match_matrix = MatchMatrix::generate_for_map(actual, &self.elements);
-            if let Some(unmatchable_explanation) =
-                match_matrix.explain_unmatchable(self.requirements)
-            {
-                return unmatchable_explanation;
-            }
-
-            let best_match = match_matrix.find_best_match();
-
-            best_match
-                .get_explanation_for_map(actual, &self.elements, self.requirements)
-                .unwrap_or("whose elements all match".into())
-        }
-
-        fn describe(&self, matcher_result: MatcherResult) -> Description {
-            format!(
-                "{} elements matching in any order:\n{}",
-                if matcher_result.into() { "contains" } else { "doesn't contain" },
-                self.elements
-                    .iter()
-                    .map(|(key_matcher, value_matcher)| format!(
-                        "{} => {}",
-                        key_matcher.describe(MatcherResult::Match),
-                        value_matcher.describe(MatcherResult::Match)
-                    ))
-                    .collect::<Description>()
-                    .indent()
-            )
-            .into()
-        }
-    }
-
     /// The requirements of the mapping between matchers and actual values by
-    /// which [`UnorderedElemetnsAre`] is deemed to match its input.
+    /// which [`UnorderedElementsAre`] is deemed to match its input.
     ///
     /// **For internal use only. API stablility is not guaranteed!**
     #[doc(hidden)]
@@ -552,14 +411,11 @@
     }
 
     impl Requirements {
-        fn explain_size_mismatch<ContainerT: ?Sized>(
+        fn explain_size_mismatch<ContainerT: IntoIterator + Copy>(
             &self,
-            actual: &ContainerT,
+            actual: ContainerT,
             expected_size: usize,
-        ) -> Option<Description>
-        where
-            for<'b> &'b ContainerT: IntoIterator,
-        {
+        ) -> Option<Description> {
             let actual_size = count_elements(actual);
             match self {
                 Requirements::PerfectMatch if actual_size != expected_size => Some(
@@ -601,13 +457,10 @@
     struct MatchMatrix<const N: usize>(Vec<[MatcherResult; N]>);
 
     impl<const N: usize> MatchMatrix<N> {
-        fn generate<'a, T: Debug + 'a, ContainerT: Debug + ?Sized>(
-            actual: &ContainerT,
-            expected: &[Box<dyn Matcher<ActualT = T> + 'a>; N],
-        ) -> Self
-        where
-            for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
-        {
+        fn generate<'a, T: Debug + Copy + 'a, ContainerT: Debug + Copy + IntoIterator<Item = T>>(
+            actual: ContainerT,
+            expected: &[Box<dyn Matcher<T> + 'a>; N],
+        ) -> Self {
             let mut matrix = MatchMatrix(vec![[MatcherResult::NoMatch; N]; count_elements(actual)]);
             for (actual_idx, actual) in actual.into_iter().enumerate() {
                 for (expected_idx, expected) in expected.iter().enumerate() {
@@ -617,24 +470,6 @@
             matrix
         }
 
-        fn generate_for_map<'a, KeyT: Debug, ValueT: Debug, ContainerT: Debug + ?Sized>(
-            actual: &ContainerT,
-            expected: &[KeyValueMatcher<'a, KeyT, ValueT>; N],
-        ) -> Self
-        where
-            for<'b> &'b ContainerT: IntoIterator<Item = (&'b KeyT, &'b ValueT)>,
-        {
-            let mut matrix = MatchMatrix(vec![[MatcherResult::NoMatch; N]; count_elements(actual)]);
-            for (actual_idx, (actual_key, actual_value)) in actual.into_iter().enumerate() {
-                for (expected_idx, (expected_key, expected_value)) in expected.iter().enumerate() {
-                    matrix.0[actual_idx][expected_idx] = (expected_key.matches(actual_key).into()
-                        && expected_value.matches(actual_value).into())
-                    .into();
-                }
-            }
-            matrix
-        }
-
         fn is_match_for(&self, requirements: Requirements) -> bool {
             match requirements {
                 Requirements::PerfectMatch => {
@@ -959,15 +794,16 @@
             (0..N).filter(|expected_idx| !matched_expected.contains(expected_idx)).collect()
         }
 
-        fn get_explanation<'a, T: Debug, ContainerT: Debug + ?Sized>(
+        fn get_explanation<
+            'a,
+            T: Debug + Copy,
+            ContainerT: Debug + Copy + IntoIterator<Item = T>,
+        >(
             &self,
-            actual: &ContainerT,
-            expected: &[Box<dyn Matcher<ActualT = T> + 'a>; N],
+            actual: ContainerT,
+            expected: &[Box<dyn Matcher<T> + 'a>; N],
             requirements: Requirements,
-        ) -> Option<Description>
-        where
-            for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
-        {
+        ) -> Option<Description> {
             let actual: Vec<_> = actual.into_iter().collect();
             if self.is_full_match() {
                 return None;
@@ -1005,71 +841,12 @@
                 "which does not have a {requirements} match with the expected elements. The best match found was:\n{best_match}"
             ).into())
         }
-
-        fn get_explanation_for_map<'a, KeyT: Debug, ValueT: Debug, ContainerT: Debug + ?Sized>(
-            &self,
-            actual: &ContainerT,
-            expected: &[KeyValueMatcher<'a, KeyT, ValueT>; N],
-            requirements: Requirements,
-        ) -> Option<Description>
-        where
-            for<'b> &'b ContainerT: IntoIterator<Item = (&'b KeyT, &'b ValueT)>,
-        {
-            let actual: Vec<_> = actual.into_iter().collect();
-            if self.is_full_match() {
-                return None;
-            }
-            let mut error_message =
-                format!("which does not have a {requirements} match with the expected elements.");
-
-            error_message.push_str("\n  The best match found was: ");
-
-            let matches = self.get_matches()
-                .map(|(actual_idx, expected_idx)| {
-                    format!(
-                        "Actual element {:?} => {:?} at index {actual_idx} matched expected element `{}` => `{}` at index {expected_idx}.",
-                        actual[actual_idx].0,
-                        actual[actual_idx].1,
-                        expected[expected_idx].0.describe(MatcherResult::Match),
-                        expected[expected_idx].1.describe(MatcherResult::Match),
-                    )
-                });
-
-            let unmatched_actual = self.get_unmatched_actual()
-                .map(|actual_idx| {
-                    format!(
-                        "Actual element {:#?} => {:#?} at index {actual_idx} did not match any remaining expected element.",
-                        actual[actual_idx].0,
-                        actual[actual_idx].1,
-                    )
-                });
-
-            let unmatched_expected = self.get_unmatched_expected()
-                .into_iter()
-                .map(|expected_idx| {
-                    format!(
-                        "Expected element `{}` => `{}` at index {expected_idx} did not match any remaining actual element.",
-                        expected[expected_idx].0.describe(MatcherResult::Match),
-                        expected[expected_idx].1.describe(MatcherResult::Match),
-                    )
-                });
-
-            let best_match = matches
-                .chain(unmatched_actual)
-                .chain(unmatched_expected)
-                .collect::<Description>()
-                .indent();
-            Some(format!(
-                "which does not have a {requirements} match with the expected elements. The best match found was:\n{best_match}"
-            ).into())
-        }
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use super::internal::UnorderedElementsOfMapAreMatcher;
-    use crate::matcher::{Matcher, MatcherResult};
+    use crate::matcher::MatcherResult;
     use crate::prelude::*;
     use indoc::indoc;
     use std::collections::HashMap;
@@ -1081,20 +858,26 @@
         // compiler takes care of that, but when the matcher is created separately,
         // we must create the constitute matchers separately so that they
         // aren't dropped too early.
-        let matchers = ((eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three")));
-        let matcher: UnorderedElementsOfMapAreMatcher<HashMap<i32, &str>, _, _, 3> = unordered_elements_are![
-            (matchers.0.0, matchers.0.1),
-            (matchers.1.0, matchers.1.1),
-            (matchers.2.0, matchers.2.1)
+        let matchers = ((eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three")));
+        let matcher = unordered_elements_are![
+            (matchers.0 .0, matchers.0 .1),
+            (matchers.1 .0, matchers.1 .1),
+            (matchers.2 .0, matchers.2 .1)
         ];
         verify_that!(
-            Matcher::describe(&matcher, MatcherResult::Match),
+            Matcher::<&HashMap<i32, String>>::describe(&matcher, MatcherResult::Match),
             displays_as(eq(indoc!(
                 "
                 contains elements matching in any order:
-                  is equal to 2 => is equal to \"Two\"
-                  is equal to 1 => is equal to \"One\"
-                  is equal to 3 => is equal to \"Three\""
+                  0. is a tuple whose values respectively match:
+                       is equal to 2
+                       is equal to \"Two\"
+                  1. is a tuple whose values respectively match:
+                       is equal to 1
+                       is equal to \"One\"
+                  2. is a tuple whose values respectively match:
+                       is equal to 3
+                       is equal to \"Three\""
             )))
         )
     }
@@ -1106,22 +889,26 @@
         // compiler takes care of that, but when the matcher is created separately,
         // we must create the constitute matchers separately so that they
         // aren't dropped too early.
-        let matchers = ((anything(), eq(1)), (anything(), eq(2)), (anything(), eq(2)));
-        let matcher: UnorderedElementsOfMapAreMatcher<HashMap<u32, u32>, _, _, 3> = unordered_elements_are![
-            (matchers.0.0, matchers.0.1),
-            (matchers.1.0, matchers.1.1),
-            (matchers.2.0, matchers.2.1),
-        ];
         let value: HashMap<u32, u32> = HashMap::from_iter([(0, 1), (1, 1), (2, 2)]);
+        let matchers = ((anything(), eq(&1)), (anything(), eq(&2)), (anything(), eq(&2)));
+        let matcher = unordered_elements_are![
+            (matchers.0 .0, matchers.0 .1),
+            (matchers.1 .0, matchers.1 .1),
+            (matchers.2 .0, matchers.2 .1),
+        ];
         verify_that!(
             matcher.explain_match(&value),
-            displays_as(contains_regex(
-                "Actual element 2 => 2 at index [0-2] matched expected element `is anything` => `is equal to 2` at index [0-2]."
-            )).and(displays_as(contains_regex(
-                "Actual element [0-1] => [0-1] at index [0-2] did not match any remaining expected element."
-            ))).and(displays_as(contains_substring(
-                "Expected element `is anything` => `is equal to 2` at index 2 did not match any remaining actual element."
-            )))
+            all![
+                displays_as(contains_regex(
+                    "Actual element \\(2, 2\\) at index [0-2] matched expected element `is a tuple whose values respectively match:\n    is anything\n    is equal to 2` at index [0-2]."
+                )),
+                displays_as(contains_regex(
+                    "Actual element \\(\n      [0-1],\n      [0-1],\n  \\) at index [0-2] did not match any remaining expected element."
+                )),
+                displays_as(contains_substring(
+                    "Expected element `is a tuple whose values respectively match:\n    is anything\n    is equal to 2` at index 2 did not match any remaining actual element."
+                ))
+            ]
         )
     }
 }
diff --git a/crates/googletest/tests/all_matcher_test.rs b/crates/googletest/tests/all_matcher_test.rs
index 8b36fc0..03f645a 100644
--- a/crates/googletest/tests/all_matcher_test.rs
+++ b/crates/googletest/tests/all_matcher_test.rs
@@ -12,7 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use googletest::matcher::Matcher;
 use googletest::prelude::*;
 use indoc::indoc;
 
@@ -54,7 +53,7 @@
     #[derive(Debug, PartialEq)]
     struct AStruct(i32);
     let expected_value = AStruct(123);
-    verify_that!(AStruct(123), all![eq_deref_of(&expected_value)])
+    verify_that!(AStruct(123), all![eq(&expected_value)])
 }
 
 #[test]
@@ -115,7 +114,7 @@
 #[test]
 fn formats_error_message_correctly_when_all_is_inside_ok() -> Result<()> {
     let value: std::result::Result<i32, std::io::Error> = Ok(4);
-    let result = verify_that!(value, ok(all![eq(1), eq(2), eq(3)]));
+    let result = verify_that!(value, ok(all![eq(&1), eq(&2), eq(&3)]));
     verify_that!(
         result,
         err(displays_as(contains_substring(indoc!(
diff --git a/crates/googletest/tests/any_matcher_test.rs b/crates/googletest/tests/any_matcher_test.rs
index 82ed046..425e99c 100644
--- a/crates/googletest/tests/any_matcher_test.rs
+++ b/crates/googletest/tests/any_matcher_test.rs
@@ -12,16 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use googletest::matcher::Matcher;
 use googletest::prelude::*;
 use indoc::indoc;
 
 #[test]
-fn does_not_match_value_when_list_is_empty() -> Result<()> {
-    verify_that!((), not(any!()))
-}
-
-#[test]
 fn matches_value_with_single_matching_component() -> Result<()> {
     verify_that!(123, any!(eq(123)))
 }
@@ -54,7 +48,7 @@
     #[derive(Debug, PartialEq)]
     struct AStruct(i32);
     let expected_value = AStruct(123);
-    verify_that!(AStruct(123), any![eq_deref_of(&expected_value)])
+    verify_that!(AStruct(123), any![eq(&expected_value)])
 }
 
 #[test]
@@ -66,11 +60,6 @@
 }
 
 #[test]
-fn mismatch_description_empty_matcher() -> Result<()> {
-    verify_that!(any!().explain_match("Three"), displays_as(eq("which never matches")))
-}
-
-#[test]
 fn all_multiple_failed_assertions() -> Result<()> {
     let result = verify_that!(4, any![eq(1), eq(2), eq(3)]);
     verify_that!(
@@ -115,7 +104,7 @@
 #[test]
 fn formats_error_message_correctly_when_any_is_inside_ok() -> Result<()> {
     let value: std::result::Result<i32, std::io::Error> = Ok(4);
-    let result = verify_that!(value, ok(any![eq(1), eq(2), eq(3)]));
+    let result = verify_that!(value, ok(any![eq(&1), eq(&2), eq(&3)]));
     verify_that!(
         result,
         err(displays_as(contains_substring(indoc!(
diff --git a/crates/googletest/tests/assertions_test.rs b/crates/googletest/tests/assertions_test.rs
new file mode 100644
index 0000000..dee073d
--- /dev/null
+++ b/crates/googletest/tests/assertions_test.rs
@@ -0,0 +1,427 @@
+mod verify_pred {
+    use googletest::prelude::*;
+    use indoc::indoc;
+
+    #[test]
+    fn supports_function_call_with_non_debug_types() -> Result<()> {
+        // Non-Debug - cannot be printed.
+        struct Apple;
+        fn f(_a: &Apple, _b: u32, _c: u32) -> bool {
+            false
+        }
+        fn g(_a: u32) -> u32 {
+            5
+        }
+
+        let a = &Apple;
+        let res = verify_pred!(f(a, g(g(3)), 1 + 2));
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                f(a, g(g(3)), 1 + 2) was false with
+                  a does not implement Debug,
+                  g(g(3)) = 5,
+                  1 + 2 = 3,
+                  at"
+            })))
+        )
+    }
+
+    #[test]
+    fn supports_trailing_comma() -> Result<()> {
+        verify_that!(verify_pred!(false,), err(anything()))
+    }
+
+    #[test]
+    fn supports_non_function() -> Result<()> {
+        verify_pred!(true)?;
+        verify_that!(verify_pred!(false), err(anything()))
+    }
+
+    #[test]
+    fn does_not_print_literals() -> Result<()> {
+        trait Foo {
+            fn f(&self, _a: u32, _b: i32, _c: u32, _d: &str) -> bool {
+                false
+            }
+        }
+        impl Foo for i32 {}
+
+        let res = verify_pred!(0.f(1, 2_i32.abs(), 1 + 2, "hello"));
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {r#"
+                0.f(1, 2_i32.abs(), 1 + 2, "hello") was false with
+                  2_i32.abs() = 2,
+                  1 + 2 = 3,
+                  at"#
+            })))
+        )
+    }
+
+    #[test]
+    fn supports_chained_field_access_and_method_calls_with_non_debug_types() -> Result<()> {
+        // Non-Debug
+        struct Apple {
+            b: Banana,
+        }
+        #[derive(Debug)]
+        struct Banana;
+        impl Banana {
+            fn c(&self, _c: &Cherry, _d: u32) -> bool {
+                false
+            }
+        }
+        // Non-Debug - cannot be printed.
+        struct Cherry;
+
+        let a = Apple { b: Banana };
+        let c = &Cherry;
+        let d = 3;
+        let res = verify_pred!(a.b.c(c, d));
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                a.b.c(c, d) was false with
+                  a does not implement Debug,
+                  a.b = Banana,
+                  c does not implement Debug,
+                  d = 3,
+                  at"
+            })))
+        )
+    }
+
+    #[test]
+    fn evaluates_functions_and_arguments_exactly_once() -> Result<()> {
+        let mut a = 0;
+        let mut foo = |_b: u32| {
+            a += 1;
+            false
+        };
+        let mut b = 0;
+        let mut bar = || {
+            b += 10;
+            b
+        };
+
+        let res = verify_pred!(foo(bar()));
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                foo(bar()) was false with
+                  bar() = 10,
+                  at"
+            })))
+        )?;
+
+        verify_that!((a, b), eq((1, 10)))
+    }
+
+    #[test]
+    fn evaluates_methods_and_arguments_exactly_once() -> Result<()> {
+        struct Apple(u32);
+        impl Apple {
+            fn c(&mut self, _b: bool) -> bool {
+                self.0 += 1;
+                false
+            }
+        }
+        let mut a = Apple(0);
+        let mut b = Apple(10);
+
+        let res = verify_pred!(a.c(b.c(false)));
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                a.c(b.c(false)) was false with
+                  a does not implement Debug,
+                  b.c(false) = false,
+                  at"
+            })))
+        )?;
+
+        verify_that!((a.0, b.0), eq((1, 11)))
+    }
+
+    #[test]
+    fn supports_chained_method_calls() -> Result<()> {
+        #[derive(Debug)]
+        struct Apple;
+        impl Apple {
+            fn b(&self, _b: u32) -> Banana {
+                Banana
+            }
+        }
+        // Non-Debug: not printed on error.
+        struct Banana;
+        impl Banana {
+            fn c(&self, _c0: u32, _c1: Cherry) -> bool {
+                false
+            }
+        }
+        // Non-Debug: not printed on error.
+        #[derive(Copy, Clone)]
+        struct Cherry;
+
+        let a = Apple;
+        let v = 10;
+        let res = verify_pred!(a.b(v).c(11, Cherry));
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                a.b(v).c(11, Cherry) was false with
+                  a = Apple,
+                  v = 10,
+                  a.b(v) does not implement Debug,
+                  Cherry does not implement Debug,
+                  at"
+            })))
+        )
+    }
+
+    #[test]
+    fn prints_consumed_values() -> Result<()> {
+        // Non-Debug
+        struct Apple;
+        impl Apple {
+            fn b(self) -> Banana {
+                Banana
+            }
+        }
+        #[derive(Debug)]
+        struct Banana;
+        impl Banana {
+            fn c(self) -> bool {
+                false
+            }
+        }
+
+        let a = Apple;
+        let res = verify_pred!(a.b().c());
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                a.b().c() was false with
+                  a does not implement Debug,
+                  a.b() = Banana,
+                  at"
+            })))
+        )
+    }
+
+    #[test]
+    fn works_with_realistic_example_with_consumed_intermediate_values() -> Result<()> {
+        let res =
+            verify_pred!(vec![1, 2].into_iter().map(|x| x * 2).collect::<Vec<_>>().is_empty());
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                vec! [1, 2].into_iter().map(| x | x * 2).collect :: < Vec < _ > >
+                ().is_empty() was false with
+                  vec! [1, 2] = [1, 2],
+                  vec! [1, 2].into_iter() = IntoIter([1, 2]),
+                  | x | x * 2 does not implement Debug,
+                  vec! [1, 2].into_iter().map(| x | x * 2) = Map { iter: IntoIter([1, 2]) },
+                  vec! [1, 2].into_iter().map(| x | x * 2).collect :: < Vec < _ > > () = [2, 4],
+                  at"
+            })))
+        )
+    }
+
+    #[test]
+    fn values_should_be_accessible_after_test() -> Result<()> {
+        // Not `Copy` and should not be consumed by the generated test code.
+        #[derive(Debug)]
+        struct Apple;
+        impl Apple {
+            fn b(&self, _c: &mut u32) -> bool {
+                false
+            }
+        }
+
+        let mut c = 0;
+        let a = Apple;
+        let res = verify_pred!(a.b(&mut c));
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                a.b(& mut c) was false with
+                  a = Apple,
+                  & mut c = 0,
+                  at"
+            })))
+        )?;
+
+        // `a` and `&mut c` should still be accessible after the test despite not being
+        // `Copy`.
+        let _ = a.b(&mut c);
+
+        Ok(())
+    }
+
+    #[test]
+    fn prints_values_for_mutating_expressions() -> Result<()> {
+        let mut a = 1;
+        let mut b = 2;
+        let mut c = 0;
+        trait Mutator {
+            fn mutate_and_false(&mut self, b: &mut u32) -> bool;
+        }
+        impl Mutator for u32 {
+            fn mutate_and_false(&mut self, b: &mut u32) -> bool {
+                *self += 10;
+                *b += 20;
+                false
+            }
+        }
+
+        // Macro to to avoid the inconsistency in how `;` and `&mut` are printed between
+        // Rust versions when printing out the stringified version of the block.
+        macro_rules! block_a {
+            () => {{
+                c += 10;
+                &mut a
+            }};
+        }
+        macro_rules! block_b {
+            () => {{
+                c += 100;
+                &mut b
+            }};
+        }
+        let res = verify_pred! { block_a!().mutate_and_false(block_b!()) };
+
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                block_a! ().mutate_and_false(block_b! ()) was false with
+                  block_a! () = 1,
+                  block_b! () = 2,
+                  at"
+            })))
+        )?;
+
+        verify_that!((a, b, c), eq((11, 22, 110)))
+    }
+
+    #[test]
+    fn values_can_be_insulated_with_parens() -> Result<()> {
+        // Not `Copy` and has a consuming method.
+        struct Apple;
+        impl Apple {
+            fn b(self) -> Banana {
+                Banana
+            }
+        }
+        #[derive(Debug)]
+        struct Banana;
+        impl Banana {
+            fn c(&self) -> bool {
+                false
+            }
+        }
+
+        let a = Apple;
+        let res = verify_pred!({ a.b() }.c());
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                { a.b() }.c() was false with
+                  { a.b() } = Banana,
+                  at"
+            })))
+        )
+    }
+
+    #[test]
+    fn binary_operator() -> Result<()> {
+        // Add chaining and function calls.
+        fn f(x: u32) -> u32 {
+            x + 1
+        }
+        #[derive(Debug)]
+        struct Apple;
+        impl Apple {
+            fn b(&self, y: u32) -> u32 {
+                y + 10
+            }
+        }
+        let a = Apple;
+        let x = 1;
+        let y = 2;
+        let res = verify_pred!(f(x) - 1 == a.b(y + 1) + f(y));
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                f(x) - 1 == a.b(y + 1) + f(y) was false with
+                  x = 1,
+                  f(x) = 2,
+                  f(x) - 1 = 1,
+                  a = Apple,
+                  y + 1 = 3,
+                  a.b(y + 1) = 13,
+                  y = 2,
+                  f(y) = 3,
+                  a.b(y + 1) + f(y) = 16,
+                  at"
+            })))
+        )
+    }
+
+    #[rustversion::before(1.77)]
+    #[test]
+    fn unary_operator() -> Result<()> {
+        #[derive(Debug)]
+        struct Apple;
+        impl Apple {
+            fn b(&self, _b: u32, _c: i32) -> i32 {
+                0
+            }
+        }
+
+        let a = Apple;
+        let b = 1;
+        let res = verify_pred!(!a.b(b, -1) == !-2);
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                ! a.b(b, - 1) ==! - 2 was false with
+                  a = Apple,
+                  b = 1,
+                  a.b(b, - 1) = 0,
+                  ! a.b(b, - 1) = -1,
+                  ! - 2 = 1,
+                  at"
+            })))
+        )
+    }
+
+    #[rustversion::since(1.77)]
+    #[test]
+    fn unary_operator() -> Result<()> {
+        #[derive(Debug)]
+        struct Apple;
+        impl Apple {
+            fn b(&self, _b: u32, _c: i32) -> i32 {
+                0
+            }
+        }
+
+        let a = Apple;
+        let b = 1;
+        let res = verify_pred!(!a.b(b, -1) == !-2);
+        verify_that!(
+            res,
+            err(displays_as(contains_substring(indoc! {"
+                ! a.b(b, - 1) == ! - 2 was false with
+                  a = Apple,
+                  b = 1,
+                  a.b(b, - 1) = 0,
+                  ! a.b(b, - 1) = -1,
+                  ! - 2 = 1,
+                  at"
+            })))
+        )
+    }
+}
diff --git a/crates/googletest/tests/colorized_diff_test.rs b/crates/googletest/tests/colorized_diff_test.rs
index d056020..2029521 100644
--- a/crates/googletest/tests/colorized_diff_test.rs
+++ b/crates/googletest/tests/colorized_diff_test.rs
@@ -32,7 +32,7 @@
     std::env::remove_var("NO_COLOR");
     std::env::set_var("FORCE_COLOR", "1");
 
-    let result = verify_that!(build_text(1..50), eq(build_text(1..51)));
+    let result = verify_that!(build_text(1..50), eq(&build_text(1..51)));
 
     verify_that!(
         result,
diff --git a/crates/googletest/tests/composition_test.rs b/crates/googletest/tests/composition_test.rs
index 7ae146f..e5f2cd7 100644
--- a/crates/googletest/tests/composition_test.rs
+++ b/crates/googletest/tests/composition_test.rs
@@ -17,14 +17,14 @@
 #[test]
 fn all_matcher_works_as_inner_matcher() -> Result<()> {
     let value = vec![1];
-    verify_that!(value, contains_each![all!(gt(0), lt(2))])
+    verify_that!(value, contains_each![all!(gt(&0), lt(&2))])
 }
 
 #[test]
 fn matches_pattern_works_as_inner_matcher() -> Result<()> {
     #[derive(Debug)]
     struct AStruct(i32);
-    verify_that!(vec![AStruct(123)], contains_each![matches_pattern!(AStruct(eq(123)))])
+    verify_that!(vec![AStruct(123)], contains_each![matches_pattern!(&AStruct(eq(123)))])
 }
 
 #[test]
@@ -38,7 +38,7 @@
     }
     verify_that!(
         vec![AStruct(123)],
-        contains_each![matches_pattern!(AStruct {
+        contains_each![matches_pattern!(&AStruct {
             get_value(): eq(123)
         })]
     )
@@ -48,24 +48,139 @@
 fn contains_each_works_as_inner_matcher() -> Result<()> {
     #[derive(Debug)]
     struct AStruct(Vec<i32>);
-    verify_that!(AStruct(vec![123]), matches_pattern!(AStruct(contains_each![eq(123)])))
+    verify_that!(AStruct(vec![123]), matches_pattern!(&AStruct(ref contains_each![eq(&123)])))
 }
 
 #[test]
 fn pointwise_works_as_inner_matcher() -> Result<()> {
     #[derive(Debug)]
     struct AStruct(Vec<i32>);
-    verify_that!(AStruct(vec![123]), matches_pattern!(AStruct(pointwise!(eq, [123]))))
+    verify_that!(AStruct(vec![123]), matches_pattern!(&AStruct(ref pointwise!(eq, [&123]))))
 }
 
 #[test]
 fn elements_are_works_as_inner_matcher() -> Result<()> {
     #[derive(Debug)]
     struct AStruct(Vec<i32>);
-    verify_that!(AStruct(vec![123]), matches_pattern!(AStruct(elements_are![eq(123)])))
+    verify_that!(AStruct(vec![123]), matches_pattern!(&AStruct(ref elements_are![eq(&123)])))
 }
 
 #[test]
 fn tuple_works_as_inner_matcher() -> Result<()> {
-    verify_that!(vec![(123,)], elements_are![(eq(123),)])
+    verify_that!(vec![(123,)], elements_are![(eq(&123),)])
+}
+
+#[test]
+fn matches_struct_with_method_returning_option_of_non_copy_value() -> Result<()> {
+    #[derive(Debug)]
+    struct AnInnerStruct;
+
+    #[derive(Debug)]
+    struct AStruct;
+
+    impl AStruct {
+        fn get_value(&self) -> Option<AnInnerStruct> {
+            Some(AnInnerStruct)
+        }
+    }
+
+    verify_that!(
+        AStruct,
+        matches_pattern!(&AStruct {
+            get_value(): ref some(matches_pattern!(&AnInnerStruct))
+        })
+    )
+}
+
+#[test]
+fn matches_struct_with_method_returning_option_of_non_copy_enum() -> Result<()> {
+    #[derive(Debug)]
+    enum AnInnerStruct {
+        ThisCase,
+        #[allow(unused)]
+        ThatCase,
+    }
+    #[derive(Debug)]
+    struct AStruct;
+    impl AStruct {
+        fn get_value(&self) -> Option<AnInnerStruct> {
+            Some(AnInnerStruct::ThisCase)
+        }
+    }
+
+    verify_that!(
+        AStruct,
+        matches_pattern!(&AStruct {
+            get_value(): ref some(matches_pattern!(&AnInnerStruct::ThisCase))
+        })
+    )
+}
+
+#[test]
+fn matches_struct_with_method_returning_option_ref_binding_mode() -> Result<()> {
+    #[derive(Debug)]
+    struct AnInnerStruct;
+    #[derive(Debug)]
+    struct AStruct;
+    impl AStruct {
+        fn get_value(&self) -> Option<AnInnerStruct> {
+            Some(AnInnerStruct)
+        }
+    }
+
+    verify_that!(
+        AStruct,
+        matches_pattern!(AStruct {
+            get_value(): some(matches_pattern!(AnInnerStruct))
+        })
+    )
+}
+
+#[test]
+fn matches_struct_with_method_returning_option_enum_ref_binding_mode() -> Result<()> {
+    #[derive(Debug)]
+    enum AnInnerStruct {
+        ThisCase,
+        #[allow(unused)]
+        ThatCase,
+    }
+    #[derive(Debug)]
+    struct AStruct;
+    impl AStruct {
+        fn get_value(&self) -> Option<AnInnerStruct> {
+            Some(AnInnerStruct::ThisCase)
+        }
+    }
+
+    verify_that!(
+        AStruct,
+        matches_pattern!(AStruct {
+            get_value(): some(matches_pattern!(AnInnerStruct::ThisCase))
+        })
+    )
+}
+
+#[test]
+fn matches_struct_with_property_against_predicate() -> Result<()> {
+    #[derive(Debug)]
+    enum AnInnerStruct {
+        ThisCase,
+        #[allow(unused)]
+        ThatCase,
+    }
+
+    #[derive(Debug)]
+    struct AStruct;
+    impl AStruct {
+        fn get_value(&self) -> AnInnerStruct {
+            AnInnerStruct::ThisCase
+        }
+    }
+
+    verify_that!(
+        AStruct,
+        matches_pattern!(AStruct {
+            get_value(): predicate(|_: &_| true)
+        })
+    )
 }
diff --git a/crates/googletest/tests/elements_are_matcher_test.rs b/crates/googletest/tests/elements_are_matcher_test.rs
index 4de2314..3aafbc7 100644
--- a/crates/googletest/tests/elements_are_matcher_test.rs
+++ b/crates/googletest/tests/elements_are_matcher_test.rs
@@ -12,21 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use googletest::matcher::Matcher;
 use googletest::prelude::*;
 use indoc::indoc;
 
 #[test]
 fn elements_are_matches_vector() -> Result<()> {
     let value = vec![1, 2, 3];
-    verify_that!(value, elements_are![eq(1), eq(2), eq(3)])
+    verify_that!(value, elements_are![eq(&1), eq(&2), eq(&3)])
 }
 
 #[test]
 fn elements_are_matches_slice() -> Result<()> {
     let value = vec![1, 2, 3];
     let slice = value.as_slice();
-    verify_that!(*slice, elements_are![eq(1), eq(2), eq(3)])
+    verify_that!(slice, elements_are![eq(&1), eq(&2), eq(&3)])
 }
 
 #[test]
@@ -37,13 +36,13 @@
 #[test]
 fn elements_are_supports_trailing_comma() -> Result<()> {
     let value = vec![1, 2, 3];
-    verify_that!(value, elements_are![eq(1), eq(2), eq(3),])
+    verify_that!(value, elements_are![eq(&1), eq(&2), eq(&3),])
 }
 
 #[test]
 fn elements_are_returns_no_match_when_expected_and_actual_sizes_differ() -> Result<()> {
     let value = vec![1, 2];
-    verify_that!(value, not(elements_are![eq(1), eq(2), eq(3)]))
+    verify_that!(value, not(elements_are![eq(&1), eq(&2), eq(&3)]))
 }
 
 #[test]
@@ -51,12 +50,32 @@
     #[derive(Debug, PartialEq)]
     struct AStruct(i32);
     let expected_value = AStruct(123);
-    verify_that!(vec![AStruct(123)], elements_are![eq_deref_of(&expected_value)])
+    verify_that!(vec![AStruct(123)], elements_are![eq(&expected_value)])
+}
+
+#[test]
+fn elements_are_matches_iterator_returning_by_value() -> Result<()> {
+    #[derive(Debug, Copy, Clone)]
+    struct Countdown(i32);
+    impl Iterator for Countdown {
+        type Item = i32;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            match self.0 {
+                0 => None,
+                x => {
+                    self.0 -= 1;
+                    Some(x)
+                }
+            }
+        }
+    }
+    verify_that!(Countdown(3), elements_are![eq(3), eq(2), eq(1)])
 }
 
 #[test]
 fn elements_are_produces_correct_failure_message() -> Result<()> {
-    let result = verify_that!(vec![1, 4, 3], elements_are![eq(1), eq(2), eq(3)]);
+    let result = verify_that!(vec![1, 4, 3], elements_are![eq(&1), eq(&2), eq(&3)]);
     verify_that!(
         result,
         err(displays_as(contains_substring(indoc!(
@@ -76,7 +95,7 @@
 fn elements_are_produces_correct_failure_message_nested() -> Result<()> {
     let result = verify_that!(
         vec![vec![0, 1], vec![1, 2]],
-        elements_are![elements_are![eq(1), eq(2)], elements_are![eq(2), eq(3)]]
+        elements_are![elements_are![eq(&1), eq(&2)], elements_are![eq(&2), eq(&3)]]
     );
     verify_that!(
         result,
@@ -103,14 +122,12 @@
 
 #[test]
 fn elements_are_explain_match_wrong_size() -> Result<()> {
-    verify_that!(
-        elements_are![eq(1)].explain_match(&vec![1, 2]),
-        displays_as(eq("whose size is 2"))
-    )
+    let matcher = elements_are![eq(&1)];
+    verify_that!(matcher.explain_match(&vec![1, 2]), displays_as(eq("whose size is 2")))
 }
 
-fn create_matcher() -> impl Matcher<ActualT = Vec<i32>> {
-    elements_are![eq(1)]
+fn create_matcher<'a>() -> impl Matcher<&'a Vec<i32>> {
+    elements_are![eq(&1)]
 }
 
 #[test]
@@ -120,5 +137,10 @@
 
 #[test]
 fn elements_are_implicitly_called() -> Result<()> {
-    verify_that!(vec![1, 2, 3], [eq(1), eq(2), eq(3)])
+    verify_that!(vec![1, 2, 3], [eq(&1), eq(&2), eq(&3)])
+}
+
+#[test]
+fn elements_are_with_auto_eq() -> Result<()> {
+    verify_that!(vec![1, 2, 3], [&1, &2, lt(&43)])
 }
diff --git a/crates/googletest/tests/field_matcher_test.rs b/crates/googletest/tests/field_matcher_test.rs
index f585c21..c239b47 100644
--- a/crates/googletest/tests/field_matcher_test.rs
+++ b/crates/googletest/tests/field_matcher_test.rs
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use googletest::matcher::{Matcher, MatcherResult};
+use googletest::matcher::MatcherResult;
 use googletest::prelude::*;
 
 #[derive(Debug)]
@@ -22,7 +22,7 @@
 
 #[test]
 fn field_matches_integer_field() -> Result<()> {
-    verify_that!(IntField { int: 32 }, field!(IntField.int, eq(32)))
+    verify_that!(IntField { int: 32 }, field!(&IntField.int, eq(32)))
 }
 
 #[derive(Debug)]
@@ -32,12 +32,15 @@
 
 #[test]
 fn field_matches_string_field() -> Result<()> {
-    verify_that!(StringField { strink: "yes".to_string() }, field!(StringField.strink, eq("yes")))
+    verify_that!(
+        StringField { strink: "yes".to_string() },
+        field!(&StringField.strink, ref eq("yes"))
+    )
 }
 
 #[test]
 fn field_error_message_shows_field_name_and_inner_matcher() -> Result<()> {
-    let matcher = field!(IntField.int, eq(31));
+    let matcher = field!(&IntField.int, eq(31));
 
     verify_that!(
         matcher.describe(MatcherResult::Match),
@@ -54,15 +57,15 @@
 
 #[test]
 fn struct_in_other_module_matches() -> Result<()> {
-    verify_that!(sub::SubStruct { field: 32 }, field!(sub::SubStruct.field, eq(32)))
+    verify_that!(sub::SubStruct { field: 32 }, field!(&sub::SubStruct.field, eq(32)))
 }
 
 #[derive(Debug)]
-struct Tuple(i32, String);
+struct Tuple(i32, #[allow(unused)] String);
 
 #[test]
 fn tuple_matches_with_index() -> Result<()> {
-    verify_that!(Tuple(32, "yes".to_string()), field!(Tuple.0, eq(32)))
+    verify_that!(Tuple(32, "yes".to_string()), field!(&Tuple.0, eq(32)))
 }
 
 #[test]
@@ -73,7 +76,7 @@
     }
     let value = AnEnum::AValue(123);
 
-    verify_that!(value, field!(AnEnum::AValue.0, eq(123)))
+    verify_that!(value, field!(&AnEnum::AValue.0, eq(123)))
 }
 
 #[test]
@@ -84,7 +87,7 @@
     }
     let value = AStruct { a: vec![1] };
 
-    let result = verify_that!(value, field!(AStruct.a, container_eq([])));
+    let result = verify_that!(value, field!(&AStruct.a, ref container_eq([])));
 
     verify_that!(
         result,
@@ -104,7 +107,7 @@
     }
     let value = AnEnum::AnotherValue;
 
-    verify_that!(value, not(field!(AnEnum::AValue.0, eq(123))))
+    verify_that!(&value, not(field!(&AnEnum::AValue.0, eq(123))))
 }
 
 #[test]
@@ -119,7 +122,7 @@
     }
     let value = AnEnum::AnotherValue;
 
-    let result = verify_that!(value, field!(AnEnum::AValue.a, eq(123)));
+    let result = verify_that!(value, field!(&AnEnum::AValue.a, eq(123)));
 
     verify_that!(
         result,
@@ -133,11 +136,12 @@
     enum AnEnum {
         #[allow(dead_code)] // This variant is intentionally unused.
         AValue(u32),
+        #[allow(unused)]
         AnotherValue(u32),
     }
     let value = AnEnum::AnotherValue(123);
 
-    let result = verify_that!(value, field!(AnEnum::AValue.0, eq(123)));
+    let result = verify_that!(value, field!(&AnEnum::AValue.0, eq(123)));
 
     verify_that!(
         result,
@@ -158,7 +162,7 @@
     }
     let value = AnEnum::AnotherValue { a: 123 };
 
-    let result = verify_that!(value, field!(AnEnum::AValue.0, eq(123)));
+    let result = verify_that!(value, field!(&AnEnum::AValue.0, eq(123)));
 
     verify_that!(
         result,
@@ -174,5 +178,87 @@
     }
     let value = AnEnum::AValue { a_field: 123 };
 
-    verify_that!(value, field!(AnEnum::AValue.a_field, eq(123)))
+    verify_that!(value, field!(&AnEnum::AValue.a_field, eq(123)))
+}
+
+#[test]
+fn matches_struct_copy_to_copy() -> Result<()> {
+    #[derive(Debug, Clone, Copy)]
+    struct Strukt {
+        a_field: i32,
+    }
+
+    verify_that!(Strukt { a_field: 32 }, field!(Strukt.a_field, eq(32)))
+}
+
+#[test]
+fn matches_struct_ref_to_copy() -> Result<()> {
+    #[derive(Debug)]
+    struct Strukt {
+        a_field: i32,
+    }
+
+    verify_that!(Strukt { a_field: 32 }, field!(&Strukt.a_field, eq(32)))
+}
+
+#[test]
+fn matches_struct_ref_to_ref() -> Result<()> {
+    #[derive(Debug)]
+    struct Strukt {
+        a_field: String,
+    }
+
+    verify_that!(Strukt { a_field: "32".into() }, field!(&Strukt.a_field, ref eq("32")))
+}
+
+#[test]
+fn matches_struct_copy_to_ref() -> Result<()> {
+    // It is not possible to have a copy struct with non-copy field. Hence, this
+    // test case is not necessary.
+    Ok(())
+}
+
+#[test]
+fn matches_struct_ref_to_ref_binding_mode() -> Result<()> {
+    #[derive(Debug)]
+    struct Strukt {
+        a_field: String,
+    }
+
+    verify_that!(Strukt { a_field: "32".into() }, field!(Strukt.a_field, eq("32")))
+}
+
+#[test]
+fn matches_struct_with_auto_eq() -> Result<()> {
+    #[derive(Debug)]
+    struct Strukt {
+        a_field: String,
+    }
+
+    verify_that!(Strukt { a_field: "32".into() }, field!(Strukt.a_field, "32"))
+}
+
+#[test]
+fn matches_enum_with_auto_eq() -> Result<()> {
+    #[derive(Debug)]
+    enum Enum {
+        Str(String),
+        #[allow(unused)]
+        Int(i32),
+    }
+
+    verify_that!(Enum::Str("32".into()), field!(Enum::Str.0, "32"))
+}
+
+#[test]
+fn matches_enum_with_auto_eq_with_wrapper() -> Result<()> {
+    #[derive(Debug)]
+    struct Wrapper<I> {
+        wrapped: I,
+    }
+
+    verify_that!(
+        Wrapper { wrapped: Wrapper { wrapped: 23 } },
+        field!(Wrapper.wrapped, field!(Wrapper.wrapped, &23))
+    )
 }
diff --git a/crates/googletest/tests/fmt_test.rs b/crates/googletest/tests/fmt_test.rs
new file mode 100644
index 0000000..63e2dd7
--- /dev/null
+++ b/crates/googletest/tests/fmt_test.rs
@@ -0,0 +1,58 @@
+// Copyright 2024 Google LLC
+//
+// 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.
+
+mod write_expr_value {
+    use googletest::prelude::*;
+
+    // Converts the formatting call to a `String` for testing.
+    macro_rules! write_expr_value {
+        ($expr_str:expr, $expr: expr $(,)?) => {{
+            let mut s = String::new();
+            ::googletest::fmt::internal::__googletest__write_expr_value!(s, $expr_str, $expr);
+            s
+        }};
+    }
+
+    #[test]
+    fn test_with_debug_value_references() -> Result<()> {
+        #[derive(Debug)]
+        struct Foo;
+        let mut val = Foo;
+
+        verify_that!(write_expr_value!("val", val), eq("\n  val = Foo,"))?;
+        verify_that!(write_expr_value!("val", &val), eq("\n  val = Foo,"))?;
+        verify_that!(write_expr_value!("val", &&val), eq("\n  val = Foo,"))?;
+        verify_that!(write_expr_value!("val", &mut val), eq("\n  val = Foo,"))?;
+        verify_that!(write_expr_value!("val", &mut &mut val), eq("\n  val = Foo,"))?;
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_with_non_debug_value_references() -> Result<()> {
+        struct Foo;
+        let mut val = Foo;
+
+        verify_that!(write_expr_value!("val", val), eq("\n  val does not implement Debug,"))?;
+        verify_that!(write_expr_value!("val", &val), eq("\n  val does not implement Debug,"))?;
+        verify_that!(write_expr_value!("val", &&val), eq("\n  val does not implement Debug,"))?;
+        verify_that!(write_expr_value!("val", &mut val), eq("\n  val does not implement Debug,"))?;
+        verify_that!(
+            write_expr_value!("val", &mut &mut val),
+            eq("\n  val does not implement Debug,")
+        )?;
+
+        Ok(())
+    }
+}
diff --git a/crates/googletest/tests/lib.rs b/crates/googletest/tests/lib.rs
index fb243ca..f5d8f75 100644
--- a/crates/googletest/tests/lib.rs
+++ b/crates/googletest/tests/lib.rs
@@ -14,6 +14,7 @@
 
 mod all_matcher_test;
 mod any_matcher_test;
+mod assertions_test;
 mod colorized_diff_test;
 mod composition_test;
 mod elements_are_matcher_test;
@@ -21,7 +22,6 @@
 mod matches_pattern_test;
 mod pointwise_matcher_test;
 mod property_matcher_test;
-#[cfg(feature = "proptest")]
 mod proptest_integration_test;
 mod tuple_matcher_test;
 mod unordered_elements_are_matcher_test;
diff --git a/crates/googletest/tests/matches_pattern_test.rs b/crates/googletest/tests/matches_pattern_test.rs
index 3298e36..d1b97e7 100644
--- a/crates/googletest/tests/matches_pattern_test.rs
+++ b/crates/googletest/tests/matches_pattern_test.rs
@@ -23,7 +23,7 @@
     }
     let actual = AStruct { a_field: 123 };
 
-    verify_that!(actual, matches_pattern!(AStruct { a_field: eq(123) }))
+    verify_that!(actual, matches_pattern!(&AStruct { a_field: eq(123) }))
 }
 
 #[test]
@@ -35,7 +35,7 @@
     }
     let actual = AStruct { a_field: 123, another_field: 234 };
 
-    verify_that!(actual, matches_pattern!(AStruct { a_field: eq(123), another_field: eq(234) }))
+    verify_that!(actual, matches_pattern!(&AStruct { a_field: eq(123), another_field: eq(234) }))
 }
 
 #[test]
@@ -47,7 +47,7 @@
     }
     let actual = AStruct { a_field: 123 };
 
-    verify_that!(actual, matches_pattern!(AStruct {
+    verify_that!(actual, matches_pattern!(&AStruct {
         a_field: eq(123), // Block reformatting
     }))
 }
@@ -63,7 +63,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             a_field: eq(123),
             another_field: eq(234), // Block reformatting
         })
@@ -82,7 +82,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             a_field: eq(123),
             another_field: eq(234),
             a_third_field: eq(345),
@@ -104,29 +104,69 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { a_nested_struct: pat!(ANestedStruct { a_field: eq(123) }) })
+        matches_pattern!(&AStruct { a_nested_struct: ref pat!(&ANestedStruct { a_field: eq(123) }) })
     )
 }
 
 #[test]
+fn matches_struct_containing_nested_struct_with_field_with_binding_mode() -> Result<()> {
+    #[derive(Debug)]
+    struct AStruct {
+        a_nested_struct: ANestedStruct,
+    }
+    #[derive(Debug)]
+    struct ANestedStruct {
+        a_field: u32,
+    }
+    let actual = AStruct { a_nested_struct: ANestedStruct { a_field: 123 } };
+
+    verify_that!(
+        actual,
+        matches_pattern!(AStruct { a_nested_struct: pat!(ANestedStruct { a_field: eq(&123) }) })
+    )
+}
+
+#[test]
+fn matches_struct_containing_non_copy_field_binding_mode() -> Result<()> {
+    #[derive(Debug)]
+    struct AStruct {
+        a_string: String,
+    }
+    let actual = AStruct { a_string: "123".into() };
+
+    verify_that!(actual, matches_pattern!(AStruct { a_string: eq("123") }))
+}
+
+#[test]
 fn has_correct_assertion_failure_message_for_single_field() -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
     }
     let actual = AStruct { a_field: 123 };
-    let result = verify_that!(actual, matches_pattern!(AStruct { a_field: eq(234) }));
+    let result = verify_that!(actual, matches_pattern!(&AStruct { a_field: eq(234) }));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(indoc! {"
-            Value of: actual
-            Expected: is AStruct which has field `a_field`, which is equal to 234
-            Actual: AStruct { a_field: 123 },
-              which has field `a_field`, which isn't equal to 234
-            "
-        })))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = indoc!(
+        "
+        Value of: actual
+        Expected: is & AStruct which has field `a_field`, which is equal to 234
+        Actual: AStruct { a_field: 123 },
+          which has field `a_field`, which isn't equal to 234
+        "
+    );
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = indoc!(
+        "
+        Value of: actual
+        Expected: is &AStruct which has field `a_field`, which is equal to 234
+        Actual: AStruct { a_field: 123 },
+          which has field `a_field`, which isn't equal to 234
+        "
+    );
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
 #[test]
@@ -139,21 +179,34 @@
     let actual = AStruct { a_field: 123, another_field: 234 };
     let result = verify_that!(
         actual,
-        matches_pattern!(AStruct { a_field: eq(234), another_field: eq(123) })
+        matches_pattern!(&AStruct { a_field: eq(234), another_field: eq(123) })
     );
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(indoc!(
-            "
-            Value of: actual
-            Expected: is AStruct which has all the following properties:
-              * has field `a_field`, which is equal to 234
-              * has field `another_field`, which is equal to 123
-            Actual: AStruct { a_field: 123, another_field: 234 },
-              * which has field `a_field`, which isn't equal to 234
-              * which has field `another_field`, which isn't equal to 123"
-        ))))
-    )
+
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = indoc!(
+        "
+        Value of: actual
+        Expected: is & AStruct which has all the following properties:
+          * has field `a_field`, which is equal to 234
+          * has field `another_field`, which is equal to 123
+        Actual: AStruct { a_field: 123, another_field: 234 },
+          * which has field `a_field`, which isn't equal to 234
+          * which has field `another_field`, which isn't equal to 123"
+    );
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = indoc!(
+        "
+        Value of: actual
+        Expected: is &AStruct which has all the following properties:
+          * has field `a_field`, which is equal to 234
+          * has field `another_field`, which is equal to 123
+        Actual: AStruct { a_field: 123, another_field: 234 },
+          * which has field `a_field`, which isn't equal to 234
+          * which has field `another_field`, which isn't equal to 123"
+    );
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
 #[test]
@@ -171,33 +224,47 @@
     let actual = AStruct { a_field: 123, another_field: 234 };
     let result = verify_that!(
         actual,
-        matches_pattern!(AStruct { get_field(): eq(234), another_field: eq(123) })
+        matches_pattern!(&AStruct { get_field(): eq(234), another_field: eq(123) })
     );
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(indoc!(
-            "
-            Value of: actual
-            Expected: is AStruct which has all the following properties:
-              * has property `get_field ()`, which is equal to 234
-              * has field `another_field`, which is equal to 123
-            Actual: AStruct { a_field: 123, another_field: 234 },
-              * whose property `get_field ()` is `123`, which isn't equal to 234
-              * which has field `another_field`, which isn't equal to 123"
-        ))))
-    )
+
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = indoc!(
+        "
+    Value of: actual
+    Expected: is & AStruct which has all the following properties:
+      * has property `get_field ()`, which is equal to 234
+      * has field `another_field`, which is equal to 123
+    Actual: AStruct { a_field: 123, another_field: 234 },
+      * whose property `get_field ()` is `123`, which isn't equal to 234
+      * which has field `another_field`, which isn't equal to 123"
+    );
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = indoc!(
+        "
+    Value of: actual
+    Expected: is &AStruct which has all the following properties:
+      * has property `get_field ()`, which is equal to 234
+      * has field `another_field`, which is equal to 123
+    Actual: AStruct { a_field: 123, another_field: 234 },
+      * whose property `get_field ()` is `123`, which isn't equal to 234
+      * which has field `another_field`, which isn't equal to 123"
+    );
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
 #[test]
 fn has_meaningful_assertion_failure_message_when_wrong_enum_variant_is_used() -> Result<()> {
     #[derive(Debug)]
     enum AnEnum {
+        #[allow(unused)]
         A(u32),
         #[allow(unused)]
         B(u32),
     }
     let actual = AnEnum::A(123);
-    let result = verify_that!(actual, matches_pattern!(AnEnum::B(eq(123))));
+    let result = verify_that!(actual, matches_pattern!(&AnEnum::B(eq(123))));
 
     verify_that!(
         result,
@@ -219,7 +286,7 @@
     }
     let actual = a_module::AStruct { a_field: 123 };
 
-    verify_that!(actual, matches_pattern!(a_module::AStruct { a_field: eq(123) }))
+    verify_that!(actual, matches_pattern!(&a_module::AStruct { a_field: eq(123) }))
 }
 
 #[test]
@@ -228,7 +295,7 @@
     struct AStruct(u32);
     let actual = AStruct(123);
 
-    verify_that!(actual, matches_pattern!(AStruct(eq(123))))
+    verify_that!(actual, matches_pattern!(&AStruct(eq(123))))
 }
 
 #[test]
@@ -237,7 +304,7 @@
     struct AStruct(u32, u32);
     let actual = AStruct(123, 234);
 
-    verify_that!(actual, matches_pattern!(AStruct(eq(123), eq(234))))
+    verify_that!(actual, matches_pattern!(&AStruct(eq(123), eq(234))))
 }
 
 #[test]
@@ -246,7 +313,7 @@
     struct AStruct(u32, u32, u32);
     let actual = AStruct(123, 234, 345);
 
-    verify_that!(actual, matches_pattern!(AStruct(eq(123), eq(234), eq(345))))
+    verify_that!(actual, matches_pattern!(&AStruct(eq(123), eq(234), eq(345))))
 }
 
 #[test]
@@ -255,7 +322,7 @@
     struct AStruct(u32, u32, u32, u32);
     let actual = AStruct(123, 234, 345, 456);
 
-    verify_that!(actual, matches_pattern!(AStruct(eq(123), eq(234), eq(345), eq(456))))
+    verify_that!(actual, matches_pattern!(&AStruct(eq(123), eq(234), eq(345), eq(456))))
 }
 
 #[test]
@@ -264,7 +331,7 @@
     struct AStruct(u32, u32, u32, u32, u32);
     let actual = AStruct(123, 234, 345, 456, 567);
 
-    verify_that!(actual, matches_pattern!(AStruct(eq(123), eq(234), eq(345), eq(456), eq(567))))
+    verify_that!(actual, matches_pattern!(&AStruct(eq(123), eq(234), eq(345), eq(456), eq(567))))
 }
 
 #[test]
@@ -275,7 +342,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct(eq(123), eq(234), eq(345), eq(456), eq(567), eq(678)))
+        matches_pattern!(&AStruct(eq(123), eq(234), eq(345), eq(456), eq(567), eq(678)))
     )
 }
 
@@ -287,7 +354,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct(eq(123), eq(234), eq(345), eq(456), eq(567), eq(678), eq(789)))
+        matches_pattern!(&AStruct(eq(123), eq(234), eq(345), eq(456), eq(567), eq(678), eq(789)))
     )
 }
 
@@ -299,7 +366,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct(
+        matches_pattern!(&AStruct(
             eq(123),
             eq(234),
             eq(345),
@@ -320,7 +387,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct(
+        matches_pattern!(&AStruct(
             eq(123),
             eq(234),
             eq(345),
@@ -342,7 +409,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct(
+        matches_pattern!(&AStruct(
             eq(123),
             eq(234),
             eq(345),
@@ -358,6 +425,29 @@
 }
 
 #[test]
+fn matches_tuple_struct_containing_ten_fields_by_ref() -> Result<()> {
+    #[derive(Debug)]
+    struct AStruct(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32);
+    let actual = AStruct(123, 234, 345, 456, 567, 678, 789, 890, 901, 12);
+
+    verify_that!(
+        actual,
+        matches_pattern!(&AStruct(
+            ref eq(&123),
+            ref eq(&234),
+            ref eq(&345),
+            ref eq(&456),
+            ref eq(&567),
+            ref eq(&678),
+            ref eq(&789),
+            ref eq(&890),
+            ref eq(&901),
+            ref eq(&12)
+        ))
+    )
+}
+
+#[test]
 fn matches_tuple_struct_with_trailing_comma() -> Result<()> {
     #[derive(Debug)]
     struct AStruct(u32);
@@ -365,7 +455,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct(
+        matches_pattern!(&AStruct(
             eq(123), // Keep the trailing comma, block reformatting
         ))
     )
@@ -379,7 +469,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct(
+        matches_pattern!(&AStruct(
             eq(123),
             eq(234), // Keep the trailing comma, block reformatting
         ))
@@ -394,14 +484,30 @@
     }
     let actual = AnEnum::A;
 
+    verify_that!(actual, matches_pattern!(&AnEnum::A))
+}
+
+#[test]
+fn matches_enum_without_field_ref_binding_mode() -> Result<()> {
+    #[derive(Debug)]
+    enum AnEnum {
+        A,
+    }
+    let actual = AnEnum::A;
+
     verify_that!(actual, matches_pattern!(AnEnum::A))
 }
 
-#[rustversion::before(1.76)]
-const ANENUM_A_REPR: &str = "AnEnum :: A";
+#[test]
+fn matches_enum_without_field_copy() -> Result<()> {
+    #[derive(Debug, Clone, Copy)]
+    enum AnEnum {
+        A,
+    }
+    let actual = AnEnum::A;
 
-#[rustversion::since(1.76)]
-const ANENUM_A_REPR: &str = "AnEnum::A";
+    verify_that!(actual, matches_pattern!(AnEnum::A))
+}
 
 #[test]
 fn generates_correct_failure_output_when_enum_variant_without_field_is_not_matched() -> Result<()> {
@@ -413,11 +519,16 @@
     }
     let actual = AnEnum::B;
 
-    let result = verify_that!(actual, matches_pattern!(AnEnum::A));
+    let result = verify_that!(actual, matches_pattern!(&AnEnum::A));
 
-    verify_that!(result, err(displays_as(contains_substring(format!("is not {ANENUM_A_REPR}")))))
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "is not & AnEnum :: A";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "is not &AnEnum::A";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn generates_correct_failure_output_when_enum_variant_without_field_is_matched() -> Result<()> {
     #[derive(Debug)]
@@ -426,11 +537,16 @@
     }
     let actual = AnEnum::A;
 
-    let result = verify_that!(actual, not(matches_pattern!(AnEnum::A)));
+    let result = verify_that!(actual, not(matches_pattern!(&AnEnum::A)));
 
-    verify_that!(result, err(displays_as(contains_substring(format!("is {ANENUM_A_REPR}")))))
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "is & AnEnum :: A";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "is &AnEnum::A";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn matches_enum_with_field() -> Result<()> {
     #[derive(Debug)]
@@ -439,9 +555,8 @@
     }
     let actual = AnEnum::A(123);
 
-    verify_that!(actual, matches_pattern!(AnEnum::A(eq(123))))
+    verify_that!(actual, matches_pattern!(&AnEnum::A(eq(123))))
 }
-
 #[test]
 fn does_not_match_wrong_enum_value() -> Result<()> {
     #[derive(Debug)]
@@ -452,9 +567,8 @@
     }
     let actual = AnEnum::B;
 
-    verify_that!(actual, not(matches_pattern!(AnEnum::A(eq(123)))))
+    verify_that!(actual, not(matches_pattern!(&AnEnum::A(eq(123)))))
 }
-
 #[test]
 fn includes_enum_variant_in_description_with_field() -> Result<()> {
     #[derive(Debug)]
@@ -463,16 +577,16 @@
     }
     let actual = AnEnum::A(123);
 
-    let result = verify_that!(actual, matches_pattern!(AnEnum::A(eq(234))));
+    let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234))));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(format!(
-            "Expected: is {ANENUM_A_REPR} which has field `0`"
-        ))))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AnEnum :: A which has field `0`";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AnEnum::A which has field `0`";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn includes_enum_variant_in_negative_description_with_field() -> Result<()> {
     #[derive(Debug)]
@@ -481,16 +595,16 @@
     }
     let actual = AnEnum::A(123);
 
-    let result = verify_that!(actual, not(matches_pattern!(AnEnum::A(eq(123)))));
+    let result = verify_that!(actual, not(matches_pattern!(&AnEnum::A(eq(123)))));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(format!(
-            "Expected: is not {ANENUM_A_REPR} which has field `0`, which is equal to"
-        ))))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is not & AnEnum :: A which has field `0`, which is equal to";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is not &AnEnum::A which has field `0`, which is equal to";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn includes_enum_variant_in_description_with_two_fields() -> Result<()> {
     #[derive(Debug)]
@@ -499,16 +613,16 @@
     }
     let actual = AnEnum::A(123, 234);
 
-    let result = verify_that!(actual, matches_pattern!(AnEnum::A(eq(234), eq(234))));
+    let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234), eq(234))));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(format!(
-            "Expected: is {ANENUM_A_REPR} which has all the following properties"
-        ))))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AnEnum::A which has all the following properties";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn includes_enum_variant_in_description_with_three_fields() -> Result<()> {
     #[derive(Debug)]
@@ -517,16 +631,16 @@
     }
     let actual = AnEnum::A(123, 234, 345);
 
-    let result = verify_that!(actual, matches_pattern!(AnEnum::A(eq(234), eq(234), eq(345))));
+    let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234), eq(234), eq(345))));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(format!(
-            "Expected: is {ANENUM_A_REPR} which has all the following properties"
-        ))))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AnEnum::A which has all the following properties";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn includes_enum_variant_in_description_with_named_field() -> Result<()> {
     #[derive(Debug)]
@@ -535,16 +649,16 @@
     }
     let actual = AnEnum::A { field: 123 };
 
-    let result = verify_that!(actual, matches_pattern!(AnEnum::A { field: eq(234) }));
+    let result = verify_that!(actual, matches_pattern!(&AnEnum::A { field: eq(234) }));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(format!(
-            "Expected: is {ANENUM_A_REPR} which has field `field`"
-        ))))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AnEnum :: A which has field `field`";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AnEnum::A which has field `field`";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn includes_enum_variant_in_description_with_two_named_fields() -> Result<()> {
     #[derive(Debug)]
@@ -555,17 +669,17 @@
 
     let result = verify_that!(
         actual,
-        matches_pattern!(AnEnum::A { field: eq(234), another_field: eq(234) })
+        matches_pattern!(&AnEnum::A { field: eq(234), another_field: eq(234) })
     );
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(format!(
-            "Expected: is {ANENUM_A_REPR} which has all the following properties"
-        ))))
-    )
-}
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
 
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AnEnum::A which has all the following properties";
+
+    verify_that!(&result, err(displays_as(contains_substring(EXPECTED))))
+}
 #[test]
 fn includes_struct_name_in_description_with_property() -> Result<()> {
     #[derive(Debug)]
@@ -579,16 +693,16 @@
     }
     let actual = AStruct { field: 123 };
 
-    let result = verify_that!(actual, matches_pattern!(AStruct { get_field(): eq(234) }));
+    let result = verify_that!(actual, matches_pattern!(&AStruct { get_field(): eq(234) }));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(
-            "Expected: is AStruct which has property `get_field ()`"
-        )))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AStruct which has property `get_field ()`";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AStruct which has property `get_field ()`";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn includes_struct_name_in_description_with_ref_property() -> Result<()> {
     #[derive(Debug)]
@@ -602,14 +716,15 @@
     }
     let actual = AStruct { field: 123 };
 
-    let result = verify_that!(actual, matches_pattern!(AStruct { *get_field(): eq(234) }));
+    let result = verify_that!(actual, matches_pattern!(&AStruct { get_field(): eq(&234) }));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(
-            "Expected: is AStruct which has property `get_field ()`"
-        )))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AStruct which has property `get_field ()`";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AStruct which has property `get_field ()`";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
 #[test]
@@ -626,14 +741,15 @@
     let actual = AStruct { field: 123 };
 
     let result =
-        verify_that!(actual, matches_pattern!(AStruct { field: eq(123), get_field(): eq(234) }));
+        verify_that!(actual, matches_pattern!(&AStruct { field: eq(123), get_field(): eq(234) }));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(
-            "Expected: is AStruct which has all the following properties"
-        )))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AStruct which has all the following properties";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AStruct which has all the following properties";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
 #[test]
@@ -650,16 +766,16 @@
     let actual = AStruct { field: 123 };
 
     let result =
-        verify_that!(actual, matches_pattern!(AStruct { field: eq(123), *get_field(): eq(234) }));
+        verify_that!(actual, matches_pattern!(&AStruct { field: eq(123), get_field(): eq(&234) }));
 
-    verify_that!(
-        result,
-        err(displays_as(contains_substring(
-            "Expected: is AStruct which has all the following properties"
-        )))
-    )
+    #[rustversion::before(1.76)]
+    const EXPECTED: &str = "Expected: is & AStruct which has all the following properties";
+
+    #[rustversion::since(1.76)]
+    const EXPECTED: &str = "Expected: is &AStruct which has all the following properties";
+
+    verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
-
 #[test]
 fn matches_struct_with_a_method() -> Result<()> {
     #[derive(Debug)]
@@ -675,9 +791,8 @@
 
     let actual = AStruct { a_field: 123 };
 
-    verify_that!(actual, matches_pattern!(AStruct { get_field(): eq(123) }))
+    verify_that!(actual, matches_pattern!(&AStruct { get_field(): eq(123) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_and_trailing_comma() -> Result<()> {
     #[derive(Debug)]
@@ -693,9 +808,8 @@
 
     let actual = AStruct { a_field: 123 };
 
-    verify_that!(actual, matches_pattern!(AStruct { get_field(): eq(123), }))
+    verify_that!(actual, matches_pattern!(&AStruct { get_field(): eq(123), }))
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_parameter() -> Result<()> {
     #[derive(Debug)]
@@ -711,9 +825,8 @@
 
     let actual = AStruct { a_field: 1 };
 
-    verify_that!(actual, matches_pattern!(AStruct { add_to_field(2): eq(3) }))
+    verify_that!(actual, matches_pattern!(&AStruct { add_to_field(2): eq(3) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_two_parameters() -> Result<()> {
     #[derive(Debug)]
@@ -729,9 +842,8 @@
 
     let actual = AStruct { a_field: 1 };
 
-    verify_that!(actual, matches_pattern!(AStruct { add_product_to_field(2, 3): eq(7) }))
+    verify_that!(actual, matches_pattern!(&AStruct { add_product_to_field(2, 3): eq(7) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_enum_value_parameter() -> Result<()> {
     enum AnEnum {
@@ -751,9 +863,8 @@
 
     let actual = AStruct { a_field: 1 };
 
-    verify_that!(actual, matches_pattern!(AStruct { get_a_field(AnEnum::AVariant): eq(1) }))
+    verify_that!(actual, matches_pattern!(&AStruct { get_a_field(AnEnum::AVariant): eq(1) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_two_parameters_with_trailing_comma() -> Result<()> {
     #[derive(Debug)]
@@ -769,9 +880,8 @@
 
     let actual = AStruct { a_field: 1 };
 
-    verify_that!(actual, matches_pattern!(AStruct { add_product_to_field(2, 3,): eq(7) }))
+    verify_that!(actual, matches_pattern!(&AStruct { add_product_to_field(2, 3,): eq(7) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_returning_a_reference() -> Result<()> {
     #[derive(Debug)]
@@ -787,9 +897,8 @@
 
     let actual = AStruct { a_field: 123 };
 
-    verify_that!(actual, matches_pattern!(AStruct { *get_field_ref(): eq(123) }))
+    verify_that!(actual, matches_pattern!(&AStruct { get_field_ref(): eq(&123) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_returning_a_reference_with_trailing_comma() -> Result<()> {
     #[derive(Debug)]
@@ -805,9 +914,8 @@
 
     let actual = AStruct { a_field: 123 };
 
-    verify_that!(actual, matches_pattern!(AStruct { *get_field_ref(): eq(123), }))
+    verify_that!(actual, matches_pattern!(&AStruct { get_field_ref(): eq(&123), }))
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_two_parameters_ret_ref() -> Result<()> {
     #[derive(Debug)]
@@ -823,9 +931,8 @@
 
     let actual = AStruct { a_field: 1 };
 
-    verify_that!(actual, matches_pattern!(AStruct { *get_field_ref(2, 3): eq(1) }))
+    verify_that!(actual, matches_pattern!(&AStruct { get_field_ref(2, 3): eq(&1) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_returning_reference_taking_enum_value_parameter() -> Result<()> {
     enum AnEnum {
@@ -845,9 +952,8 @@
 
     let actual = AStruct { a_field: 1 };
 
-    verify_that!(actual, matches_pattern!(AStruct { *get_field_ref(AnEnum::AVariant): eq(1) }))
+    verify_that!(actual, matches_pattern!(&AStruct { get_field_ref(AnEnum::AVariant): eq(&1) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_two_parameters_with_trailing_comma_ret_ref() -> Result<()> {
     #[derive(Debug)]
@@ -863,9 +969,8 @@
 
     let actual = AStruct { a_field: 1 };
 
-    verify_that!(actual, matches_pattern!(AStruct { *get_field_ref(2, 3,): eq(1) }))
+    verify_that!(actual, matches_pattern!(&AStruct { get_field_ref(2, 3,): eq(&1) }))
 }
-
 #[test]
 fn matches_struct_with_a_method_followed_by_a_field() -> Result<()> {
     #[derive(Debug)]
@@ -882,9 +987,11 @@
 
     let actual = AStruct { a_field: 123, another_field: 234 };
 
-    verify_that!(actual, matches_pattern!(AStruct { get_field(): eq(123), another_field: eq(234) }))
+    verify_that!(
+        actual,
+        matches_pattern!(&AStruct { get_field(): eq(123), another_field: eq(234) })
+    )
 }
-
 #[test]
 fn matches_struct_with_a_method_followed_by_a_field_with_trailing_comma() -> Result<()> {
     #[derive(Debug)]
@@ -903,10 +1010,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { get_field(): eq(123), another_field: eq(234), })
+        matches_pattern!(&AStruct { get_field(): eq(123), another_field: eq(234), })
     )
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_two_parameters_and_field() -> Result<()> {
     #[derive(Debug)]
@@ -925,10 +1031,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { add_product_to_field(2, 3): eq(7), another_field: eq(123) })
+        matches_pattern!(&AStruct { add_product_to_field(2, 3): eq(7), another_field: eq(123) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_enum_value_parameter_followed_by_field() -> Result<()> {
     enum AnEnum {
@@ -951,10 +1056,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { get_field(AnEnum::AVariant): eq(1), another_field: eq(2) })
+        matches_pattern!(&AStruct { get_field(AnEnum::AVariant): eq(1), another_field: eq(2) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_two_parameters_with_trailing_comma_and_field() -> Result<()>
 {
@@ -974,10 +1078,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { add_product_to_field(2, 3,): eq(7), another_field: eq(123) })
+        matches_pattern!(&AStruct { add_product_to_field(2, 3,): eq(7), another_field: eq(123) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_method_returning_reference_followed_by_a_field() -> Result<()> {
     #[derive(Debug)]
@@ -996,13 +1099,12 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { *get_field_ref(): eq(123), another_field: eq(234) })
+        matches_pattern!(&AStruct { get_field_ref(): eq(&123), another_field: eq(234) })
     )
 }
-
 #[test]
-fn matches_struct_with_a_method_returning_reference_followed_by_a_field_with_trailing_comma()
--> Result<()> {
+fn matches_struct_with_a_method_returning_reference_followed_by_a_field_with_trailing_comma(
+) -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
@@ -1019,10 +1121,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { *get_field_ref(): eq(123), another_field: eq(234), })
+        matches_pattern!(&AStruct { get_field_ref(): eq(&123), another_field: eq(234), })
     )
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_two_parameters_ret_ref_and_field() -> Result<()> {
     #[derive(Debug)]
@@ -1041,10 +1142,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { *get_field_ref(2, 3): eq(1), another_field: eq(123) })
+        matches_pattern!(&AStruct { get_field_ref(2, 3): eq(&1), another_field: eq(123) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_method_taking_enum_value_param_ret_ref_followed_by_field() -> Result<()> {
     enum AnEnum {
@@ -1067,13 +1167,12 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { *get_field_ref(AnEnum::AVariant): eq(1), another_field: eq(2) })
+        matches_pattern!(&AStruct { get_field_ref(AnEnum::AVariant): eq(&1), another_field: eq(2) })
     )
 }
-
 #[test]
-fn matches_struct_with_a_method_taking_two_parameters_with_trailing_comma_ret_ref_and_field()
--> Result<()> {
+fn matches_struct_with_a_method_taking_two_parameters_with_trailing_comma_ret_ref_and_field(
+) -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
@@ -1090,10 +1189,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { *get_field_ref(2, 3,): eq(1), another_field: eq(123) })
+        matches_pattern!(&AStruct { get_field_ref(2, 3,): eq(&1), another_field: eq(123) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method() -> Result<()> {
     #[derive(Debug)]
@@ -1110,9 +1208,11 @@
 
     let actual = AStruct { a_field: 123, another_field: 234 };
 
-    verify_that!(actual, matches_pattern!(AStruct { another_field: eq(234), get_field(): eq(123) }))
+    verify_that!(
+        actual,
+        matches_pattern!(&AStruct { another_field: eq(234), get_field(): eq(123) })
+    )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method_with_trailing_comma() -> Result<()> {
     #[derive(Debug)]
@@ -1131,10 +1231,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(234), get_field(): eq(123), })
+        matches_pattern!(&AStruct { another_field: eq(234), get_field(): eq(123), })
     )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method_with_params() -> Result<()> {
     #[derive(Debug)]
@@ -1153,10 +1252,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(234), add_product_to_field(2, 3): eq(7) })
+        matches_pattern!(&AStruct { another_field: eq(234), add_product_to_field(2, 3): eq(7) })
     )
 }
-
 #[test]
 fn matches_struct_with_field_followed_by_method_taking_enum_value_param() -> Result<()> {
     enum AnEnum {
@@ -1179,10 +1277,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(2), get_field(AnEnum::AVariant): eq(1) })
+        matches_pattern!(&AStruct { another_field: eq(2), get_field(AnEnum::AVariant): eq(1) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma() -> Result<()> {
     #[derive(Debug)]
@@ -1201,10 +1298,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(234), add_product_to_field(2, 3,): eq(7) })
+        matches_pattern!(&AStruct { another_field: eq(234), add_product_to_field(2, 3,): eq(7) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method_returning_reference() -> Result<()> {
     #[derive(Debug)]
@@ -1223,10 +1319,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(234), *get_field_ref(): eq(123) })
+        matches_pattern!(&AStruct { another_field: eq(234), get_field_ref(): eq(&123) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method_returning_ref_and_trailing_comma() -> Result<()>
 {
@@ -1246,10 +1341,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(234), *get_field_ref(): eq(123), })
+        matches_pattern!(&AStruct { another_field: eq(234), get_field_ref(): eq(&123), })
     )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method_with_params_ret_ref() -> Result<()> {
     #[derive(Debug)]
@@ -1268,10 +1362,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(234), *get_field_ref(2, 3): eq(123) })
+        matches_pattern!(&AStruct { another_field: eq(234), get_field_ref(2, 3): eq(&123) })
     )
 }
-
 #[test]
 fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref() -> Result<()> {
     enum AnEnum {
@@ -1294,13 +1387,12 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(2), *get_field_ref(AnEnum::AVariant): eq(1) })
+        matches_pattern!(&AStruct { another_field: eq(2), get_field_ref(AnEnum::AVariant): eq(&1) })
     )
 }
-
 #[test]
-fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma_ret_ref()
--> Result<()> {
+fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma_ret_ref(
+) -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
@@ -1317,10 +1409,9 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct { another_field: eq(234), *get_field_ref(2, 3,): eq(123) })
+        matches_pattern!(&AStruct { another_field: eq(234), get_field_ref(2, 3,): eq(&123) })
     )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method_followed_by_a_field() -> Result<()> {
     #[derive(Debug)]
@@ -1340,17 +1431,16 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(234),
             get_field(): eq(123),
             a_third_field: eq(345)
         })
     )
 }
-
 #[test]
-fn matches_struct_with_a_field_followed_by_a_method_followed_by_a_field_with_trailing_comma()
--> Result<()> {
+fn matches_struct_with_a_field_followed_by_a_method_followed_by_a_field_with_trailing_comma(
+) -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
@@ -1368,14 +1458,13 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(234),
             get_field(): eq(123),
             a_third_field: eq(345),
         })
     )
 }
-
 #[test]
 fn matches_struct_with_a_field_followed_by_a_method_with_params_followed_by_a_field() -> Result<()>
 {
@@ -1396,7 +1485,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(234),
             add_product_to_field(2, 3): eq(7),
             a_third_field: eq(345),
@@ -1405,8 +1494,8 @@
 }
 
 #[test]
-fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma_followed_by_a_field()
--> Result<()> {
+fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma_followed_by_a_field(
+) -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
@@ -1424,7 +1513,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(234),
             add_product_to_field(2, 3,): eq(7),
             a_third_field: eq(345),
@@ -1433,8 +1522,8 @@
 }
 
 #[test]
-fn matches_struct_with_field_followed_by_method_taking_enum_value_param_followed_by_field()
--> Result<()> {
+fn matches_struct_with_field_followed_by_method_taking_enum_value_param_followed_by_field(
+) -> Result<()> {
     enum AnEnum {
         AVariant,
     }
@@ -1456,7 +1545,7 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(2),
             get_field(AnEnum::AVariant): eq(1),
             a_third_field: eq(3),
@@ -1483,17 +1572,17 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(234),
-            *get_field_ref(): eq(123),
+            get_field_ref(): eq(&123),
             a_third_field: eq(345)
         })
     )
 }
 
 #[test]
-fn matches_struct_with_a_field_followed_by_a_method_ret_ref_followed_by_a_field_with_trailing_comma()
--> Result<()> {
+fn matches_struct_with_a_field_followed_by_a_method_ret_ref_followed_by_a_field_with_trailing_comma(
+) -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
@@ -1511,17 +1600,17 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(234),
-            *get_field_ref(): eq(123),
+            get_field_ref(): eq(&123),
             a_third_field: eq(345),
         })
     )
 }
 
 #[test]
-fn matches_struct_with_a_field_followed_by_a_method_with_params_ret_ref_followed_by_a_field()
--> Result<()> {
+fn matches_struct_with_a_field_followed_by_a_method_with_params_ret_ref_followed_by_a_field(
+) -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
@@ -1539,17 +1628,17 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(234),
-            *get_field_ref(2, 3): eq(123),
+            get_field_ref(2, 3): eq(&123),
             a_third_field: eq(345),
         })
     )
 }
 
 #[test]
-fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref_followed_by_field()
--> Result<()> {
+fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref_followed_by_field(
+) -> Result<()> {
     enum AnEnum {
         AVariant,
     }
@@ -1571,17 +1660,17 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(2),
-            *get_field_ref(AnEnum::AVariant): eq(1),
+            get_field_ref(AnEnum::AVariant): eq(&1),
             a_third_field: eq(3),
         })
     )
 }
 
 #[test]
-fn matches_struct_with_a_field_followed_by_a_method_with_params_trailing_comma_ret_ref_followed_by_a_field()
--> Result<()> {
+fn matches_struct_with_a_field_followed_by_a_method_with_params_trailing_comma_ret_ref_followed_by_a_field(
+) -> Result<()> {
     #[derive(Debug)]
     struct AStruct {
         a_field: u32,
@@ -1599,10 +1688,129 @@
 
     verify_that!(
         actual,
-        matches_pattern!(AStruct {
+        matches_pattern!(&AStruct {
             another_field: eq(234),
-            *get_field_ref(2, 3,): eq(123),
+            get_field_ref(2, 3,): eq(&123),
             a_third_field: eq(345),
         })
     )
 }
+
+#[test]
+fn matches_struct_field_copy() -> Result<()> {
+    #[derive(Debug)]
+    struct AStruct {
+        a_field: u32,
+    }
+
+    let actual = AStruct { a_field: 123 };
+
+    verify_that!(actual, matches_pattern!(&AStruct { a_field: eq(123) }))
+}
+
+#[test]
+fn matches_struct_field_non_copy() -> Result<()> {
+    #[derive(Debug)]
+    struct AStruct {
+        a_field: String,
+    }
+
+    let actual = AStruct { a_field: "123".into() };
+
+    verify_that!(
+        actual,
+        matches_pattern!(&AStruct {
+            a_field: ref eq("123"),
+        })
+    )
+}
+
+#[test]
+fn matches_copy_struct_field_copy() -> Result<()> {
+    #[derive(Debug, Clone, Copy)]
+    struct AStruct {
+        a_field: i32,
+    }
+
+    let actual = AStruct { a_field: 123 };
+
+    verify_that!(actual, matches_pattern!(AStruct { a_field: eq(123) }))
+}
+
+#[test]
+fn matches_struct_property_copy() -> Result<()> {
+    #[derive(Debug)]
+    struct AStruct;
+
+    impl AStruct {
+        fn prop(&self) -> i32 {
+            123
+        }
+    }
+
+    let actual = AStruct;
+
+    verify_that!(actual, matches_pattern!(&AStruct { prop(): eq(123) }))
+}
+
+#[test]
+fn matches_struct_property_non_copy() -> Result<()> {
+    #[derive(Debug)]
+    struct AStruct;
+
+    impl AStruct {
+        fn prop(&self) -> String {
+            "123".into()
+        }
+    }
+
+    let actual = AStruct;
+
+    verify_that!(actual, matches_pattern!(&AStruct { prop(): ref eq("123") }))
+}
+
+#[test]
+fn matches_copy_struct_property_copy() -> Result<()> {
+    #[derive(Debug, Clone, Copy)]
+    struct AStruct;
+
+    impl AStruct {
+        fn prop(self) -> i32 {
+            123
+        }
+    }
+
+    let actual = AStruct;
+
+    verify_that!(actual, matches_pattern!(AStruct { prop(): eq(123) }))
+}
+
+#[test]
+fn matches_copy_struct_property_non_copy() -> Result<()> {
+    #[derive(Debug, Clone, Copy)]
+    struct AStruct;
+
+    impl AStruct {
+        fn prop(self) -> String {
+            "123".into()
+        }
+    }
+    let actual = AStruct;
+
+    verify_that!(actual, matches_pattern!(AStruct { prop(): ref eq("123") }))
+}
+
+#[test]
+fn matches_struct_auto_eq() -> Result<()> {
+    #[derive(Debug, Clone)]
+    struct AStruct {
+        int: i32,
+        string: String,
+        option: Option<i32>,
+    }
+
+    verify_that!(
+        AStruct { int: 123, string: "123".into(), option: Some(123) },
+        matches_pattern!(&AStruct { int: 123, string: ref "123", option: Some(123) })
+    )
+}
diff --git a/crates/googletest/tests/no_color_test.rs b/crates/googletest/tests/no_color_test.rs
index f307890..84e4cad 100644
--- a/crates/googletest/tests/no_color_test.rs
+++ b/crates/googletest/tests/no_color_test.rs
@@ -12,10 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#![cfg(feature = "supports-color")]
-
 use googletest::prelude::*;
-use indoc::indoc;
 use std::fmt::{Display, Write};
 
 // Make a long text with each element of the iterator on one line.
@@ -35,20 +32,19 @@
     std::env::set_var("NO_COLOR", "1");
     std::env::set_var("FORCE_COLOR", "1");
 
-    let result = verify_that!(build_text(1..50), eq(build_text(1..51)));
+    let result = verify_that!(build_text(1..50), eq(&build_text(1..51)));
 
     verify_that!(
         result,
-        err(displays_as(contains_substring(indoc! {
+        err(displays_as(contains_substring(
             "
-
-            Difference(-actual / +expected):
-             1
-             2
-             <---- 45 common lines omitted ---->
-             48
-             49
-            +50"
-        })))
+  Difference(-actual / +expected):
+   1
+   2
+   <---- 45 common lines omitted ---->
+   48
+   49
+  +50"
+        )))
     )
 }
diff --git a/crates/googletest/tests/pointwise_matcher_test.rs b/crates/googletest/tests/pointwise_matcher_test.rs
index cb8ef3b..b7fd7c5 100644
--- a/crates/googletest/tests/pointwise_matcher_test.rs
+++ b/crates/googletest/tests/pointwise_matcher_test.rs
@@ -18,44 +18,64 @@
 #[test]
 fn pointwise_matches_single_element() -> Result<()> {
     let value = vec![1];
-    verify_that!(value, pointwise!(lt, vec![2]))
+    verify_that!(value, pointwise!(lt, vec![&2]))
 }
 
 #[test]
 fn pointwise_matches_two_elements() -> Result<()> {
     let value = vec![1, 2];
-    verify_that!(value, pointwise!(lt, vec![2, 3]))
+    verify_that!(value, pointwise!(|x| points_to(lt(x)), vec![2, 3]))
+}
+
+#[test]
+fn pointwise_matches_iterator_returning_by_value() -> Result<()> {
+    #[derive(Clone, Copy, Debug)]
+    struct Countdown(i32);
+    impl Iterator for Countdown {
+        type Item = i32;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            match self.0 {
+                0 => None,
+                x => {
+                    self.0 -= 1;
+                    Some(x)
+                }
+            }
+        }
+    }
+    verify_that!(Countdown(3), pointwise!(eq, vec![3, 2, 1]))
 }
 
 #[test]
 fn pointwise_matches_two_elements_with_array() -> Result<()> {
     let value = vec![1, 2];
-    verify_that!(value, pointwise!(lt, [2, 3]))
+    verify_that!(value, pointwise!(lt, [&2, &3]))
 }
 
 #[test]
 fn pointwise_matches_two_element_slice() -> Result<()> {
     let value = vec![1, 2];
     let slice = value.as_slice();
-    verify_that!(*slice, pointwise!(lt, [2, 3]))
+    verify_that!(slice, pointwise!(lt, [&2, &3]))
 }
 
 #[test]
 fn pointwise_does_not_match_value_of_wrong_length() -> Result<()> {
     let value = vec![1];
-    verify_that!(value, not(pointwise!(lt, vec![2, 3])))
+    verify_that!(value, not(pointwise!(lt, vec![&2, &3])))
 }
 
 #[test]
 fn pointwise_does_not_match_value_not_matching_in_first_position() -> Result<()> {
     let value = vec![1, 2];
-    verify_that!(value, not(pointwise!(lt, vec![1, 3])))
+    verify_that!(value, not(pointwise!(lt, vec![&1, &3])))
 }
 
 #[test]
 fn pointwise_does_not_match_value_not_matching_in_second_position() -> Result<()> {
     let value = vec![1, 2];
-    verify_that!(value, not(pointwise!(lt, vec![2, 2])))
+    verify_that!(value, not(pointwise!(lt, vec![&2, &2])))
 }
 
 #[test]
@@ -64,12 +84,12 @@
         pub(super) use super::lt;
     }
     let value = vec![1];
-    verify_that!(value, pointwise!(submodule::lt, vec![2]))
+    verify_that!(value, pointwise!(submodule::lt, vec![&2]))
 }
 
 #[test]
 fn pointwise_returns_mismatch_when_actual_value_has_wrong_length() -> Result<()> {
-    let result = verify_that!(vec![1, 2, 3], pointwise!(eq, vec![1, 2]));
+    let result = verify_that!(vec![1, 2, 3], pointwise!(eq, vec![&1, &2]));
 
     verify_that!(
         result,
@@ -88,7 +108,7 @@
 
 #[test]
 fn pointwise_returns_mismatch_when_actual_value_does_not_match_on_first_item() -> Result<()> {
-    let result = verify_that!(vec![1, 2, 3], pointwise!(eq, vec![2, 2, 3]));
+    let result = verify_that!(vec![1, 2, 3], pointwise!(eq, vec![&2, &2, &3]));
 
     verify_that!(
         result,
@@ -108,7 +128,7 @@
 
 #[test]
 fn pointwise_returns_mismatch_when_actual_value_does_not_match_on_second_item() -> Result<()> {
-    let result = verify_that!(vec![1, 2, 3], pointwise!(eq, vec![1, 3, 3]));
+    let result = verify_that!(vec![1, 2, 3], pointwise!(eq, &vec![1, 3, 3]));
 
     verify_that!(
         result,
@@ -127,9 +147,9 @@
 }
 
 #[test]
-fn pointwise_returns_mismatch_when_actual_value_does_not_match_on_first_and_second_items()
--> Result<()> {
-    let result = verify_that!(vec![1, 2, 3], pointwise!(eq, vec![2, 3, 3]));
+fn pointwise_returns_mismatch_when_actual_value_does_not_match_on_first_and_second_items(
+) -> Result<()> {
+    let result = verify_that!(vec![1, 2, 3], pointwise!(eq, &vec![2, 3, 3]));
 
     verify_that!(
         result,
@@ -150,21 +170,21 @@
 
 #[test]
 fn pointwise_matches_single_element_with_lambda_expression_with_extra_value() -> Result<()> {
-    let value = vec![1.00001f32];
+    let value = [1.00001f32];
     verify_that!(value, pointwise!(|v| near(v, 0.0001), vec![1.0]))
 }
 
 #[test]
 fn pointwise_matches_single_element_with_two_containers() -> Result<()> {
-    let value = vec![1.00001f32];
+    let value = [1.00001f32];
     verify_that!(value, pointwise!(near, vec![1.0], vec![0.0001]))
 }
 
 #[test]
 fn pointwise_matches_single_element_with_three_containers() -> Result<()> {
-    let value = vec![1.00001f32];
+    let value = [1.00001f32];
     verify_that!(
         value,
-        pointwise!(|v, t, u| near(v, t * u), vec![1.0f32], vec![0.0001f32], vec![0.5f32])
+        pointwise!(|v, t, u| near(v, t + u), vec![1.0f32], vec![0.0001f32], vec![0.5f32])
     )
 }
diff --git a/crates/googletest/tests/property_matcher_test.rs b/crates/googletest/tests/property_matcher_test.rs
index 7092446..3c9043d 100644
--- a/crates/googletest/tests/property_matcher_test.rs
+++ b/crates/googletest/tests/property_matcher_test.rs
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use googletest::matcher::{Matcher, MatcherResult};
+use googletest::matcher::MatcherResult;
 use googletest::prelude::*;
 
 #[derive(Debug)]
@@ -41,33 +41,25 @@
 #[test]
 fn matches_struct_with_matching_property() -> Result<()> {
     let value = SomeStruct { a_property: 10 };
-    verify_that!(value, property!(SomeStruct.get_property(), eq(10)))
+    verify_that!(value, property!(&SomeStruct.get_property(), eq(10)))
 }
 
 #[test]
 fn matches_struct_with_matching_property_with_parameters() -> Result<()> {
     let value = SomeStruct { a_property: 10 };
-    verify_that!(value, property!(SomeStruct.add_product_to_field(2, 3), eq(16)))
-}
-
-#[test]
-fn matches_struct_with_matching_property_with_captured_arguments() -> Result<()> {
-    let value = SomeStruct { a_property: 10 };
-    let arg1 = 2;
-    let arg2 = 3;
-    verify_that!(value, property!(SomeStruct.add_product_to_field(arg1, arg2), eq(16)))
+    verify_that!(value, property!(&SomeStruct.add_product_to_field(2, 3), eq(16)))
 }
 
 #[test]
 fn matches_struct_with_matching_property_with_parameters_with_trailing_comma() -> Result<()> {
     let value = SomeStruct { a_property: 10 };
-    verify_that!(value, property!(SomeStruct.add_product_to_field(2, 3,), eq(16)))
+    verify_that!(value, property!(&SomeStruct.add_product_to_field(2, 3,), eq(16)))
 }
 
 #[test]
 fn matches_struct_with_matching_property_ref() -> Result<()> {
     let value = SomeStruct { a_property: 10 };
-    verify_that!(value, property!(*SomeStruct.get_property_ref(), eq(10)))
+    verify_that!(value, property!(&SomeStruct.get_property_ref(), eq(&10)))
 }
 
 #[test]
@@ -82,7 +74,7 @@
         }
     }
     let value = StructWithString { property: "Something".into() };
-    verify_that!(value, property!(*StructWithString.get_property_ref(), eq("Something")))
+    verify_that!(value, property!(&StructWithString.get_property_ref(), eq("Something")))
 }
 
 #[test]
@@ -97,31 +89,31 @@
         }
     }
     let value = StructWithVec { property: vec![1, 2, 3] };
-    verify_that!(value, property!(*StructWithVec.get_property_ref(), eq([1, 2, 3])))
+    verify_that!(value, property!(&StructWithVec.get_property_ref(), eq([1, 2, 3])))
 }
 
 #[test]
 fn matches_struct_with_matching_property_ref_with_parameters() -> Result<()> {
     let value = SomeStruct { a_property: 10 };
-    verify_that!(value, property!(*SomeStruct.get_property_ref_with_params(2, 3), eq(10)))
+    verify_that!(value, property!(&SomeStruct.get_property_ref_with_params(2, 3), eq(&10)))
 }
 
 #[test]
 fn matches_struct_with_matching_property_ref_with_parameters_and_trailing_comma() -> Result<()> {
     let value = SomeStruct { a_property: 10 };
-    verify_that!(value, property!(*SomeStruct.get_property_ref_with_params(2, 3,), eq(10)))
+    verify_that!(value, property!(&SomeStruct.get_property_ref_with_params(2, 3,), eq(&10)))
 }
 
 #[test]
 fn does_not_match_struct_with_non_matching_property() -> Result<()> {
     let value = SomeStruct { a_property: 2 };
-    verify_that!(value, not(property!(SomeStruct.get_property(), eq(1))))
+    verify_that!(value, not(property!(&SomeStruct.get_property(), eq(1))))
 }
 
 #[test]
 fn describes_itself_in_matching_case() -> Result<()> {
     verify_that!(
-        property!(SomeStruct.get_property(), eq(1)).describe(MatcherResult::Match),
+        property!(&SomeStruct.get_property(), eq(1)).describe(MatcherResult::Match),
         displays_as(eq("has property `get_property()`, which is equal to 1"))
     )
 }
@@ -129,20 +121,44 @@
 #[test]
 fn describes_itself_in_not_matching_case() -> Result<()> {
     verify_that!(
-        property!(SomeStruct.get_property(), eq(1)).describe(MatcherResult::NoMatch),
+        property!(&SomeStruct.get_property(), eq(1)).describe(MatcherResult::NoMatch),
         displays_as(eq("has property `get_property()`, which isn't equal to 1"))
     )
 }
 
 #[test]
 fn explains_mismatch_referencing_explanation_of_inner_matcher() -> Result<()> {
+    #[derive(Debug)]
+    struct SomeStruct;
+
     impl SomeStruct {
         fn get_a_collection(&self) -> Vec<u32> {
             vec![]
         }
     }
-    let value = SomeStruct { a_property: 2 };
-    let result = verify_that!(value, property!(SomeStruct.get_a_collection(), container_eq([1])));
+    let value = SomeStruct;
+    let result =
+        verify_that!(value, property!(&SomeStruct.get_a_collection(), ref container_eq([1])));
+
+    verify_that!(
+        result,
+        err(displays_as(contains_substring(
+            "whose property `get_a_collection()` is `[]`, which is missing the element 1"
+        )))
+    )
+}
+
+#[test]
+fn explains_mismatch_referencing_explanation_of_inner_matcher_binding_mode() -> Result<()> {
+    #[derive(Debug)]
+    struct SomeStruct;
+    impl SomeStruct {
+        fn get_a_collection(&self) -> Vec<u32> {
+            vec![]
+        }
+    }
+    let result =
+        verify_that!(SomeStruct, property!(SomeStruct.get_a_collection(), container_eq([1])));
 
     verify_that!(
         result,
@@ -155,7 +171,7 @@
 #[test]
 fn describes_itself_in_matching_case_for_ref() -> Result<()> {
     verify_that!(
-        property!(*SomeStruct.get_property_ref(), eq(1)).describe(MatcherResult::Match),
+        property!(&SomeStruct.get_property_ref(), eq(&1)).describe(MatcherResult::Match),
         displays_as(eq("has property `get_property_ref()`, which is equal to 1"))
     )
 }
@@ -163,7 +179,7 @@
 #[test]
 fn describes_itself_in_not_matching_case_for_ref() -> Result<()> {
     verify_that!(
-        property!(*SomeStruct.get_property_ref(), eq(1)).describe(MatcherResult::NoMatch),
+        property!(&SomeStruct.get_property_ref(), eq(&1)).describe(MatcherResult::NoMatch),
         displays_as(eq("has property `get_property_ref()`, which isn't equal to 1"))
     )
 }
@@ -171,14 +187,16 @@
 #[test]
 fn explains_mismatch_referencing_explanation_of_inner_matcher_for_ref() -> Result<()> {
     static EMPTY_COLLECTION: Vec<u32> = vec![];
+    #[derive(Debug)]
+    struct SomeStruct;
     impl SomeStruct {
         fn get_a_collection_ref(&self) -> &[u32] {
             &EMPTY_COLLECTION
         }
     }
-    let value = SomeStruct { a_property: 2 };
+    let value = SomeStruct;
     let result =
-        verify_that!(value, property!(*SomeStruct.get_a_collection_ref(), container_eq([1])));
+        verify_that!(value, property!(&SomeStruct.get_a_collection_ref(), container_eq([1])));
 
     verify_that!(
         result,
@@ -187,3 +205,94 @@
         )))
     )
 }
+
+#[test]
+fn matches_copy_to_copy() -> Result<()> {
+    #[derive(Debug, Clone, Copy)]
+    struct Struct;
+    impl Struct {
+        fn property(self) -> i32 {
+            32
+        }
+    }
+
+    verify_that!(Struct, property!(Struct.property(), eq(32)))
+}
+
+#[test]
+fn matches_copy_to_ref() -> Result<()> {
+    #[derive(Debug, Clone, Copy)]
+    struct Struct;
+    impl Struct {
+        fn property(self) -> String {
+            "something".into()
+        }
+    }
+
+    verify_that!(Struct, property!(Struct.property(), ref eq("something")))
+}
+
+#[test]
+fn matches_copy_but_by_ref() -> Result<()> {
+    #[derive(Debug, Clone, Copy)]
+    struct Struct;
+    impl Struct {
+        fn property(&self) -> String {
+            "something".into()
+        }
+    }
+
+    verify_that!(&Struct, property!(&Struct.property(), ref eq("something")))
+}
+
+#[test]
+fn matches_ref_to_ref() -> Result<()> {
+    #[derive(Debug)]
+    struct Struct;
+    impl Struct {
+        fn property(&self) -> String {
+            "something".into()
+        }
+    }
+
+    verify_that!(Struct, property!(&Struct.property(), ref eq("something")))
+}
+
+#[test]
+fn matches_ref_to_copy() -> Result<()> {
+    #[derive(Debug)]
+    struct Struct;
+    impl Struct {
+        fn property(&self) -> i32 {
+            32
+        }
+    }
+
+    verify_that!(Struct, property!(&Struct.property(), eq(32)))
+}
+
+#[test]
+fn matches_ref_to_ref_with_binding_mode() -> Result<()> {
+    #[derive(Debug)]
+    struct Struct;
+    impl Struct {
+        fn property(&self) -> String {
+            "something".into()
+        }
+    }
+
+    verify_that!(Struct, property!(Struct.property(), eq("something")))
+}
+
+#[test]
+fn matches_property_auto_eq() -> Result<()> {
+    #[derive(Debug)]
+    struct Struct;
+    impl Struct {
+        fn property(&self) -> String {
+            "something".into()
+        }
+    }
+
+    verify_that!(Struct, property!(Struct.property(), "something"))
+}
diff --git a/crates/googletest/tests/tuple_matcher_test.rs b/crates/googletest/tests/tuple_matcher_test.rs
index a93ffee..a19e6fd 100644
--- a/crates/googletest/tests/tuple_matcher_test.rs
+++ b/crates/googletest/tests/tuple_matcher_test.rs
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use googletest::matcher::{Matcher, MatcherResult};
+use googletest::matcher::MatcherResult;
 use googletest::prelude::*;
 use indoc::indoc;
 
@@ -22,6 +22,12 @@
 }
 
 #[test]
+fn empty_matcher_matches_empty_tuple_reference() -> Result<()> {
+    let a_ok: std::result::Result<(), String> = Ok(()); // Non copy
+    verify_that!(a_ok, ok(()))
+}
+
+#[test]
 fn singleton_matcher_matches_matching_singleton_tuple() -> Result<()> {
     verify_that!((123,), (eq(123),))
 }
@@ -176,7 +182,7 @@
 #[test]
 fn tuple_matcher_1_has_correct_description_for_match() -> Result<()> {
     verify_that!(
-        (eq::<i32, _>(1),).describe(MatcherResult::Match),
+        Matcher::<(i32,)>::describe(&(eq(1),), MatcherResult::Match),
         displays_as(eq(indoc!(
             "
             is a tuple whose values respectively match:
@@ -188,7 +194,7 @@
 #[test]
 fn tuple_matcher_1_has_correct_description_for_mismatch() -> Result<()> {
     verify_that!(
-        (eq::<i32, _>(1),).describe(MatcherResult::NoMatch),
+        Matcher::<(i32,)>::describe(&(eq(1),), MatcherResult::NoMatch),
         displays_as(eq(indoc!(
             "
             is a tuple whose values do not respectively match:
@@ -200,7 +206,7 @@
 #[test]
 fn tuple_matcher_2_has_correct_description_for_match() -> Result<()> {
     verify_that!(
-        (eq::<i32, _>(1), eq::<i32, _>(2)).describe(MatcherResult::Match),
+        Matcher::<(i32, i32)>::describe(&(eq(1), eq(2)), MatcherResult::Match),
         displays_as(eq(indoc!(
             "
             is a tuple whose values respectively match:
@@ -213,7 +219,7 @@
 #[test]
 fn tuple_matcher_2_has_correct_description_for_mismatch() -> Result<()> {
     verify_that!(
-        (eq::<i32, _>(1), eq::<i32, _>(2)).describe(MatcherResult::NoMatch),
+        Matcher::<(i32, i32)>::describe(&(eq(1), eq(2)), MatcherResult::NoMatch),
         displays_as(eq(indoc!(
             "
             is a tuple whose values do not respectively match:
@@ -226,7 +232,7 @@
 #[test]
 fn describe_match_shows_which_tuple_element_did_not_match() -> Result<()> {
     verify_that!(
-        (eq(1), eq(2)).explain_match(&(1, 3)),
+        (eq(1), eq(2)).explain_match((1, 3)),
         displays_as(eq(indoc!(
             "
             which
@@ -242,7 +248,7 @@
 #[test]
 fn describe_match_shows_which_two_tuple_elements_did_not_match() -> Result<()> {
     verify_that!(
-        (eq(1), eq(2)).explain_match(&(2, 3)),
+        (eq(1), eq(2)).explain_match((2, 3)),
         displays_as(eq(indoc!(
             "
             which
diff --git a/crates/googletest/tests/unordered_elements_are_matcher_test.rs b/crates/googletest/tests/unordered_elements_are_matcher_test.rs
index bd61417..0678b0c 100644
--- a/crates/googletest/tests/unordered_elements_are_matcher_test.rs
+++ b/crates/googletest/tests/unordered_elements_are_matcher_test.rs
@@ -12,7 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use googletest::matcher::Matcher;
 use googletest::prelude::*;
 use indoc::indoc;
 use std::collections::HashMap;
@@ -32,20 +31,40 @@
 #[test]
 fn unordered_elements_are_matches_vector() -> Result<()> {
     let value = vec![1, 2, 3];
-    verify_that!(value, unordered_elements_are![eq(1), eq(2), eq(3)])
+    verify_that!(value, unordered_elements_are![eq(&1), eq(&2), eq(&3)])
+}
+
+#[test]
+fn unordered_elements_are_matches_iterator_returning_by_value() -> Result<()> {
+    #[derive(Debug, Copy, Clone)]
+    struct Countdown(i32);
+    impl Iterator for Countdown {
+        type Item = i32;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            match self.0 {
+                0 => None,
+                x => {
+                    self.0 -= 1;
+                    Some(x)
+                }
+            }
+        }
+    }
+    verify_that!(Countdown(3), unordered_elements_are![eq(1), eq(2), eq(3)])
 }
 
 #[test]
 fn unordered_elements_are_omitted() -> Result<()> {
     let value = vec![1, 2, 3];
-    verify_that!(value, {eq(3), eq(2), eq(1)})
+    verify_that!(value, {eq(&3), eq(&2), eq(&1)})
 }
 
 #[test]
 fn unordered_elements_are_matches_slice() -> Result<()> {
     let value = vec![1, 2, 3];
     let slice = value.as_slice();
-    verify_that!(*slice, unordered_elements_are![eq(1), eq(2), eq(3)])
+    verify_that!(slice, unordered_elements_are![eq(&1), eq(&2), eq(&3)])
 }
 
 #[test]
@@ -53,7 +72,7 @@
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
     verify_that!(
         value,
-        unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))]
+        unordered_elements_are![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three"))]
     )
 }
 
@@ -62,7 +81,7 @@
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
     verify_that!(
         value,
-        unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three")),]
+        unordered_elements_are![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three")),]
     )
 }
 
@@ -71,7 +90,11 @@
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (4, "Three")]);
     verify_that!(
         value,
-        not(unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))])
+        not(unordered_elements_are![
+            (eq(&2), eq(&"Two")),
+            (eq(&1), eq(&"One")),
+            (eq(&3), eq(&"Three"))
+        ])
     )
 }
 
@@ -80,7 +103,11 @@
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Four")]);
     verify_that!(
         value,
-        not(unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))])
+        not(unordered_elements_are![
+            (eq(&2), eq(&"Two")),
+            (eq(&1), eq(&"One")),
+            (eq(&3), eq(&"Three"))
+        ])
     )
 }
 
@@ -89,14 +116,18 @@
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two")]);
     verify_that!(
         value,
-        not(unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))])
+        not(unordered_elements_are![
+            (eq(&2), eq(&"Two")),
+            (eq(&1), eq(&"One")),
+            (eq(&3), eq(&"Three"))
+        ])
     )
 }
 
 #[test]
 fn unordered_elements_are_does_not_match_hash_map_with_extra_element() -> Result<()> {
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
-    verify_that!(value, not(unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One"))]))
+    verify_that!(value, not(unordered_elements_are![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One"))]))
 }
 
 #[test]
@@ -104,20 +135,24 @@
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Three"), (3, "Two")]);
     verify_that!(
         value,
-        not(unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))])
+        not(unordered_elements_are![
+            (eq(&2), eq(&"Two")),
+            (eq(&1), eq(&"One")),
+            (eq(&3), eq(&"Three"))
+        ])
     )
 }
 
 #[test]
 fn unordered_elements_are_matches_vector_with_trailing_comma() -> Result<()> {
     let value = vec![1, 2, 3];
-    verify_that!(value, unordered_elements_are![eq(1), eq(2), eq(3),])
+    verify_that!(value, unordered_elements_are![eq(&1), eq(&2), eq(&3),])
 }
 
 #[test]
 fn unordered_elements_are_matches_size() -> Result<()> {
     let value = vec![1, 2];
-    verify_that!(value, not(unordered_elements_are![eq(1), eq(2), eq(3)]))
+    verify_that!(value, not(unordered_elements_are![eq(&1), eq(&2), eq(&3)]))
 }
 
 #[test]
@@ -125,7 +160,7 @@
     #[derive(Debug, PartialEq)]
     struct AStruct(i32);
     let expected_value = AStruct(123);
-    verify_that!(vec![AStruct(123)], unordered_elements_are![eq_deref_of(&expected_value)])
+    verify_that!(vec![AStruct(123)], unordered_elements_are![eq(&expected_value)])
 }
 
 #[test]
@@ -135,13 +170,13 @@
     let expected_value = AStruct(123);
     verify_that!(
         HashMap::from([(1, AStruct(123))]),
-        unordered_elements_are![(eq(1), eq_deref_of(&expected_value))]
+        unordered_elements_are![(eq(&1), eq(&expected_value))]
     )
 }
 
 #[test]
 fn unordered_elements_are_description_mismatch() -> Result<()> {
-    let result = verify_that!(vec![1, 4, 3], unordered_elements_are![eq(1), eq(2), eq(3)]);
+    let result = verify_that!(vec![1, 4, 3], unordered_elements_are![eq(&1), eq(&2), eq(&3)]);
     verify_that!(
         result,
         err(displays_as(contains_substring(indoc!(
@@ -160,27 +195,29 @@
 #[test]
 fn unordered_elements_are_matches_unordered() -> Result<()> {
     let value = vec![1, 2];
-    verify_that!(value, unordered_elements_are![eq(2), eq(1)])
+    verify_that!(value, unordered_elements_are![eq(&2), eq(&1)])
 }
 
 #[test]
 fn unordered_elements_are_matches_unordered_with_repetition() -> Result<()> {
     let value = vec![1, 2, 1, 2, 1];
-    verify_that!(value, unordered_elements_are![eq(1), eq(1), eq(1), eq(2), eq(2)])
+    verify_that!(value, unordered_elements_are![eq(&1), eq(&1), eq(&1), eq(&2), eq(&2)])
 }
 
 #[test]
 fn unordered_elements_are_explains_mismatch_due_to_wrong_size() -> Result<()> {
+    let matcher = unordered_elements_are![eq(&2), eq(&3), eq(&4)];
     verify_that!(
-        unordered_elements_are![eq(2), eq(3), eq(4)].explain_match(&vec![2, 3]),
+        matcher.explain_match(&vec![2, 3]),
         displays_as(eq("which has size 2 (expected 3)"))
     )
 }
 
 #[test]
 fn unordered_elements_are_description_no_full_match() -> Result<()> {
+    let matcher = unordered_elements_are![eq(&1), eq(&2), eq(&2)];
     verify_that!(
-        unordered_elements_are![eq(1), eq(2), eq(2)].explain_match(&vec![1, 1, 2]),
+        matcher.explain_match(&vec![1, 1, 2]),
         displays_as(eq(indoc!(
             "
             which does not have a perfect match with the expected elements. The best match found was:
@@ -194,22 +231,24 @@
 
 #[test]
 fn unordered_elements_are_unmatchable_expected_description_mismatch() -> Result<()> {
+    let matcher = unordered_elements_are![eq(&1), eq(&2), eq(&3)];
     verify_that!(
-        unordered_elements_are![eq(1), eq(2), eq(3)].explain_match(&vec![1, 1, 3]),
+        matcher.explain_match(&vec![1, 1, 3]),
         displays_as(eq("which has no element matching the expected element #1"))
     )
 }
 
 #[test]
 fn unordered_elements_are_unmatchable_actual_description_mismatch() -> Result<()> {
+    let matcher = unordered_elements_are![eq(&1), eq(&1), eq(&3)];
     verify_that!(
-        unordered_elements_are![eq(1), eq(1), eq(3)].explain_match(&vec![1, 2, 3]),
+        matcher.explain_match(&vec![1, 2, 3]),
         displays_as(eq("whose element #1 does not match any expected elements"))
     )
 }
 
-fn create_matcher() -> impl Matcher<ActualT = Vec<i32>> {
-    unordered_elements_are![eq(1)]
+fn create_matcher<'a>() -> impl Matcher<&'a Vec<i32>> {
+    unordered_elements_are![eq(&1)]
 }
 
 #[test]
@@ -217,8 +256,8 @@
     verify_that!(vec![1], create_matcher())
 }
 
-fn create_matcher_for_map() -> impl Matcher<ActualT = HashMap<i32, i32>> {
-    unordered_elements_are![(eq(1), eq(1))]
+fn create_matcher_for_map<'a>() -> impl Matcher<&'a HashMap<i32, i32>> {
+    unordered_elements_are![(eq(&1), eq(&1))]
 }
 
 #[test]
@@ -228,24 +267,24 @@
 
 #[test]
 fn contains_each_matches_when_one_to_one_correspondence_present() -> Result<()> {
-    verify_that!(vec![2, 3, 4], contains_each!(eq(2), eq(3), eq(4)))
+    verify_that!(vec![2, 3, 4], contains_each!(eq(&2), eq(&3), eq(&4)))
 }
 
 #[test]
 fn contains_each_supports_trailing_comma() -> Result<()> {
-    verify_that!(vec![2, 3, 4], contains_each!(eq(2), eq(3), eq(4),))
+    verify_that!(vec![2, 3, 4], contains_each!(eq(&2), eq(&3), eq(&4),))
 }
 
 #[test]
 fn contains_each_matches_hash_map() -> Result<()> {
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
-    verify_that!(value, contains_each![(eq(2), eq("Two")), (eq(1), eq("One"))])
+    verify_that!(value, contains_each![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One"))])
 }
 
 #[test]
 fn contains_each_matches_hash_map_with_trailing_comma() -> Result<()> {
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two"), (3, "Three")]);
-    verify_that!(value, contains_each![(eq(2), eq("Two")), (eq(1), eq("One")),])
+    verify_that!(value, contains_each![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")),])
 }
 
 #[test]
@@ -265,42 +304,46 @@
 
 #[test]
 fn contains_each_matches_when_excess_elements_present() -> Result<()> {
-    verify_that!(vec![1, 2, 3, 4], contains_each!(eq(2), eq(3), eq(4)))
+    verify_that!(vec![1, 2, 3, 4], contains_each!(eq(&2), eq(&3), eq(&4)))
 }
 
 #[test]
 fn contains_each_does_not_match_when_matchers_are_unmatched() -> Result<()> {
-    verify_that!(vec![1, 2, 3], not(contains_each!(eq(2), eq(3), eq(4))))
+    verify_that!(vec![1, 2, 3], not(contains_each!(eq(&2), eq(&3), eq(&4))))
 }
 
 #[test]
 fn contains_each_explains_mismatch_due_to_wrong_size() -> Result<()> {
+    let matcher = contains_each![eq(&2), eq(&3), eq(&4)];
     verify_that!(
-        contains_each![eq(2), eq(3), eq(4)].explain_match(&vec![2, 3]),
+        matcher.explain_match(&vec![2, 3]),
         displays_as(eq("which has size 2 (expected at least 3)"))
     )
 }
 
 #[test]
 fn contains_each_explains_missing_element_in_mismatch() -> Result<()> {
+    let matcher = contains_each![eq(&2), eq(&3), eq(&4)];
     verify_that!(
-        contains_each![eq(2), eq(3), eq(4)].explain_match(&vec![1, 2, 3]),
+        matcher.explain_match(&vec![1, 2, 3]),
         displays_as(eq("which has no element matching the expected element #2"))
     )
 }
 
 #[test]
 fn contains_each_explains_missing_elements_in_mismatch() -> Result<()> {
+    let matcher = contains_each![eq(&2), eq(&3), eq(&4), eq(&5)];
     verify_that!(
-        contains_each![eq(2), eq(3), eq(4), eq(5)].explain_match(&vec![0, 1, 2, 3]),
+        matcher.explain_match(&vec![0, 1, 2, 3]),
         displays_as(eq("which has no elements matching the expected elements #2, #3"))
     )
 }
 
 #[test]
 fn contains_each_explains_mismatch_due_to_no_graph_matching_found() -> Result<()> {
+    let matcher = contains_each![ge(&2), ge(&2)];
     verify_that!(
-        contains_each![ge(2), ge(2)].explain_match(&vec![1, 2]),
+        matcher .explain_match(&vec![1, 2]),
         displays_as(eq(indoc!(
             "
             which does not have a superset match with the expected elements. The best match found was:
@@ -324,12 +367,12 @@
 
 #[test]
 fn is_contained_in_matches_when_one_to_one_correspondence_present() -> Result<()> {
-    verify_that!(vec![2, 3, 4], is_contained_in!(eq(2), eq(3), eq(4)))
+    verify_that!(vec![2, 3, 4], is_contained_in!(eq(&2), eq(&3), eq(&4)))
 }
 
 #[test]
 fn is_contained_supports_trailing_comma() -> Result<()> {
-    verify_that!(vec![2, 3, 4], is_contained_in!(eq(2), eq(3), eq(4),))
+    verify_that!(vec![2, 3, 4], is_contained_in!(eq(&2), eq(&3), eq(&4),))
 }
 
 #[test]
@@ -337,7 +380,7 @@
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two")]);
     verify_that!(
         value,
-        is_contained_in![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))]
+        is_contained_in![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three"))]
     )
 }
 
@@ -346,53 +389,57 @@
     let value: HashMap<u32, &'static str> = HashMap::from([(1, "One"), (2, "Two")]);
     verify_that!(
         value,
-        is_contained_in![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three")),]
+        is_contained_in![(eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three")),]
     )
 }
 
 #[test]
 fn is_contained_in_matches_when_container_is_empty() -> Result<()> {
-    verify_that!(vec![], is_contained_in!(eq::<i32, _>(2), eq(3), eq(4)))
+    verify_that!(vec![1; 0], is_contained_in!(eq(&2), eq(&3), eq(&4)))
 }
 
 #[test]
 fn is_contained_in_matches_when_excess_matchers_present() -> Result<()> {
-    verify_that!(vec![3, 4], is_contained_in!(eq(2), eq(3), eq(4)))
+    verify_that!(vec![3, 4], is_contained_in!(eq(&2), eq(&3), eq(&4)))
 }
 
 #[test]
 fn is_contained_in_does_not_match_when_elements_are_unmatched() -> Result<()> {
-    verify_that!(vec![1, 2, 3], not(is_contained_in!(eq(2), eq(3), eq(4))))
+    verify_that!(vec![1, 2, 3], not(is_contained_in!(eq(&2), eq(&3), eq(&4))))
 }
 
 #[test]
 fn is_contained_in_explains_mismatch_due_to_wrong_size() -> Result<()> {
+    let matcher = is_contained_in![eq(&2), eq(&3)];
     verify_that!(
-        is_contained_in![eq(2), eq(3)].explain_match(&vec![2, 3, 4]),
+        matcher.explain_match(&vec![2, 3, 4]),
         displays_as(eq("which has size 3 (expected at most 2)"))
     )
 }
 
 #[test]
 fn is_contained_in_explains_missing_element_in_mismatch() -> Result<()> {
+    let matcher = is_contained_in![eq(&2), eq(&3), eq(&4)];
     verify_that!(
-        is_contained_in![eq(2), eq(3), eq(4)].explain_match(&vec![1, 2, 3]),
+        matcher.explain_match(&vec![1, 2, 3]),
         displays_as(eq("whose element #0 does not match any expected elements"))
     )
 }
 
 #[test]
 fn is_contained_in_explains_missing_elements_in_mismatch() -> Result<()> {
+    let matcher = is_contained_in![eq(&2), eq(&3), eq(&4), eq(&5)];
     verify_that!(
-        is_contained_in![eq(2), eq(3), eq(4), eq(5)].explain_match(&vec![0, 1, 2, 3]),
+        matcher.explain_match(&vec![0, 1, 2, 3]),
         displays_as(eq("whose elements #0, #1 do not match any expected elements"))
     )
 }
 
 #[test]
 fn is_contained_in_explains_mismatch_due_to_no_graph_matching_found() -> Result<()> {
+    let matcher = is_contained_in![ge(&1), ge(&3)];
     verify_that!(
-        is_contained_in![ge(1), ge(3)].explain_match(&vec![1, 2]),
+        matcher.explain_match(&vec![1, 2]),
         displays_as(eq(indoc!(
             "
             which does not have a subset match with the expected elements. The best match found was:
@@ -401,3 +448,18 @@
               Expected element `is greater than or equal to 3` at index 1 did not match any remaining actual element."))
     ))
 }
+
+#[test]
+fn unordered_elements_are_with_auto_eq() -> Result<()> {
+    verify_that!(vec![3, 4, 2], unordered_elements_are![&2, &3, &4])
+}
+
+#[test]
+fn contains_each_with_auto_eq() -> Result<()> {
+    verify_that!(vec![3, 4, 2], contains_each![&2, &4])
+}
+
+#[test]
+fn is_contained_in_with_auto_eq() -> Result<()> {
+    verify_that!(vec![3, 4, 2], is_contained_in![&1, &2, &3, &4])
+}
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index 984e54a..b9bf2c8 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -216,7 +216,7 @@
  "glam",
  "glob",
  "googletest",
- "googletest_macro 0.13.0",
+ "googletest_macro",
  "gpio-cdev",
  "grpcio",
  "grpcio-compiler",
@@ -2286,11 +2286,11 @@
 
 [[package]]
 name = "googletest"
-version = "0.11.0"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee44a233e2e661240ef77ed5de92ea9ecf70d4832963a8582a6681e1517f3673"
+checksum = "dce026f84cdd339bf71be01b24fe67470ee634282f68c1c4b563d00a9f002b05"
 dependencies = [
- "googletest_macro 0.11.0",
+ "googletest_macro",
  "num-traits",
  "regex",
  "rustversion",
@@ -2298,16 +2298,6 @@
 
 [[package]]
 name = "googletest_macro"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed3057b7d1e628480193188ccb1a7850d034a3add3a350f4ed921b48e287ada9"
-dependencies = [
- "quote 1.0.38",
- "syn 2.0.96",
-]
-
-[[package]]
-name = "googletest_macro"
 version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f5070fa86976044fe2b004d874c10af5d1aed6d8f6a72ff93a6eb29cc87048bc"
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index e24e8f0..b4595e2 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -130,7 +130,7 @@
 getrandom = "=0.2.15"
 glam = "=0.29.2"
 glob = "=0.3.2"
-googletest = "=0.11.0"
+googletest = "=0.13.0"
 googletest_macro = "=0.13.0"
 gpio-cdev = "=0.6.0"
 grpcio = "=0.13.0"