get-size2-0.10.1/.cargo_vcs_info.json0000644000000001561046102023000127500ustar { "git": { "sha1": "0b2cab781cae0b3d3b614f07ecf9dd2952a728a8" }, "path_in_vcs": "crates/get-size2" }get-size2-0.10.1/Cargo.lock0000644000000522421046102023000107260ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "attribute-derive" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77" dependencies = [ "attribute-derive-macro", "derive-where", "manyhow", "proc-macro2", "quote", "syn", ] [[package]] name = "attribute-derive-macro" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61" dependencies = [ "collection_literals", "interpolator", "manyhow", "proc-macro-utils", "proc-macro2", "quote", "quote-use", "syn", ] [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "castaway" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ "rustversion", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "num-traits", ] [[package]] name = "chrono-tz" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" dependencies = [ "chrono", "phf", ] [[package]] name = "collection_literals" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084" [[package]] name = "compact_str" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" dependencies = [ "castaway", "cfg-if", "itoa", "rustversion", "ryu", "static_assertions", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "dashmap" version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", "crossbeam-utils", "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", ] [[package]] name = "derive-where" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "form_urlencoded" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "get-size-derive2" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1da24fbda09ec01bca7cfa1797c0e520e75123bccb01dcdf9041f8aa65183bc2" dependencies = [ "attribute-derive", "quote", "syn", ] [[package]] name = "get-size2" version = "0.10.1" dependencies = [ "bytes", "chrono", "chrono-tz", "compact_str", "dashmap", "get-size-derive2", "half", "hashbrown 0.17.1", "indexmap", "ordermap", "orx-concurrent-vec", "parking_lot", "roaring", "smallvec", "thin-vec", "url", ] [[package]] name = "half" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", "zerocopy", ] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "icu_collections" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", "utf8_iter", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_normalizer" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", "writeable", "yoke", "zerofrom", "zerotrie", "zerovec", ] [[package]] name = "idna" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "indexmap" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown 0.17.1", ] [[package]] name = "interpolator" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" [[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "libc" version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "litemap" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ "scopeguard", ] [[package]] name = "manyhow" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" dependencies = [ "manyhow-macros", "proc-macro2", "quote", "syn", ] [[package]] name = "manyhow-macros" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" dependencies = [ "proc-macro-utils", "proc-macro2", "quote", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "ordermap" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7476a5b122ff1fce7208e7ee9dccd0a516e835f5b8b19b8f3c98a34cf757c1" dependencies = [ "indexmap", ] [[package]] name = "orx-concurrent-iter" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78e4381d6f1393a99e5a2bebe63e7a4c58c2526cdf25e01830baa11410c7ece1" dependencies = [ "orx-iterable", "orx-pseudo-default", ] [[package]] name = "orx-concurrent-option" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "842a5c05d6f02368d1cdfebec87ae6e2277ca0cf544ab3778e6f2e6c5c947da3" [[package]] name = "orx-concurrent-vec" version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad98d4d130277af640a2222188f0f706f25515be29b9b74519fad790b6a58e6e" dependencies = [ "orx-concurrent-option", "orx-fixed-vec", "orx-pinned-concurrent-col", "orx-pinned-vec", "orx-pseudo-default", "orx-split-vec", ] [[package]] name = "orx-fixed-vec" version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ddf6c4b7f928c2273fb8df61fd901e9b1e267d4aef371532baa4863b076e549" dependencies = [ "orx-concurrent-iter", "orx-iterable", "orx-pinned-vec", "orx-pseudo-default", ] [[package]] name = "orx-iterable" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa2cb3f82a187c68835faac9cf03faaee70b93f4da3b85515ac1b4c6f8a432d" dependencies = [ "orx-self-or", ] [[package]] name = "orx-pinned-concurrent-col" version = "2.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56b22c9e39d97d1c1d63dcbd9be68ac414cc61c9c6b8e799a125d383a18f3f10" dependencies = [ "orx-fixed-vec", "orx-pinned-vec", "orx-pseudo-default", "orx-split-vec", ] [[package]] name = "orx-pinned-vec" version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa97067bc27cd45aeb48c4043c8d560aba47c632126c374c53cd2ebda31f586f" dependencies = [ "orx-iterable", "orx-pseudo-default", ] [[package]] name = "orx-pseudo-default" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34eaace9ae01f7025804fbca40ec45b87c19ba0328d97195e01c6135897762a8" [[package]] name = "orx-self-or" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67a8e35dfe18921e475b9861266fd58a5ecfd681161f242d24a9e2d1e07fbc28" [[package]] name = "orx-split-vec" version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a31c29310ba717a7e9ad41cbb10ab16443702ca87294d64e1e6cbfa3bd817d1" dependencies = [ "orx-concurrent-iter", "orx-iterable", "orx-pinned-vec", "orx-pseudo-default", ] [[package]] name = "parking_lot" version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-link", ] [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" dependencies = [ "phf_shared", ] [[package]] name = "phf_shared" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" dependencies = [ "siphasher", ] [[package]] name = "potential_utf" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] [[package]] name = "proc-macro-utils" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" dependencies = [ "proc-macro2", "quote", "smallvec", ] [[package]] name = "proc-macro2" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "quote-use" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e" dependencies = [ "quote", "quote-use-macros", ] [[package]] name = "quote-use-macros" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35" dependencies = [ "proc-macro-utils", "proc-macro2", "quote", "syn", ] [[package]] name = "redox_syscall" version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "roaring" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dedc5658c6ecb3bdb5ef5f3295bb9253f42dcf3fd1402c03f6b1f7659c3c4a9" [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "siphasher" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thin-vec" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0f7e269b48f0a7dd0146680fa24b50cc67fc0373f086a5b2f99bd084639b482" [[package]] name = "tinystr" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "url" version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "writeable" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "yoke" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerocopy" version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "zerofrom" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerotrie" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", "zerofrom", ] [[package]] name = "zerovec" version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", "syn", ] get-size2-0.10.1/Cargo.toml0000644000000102151046102023000107430ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2024" name = "get-size2" version = "0.10.1" authors = [ "Denis Kerp", "Nicolas", ] build = false exclude = [ "examples/*", "tests/*", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Determine the size in bytes an object occupies inside RAM." readme = "README.md" keywords = [ "size", "heap", "ram", "memory", "get-size", ] categories = [ "memory-management", "caching", ] license = "MIT OR Apache-2.0" repository = "https://github.com/bircni/get-size2" resolver = "2" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [features] bytes = ["dep:bytes"] chrono = ["dep:chrono"] chrono-tz = ["dep:chrono-tz"] compact-str = ["dep:compact_str"] dashmap = ["dep:dashmap"] default = [] derive = ["get-size-derive2"] half = ["dep:half"] hashbrown = ["dep:hashbrown"] indexmap = ["dep:indexmap"] ordermap = ["dep:ordermap"] orx-concurrent-vec = ["dep:orx-concurrent-vec"] parking_lot = ["dep:parking_lot"] roaring = ["dep:roaring"] smallvec = ["dep:smallvec"] thin-vec = ["dep:thin-vec"] url = ["dep:url"] [lib] name = "get_size2" path = "src/lib.rs" [dependencies.bytes] version = "1" optional = true default-features = false [dependencies.chrono] version = "0.4" optional = true default-features = false [dependencies.chrono-tz] version = "0.10" optional = true default-features = false [dependencies.compact_str] version = "0.9" optional = true default-features = false [dependencies.dashmap] version = "6" optional = true default-features = false [dependencies.get-size-derive2] version = "0.10.1" optional = true [dependencies.half] version = "2" optional = true default-features = false [dependencies.hashbrown] version = "0.17" optional = true default-features = false [dependencies.indexmap] version = "2.14" optional = true default-features = false [dependencies.ordermap] version = "1.2" optional = true default-features = false [dependencies.orx-concurrent-vec] version = "3.10" optional = true default-features = false [dependencies.parking_lot] version = "0.12" optional = true default-features = false [dependencies.roaring] version = "0.11" optional = true default-features = false [dependencies.smallvec] version = "1" optional = true default-features = false [dependencies.thin-vec] version = "0.2" optional = true default-features = false [dependencies.url] version = "2" optional = true default-features = false [dev-dependencies] [lints.clippy] allow_attributes = "warn" allow_attributes_without_reason = "warn" assertions_on_result_states = "warn" clone_on_ref_ptr = "warn" create_dir = "warn" expect_used = "warn" missing_assert_message = "warn" panic_in_result_fn = "warn" str_to_string = "warn" todo = "warn" unimplemented = "warn" unwrap_used = "warn" wildcard_enum_match_arm = "warn" [lints.clippy.all] level = "warn" priority = -1 [lints.clippy.complexity] level = "warn" priority = -1 [lints.clippy.correctness] level = "warn" priority = -1 [lints.clippy.needless_doctest_main] level = "allow" priority = 0 [lints.clippy.nursery] level = "warn" priority = -1 [lints.clippy.pedantic] level = "warn" priority = -1 [lints.clippy.perf] level = "warn" priority = -1 [lints.clippy.style] level = "warn" priority = -1 [lints.clippy.suspicious] level = "warn" priority = -1 [lints.rust] deprecated = "warn" elided_lifetimes_in_paths = "warn" rust_2021_prelude_collisions = "warn" semicolon_in_expressions_from_macros = "warn" trivial_numeric_casts = "warn" unsafe_code = "deny" unsafe_op_in_unsafe_fn = "warn" unused_extern_crates = "warn" unused_import_braces = "warn" unused_lifetimes = "warn" [lints.rustdoc] all = "warn" missing_crate_level_docs = "warn" get-size2-0.10.1/Cargo.toml.orig000064400000000000000000000047111046102023000144060ustar 00000000000000[package] name = "get-size2" description = "Determine the size in bytes an object occupies inside RAM." version.workspace = true edition.workspace = true license.workspace = true authors.workspace = true readme = "README.md" repository = "https://github.com/bircni/get-size2" keywords = ["size", "heap", "ram", "memory", "get-size"] categories = ["memory-management", "caching"] exclude = ["examples/*", "tests/*"] [lints] workspace = true [dependencies] get-size-derive2 = { workspace = true, optional = true } bytes = { version = "1", default-features = false, optional = true } chrono = { version = "0.4", default-features = false, optional = true } chrono-tz = { version = "0.10", default-features = false, optional = true } compact_str = { version = "0.9", default-features = false, optional = true } dashmap = { version = "6", default-features = false, optional = true } half = { version = "2", default-features = false, optional = true } hashbrown = { version = "0.17", default-features = false, optional = true } indexmap = { version = "2.14", default-features = false, optional = true } ordermap = { version = "1.2", default-features = false, optional = true } orx-concurrent-vec = { version = "3.10", default-features = false, optional = true } parking_lot = { version = "0.12", default-features = false, optional = true } roaring = { version = "0.11", default-features = false, optional = true } smallvec = { version = "1", default-features = false, optional = true } thin-vec = { version = "0.2", default-features = false, optional = true } url = { version = "2", default-features = false, optional = true } [dev-dependencies] get-size2 = { path = ".", features = [ "derive", "bytes", "chrono", "chrono-tz", "compact-str", "dashmap", "half", "hashbrown", "indexmap", "ordermap", "orx-concurrent-vec", "parking_lot", "roaring", "smallvec", "thin-vec", "url", ] } [features] default = [] derive = ["get-size-derive2"] bytes = ["dep:bytes"] chrono = ["dep:chrono"] chrono-tz = ["dep:chrono-tz"] compact-str = ["dep:compact_str"] dashmap = ["dep:dashmap"] half = ["dep:half"] hashbrown = ["dep:hashbrown"] indexmap = ["dep:indexmap"] ordermap = ["dep:ordermap"] orx-concurrent-vec = ["dep:orx-concurrent-vec"] parking_lot = ["dep:parking_lot"] roaring = ["dep:roaring"] smallvec = ["dep:smallvec"] thin-vec = ["dep:thin-vec"] url = ["dep:url"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] get-size2-0.10.1/LICENSE000064400000000000000000000020721046102023000125220ustar 00000000000000MIT License Copyright (c) 2022 Denis Kerp & 2025 Nicolas Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. get-size2-0.10.1/README.md000064400000000000000000000146501046102023000130010ustar 00000000000000# get-size2 [![Crates.io](https://img.shields.io/crates/v/get-size2)](https://crates.io/crates/get-size2) [![docs.rs](https://img.shields.io/docsrs/get-size2)](https://docs.rs/get-size2) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/bircni/get-size2/blob/main/crates/get-size2/LICENSE) > This repo is a fork of get-size, as it is not maintained anymore. The original repo can be found [here](https://github.com/DKerp/get-size) Determine the size in bytes an object occupies inside RAM. The [`GetSize`] trait can be used to determine the size of an object inside the stack as well as in the heap. The [`size_of`](https://doc.rust-lang.org/std/mem/fn.size_of.html) function provided by the standard library can already be used to determine the size of an object in the stack, but many application (e.g. for caching) do also need to know the number of bytes occupied inside the heap, for which this library provides an appropriate trait. ## Example We use [`GetSize`] to determine number of bytes occupied by both a `String` and a `Vec` of bytes. Note that the `Vec` has already allocated a capacity of `1024` bytes, and does thus correctly show a heap size of `1024`, even if only `1` byte is currently in use. ```rust use get_size2::GetSize; fn main() { let value = String::from("Hello World!"); assert_eq!(String::get_stack_size(), std::mem::size_of::()); assert_eq!(value.get_heap_size(), 12); assert_eq!(value.get_size(), std::mem::size_of::() + 12); let mut buffer = Vec::with_capacity(1024); // 1KB allocated on the heap. buffer.push(1u8); // 1 byte in use. assert_eq!(buffer.len(), 1); assert_eq!(buffer.get_heap_size(), 1024); } ``` ## Ownership based accounting This library follows the idea that only bytes owned by a certain object should be accounted for, and not bytes owned by different objects which are only borrowed. This means in particular that objects referenced by pointers are ignored. On the other hand references implemented as shared ownership are treated as owned values. It is your responsibility to ensure that the bytes occupied by them are not counted twice in your application. The `ignore` attribute might be helpful, [see below](#ignoring-certain-values). ## How to implement The [`GetSize`] trait is already implemented for most objects defined by the standard library, like `Vec`, `HashMap`, `String` as well as all the primitive values, like `u8`, `i32` etc. Unless you have a complex datastructure which requires a manual implementation, you can easily derive [`GetSize`] for your own structs and enums. The derived implementation will implement [`get_heap_size`] by simply calling [`get_heap_size`] on all values contained inside the struct or enum variant and return the sum of them. You will need to activate the `derive` feature first, which is disabled by default. Add the following to your `cargo.toml`: ```toml get-size2 = { version = "^0.7", features = ["derive"] } ``` Note that the derive macro _does not support unions_. You have to manually implement it for them. The derive macro does also work with generics. The generated trait implementation will by default require all generic types to implement [`GetSize`] themselves, but this [can be changed](#ignoring-certain-generic-types). ### Dealing with external types which do not implement GetSize Deriving [`GetSize`] is straight forward if all the types contained in your data structure implement [`GetSize`] themselves, but this might not always be the case. For that reason the derive macro offers some helpers to assist you in that case. Note that the helper attributes are supported for structs (named and tuple; `size_fn` requires named fields). For enums, only `ignore` is supported on named fields. #### Ignoring certain values You can tell the derive macro to ignore certain struct fields by adding the `ignore` attribute to them. The generated implementation of [`get_heap_size`] will then simple skip this field. But you may also use this as a band aid, if a certain struct fields type does not implement [`GetSize`]. Be aware though that this will result in an implementation which will return incorrect results, unless the heap size of that type is indeed always zero and can thus be ignored. It is therefor advisable to use one of the next two helper options instead. #### Returning a fixed value In same cases you may be dealing with external types which allocate a fixed amount of bytes at the heap. In this case you may use the `size` attribute to always account the given field with a fixed value. #### Using a helper function In same cases you may be dealing with an external data structure for which you know how to calculate its heap size using its public methods. In that case you may either use the newtype pattern to implement [`GetSize`] for it directly, or you can use the `size_fn` attribute, which will call the given function in order to calculate the fields heap size. The latter is especially useful if you can make use of a certain trait to calculate the heap size for multiple types. Note that unlike in other crates, the name of the function to be called is **not** encapsulated by double-quotes ("), but rather given directly. #### Ignoring certain generic types If your struct uses generics, but the fields at which they are stored are ignored or get handled by helpers because the generic does not implement [`GetSize`], you will have to mark these generics with a special struct level `ignore` attribute. Otherwise the derived [`GetSize`] implementation would still require these generics to implement [`GetSize`], even though there is no need for it. ## Tracking shared ownership To avoid double-counting shared ownership (e.g. `Rc`, `Arc`), use a tracker: ```rust use get_size2::{GetSize, StandardTracker}; fn main() { let value = std::sync::Arc::new(String::from("hello")); let (heap_size, _tracker) = value.get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(heap_size, std::mem::size_of::() + 5); } ``` ## License This library is licensed under the [MIT license](http://opensource.org/licenses/MIT). ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this library by you, shall be licensed as MIT, without any additional terms or conditions. [`GetSize`]: https://docs.rs/get-size2/latest/get_size2/trait.GetSize.html [`get_heap_size`]: https://docs.rs/get-size2/latest/get_size2/trait.GetSize.html#method.get_heap_size get-size2-0.10.1/src/impls/collections.rs000064400000000000000000000144211046102023000163150ustar 00000000000000use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; use std::hash::BuildHasher; use crate::{GetSize, GetSizeTracker}; macro_rules! impl_size_set { ($name:ident) => { impl GetSize for $name where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), elem| { let (elem_size, tracker) = T::get_heap_size_with_tracker(elem, tracker); (size + elem_size, tracker) }); let allocation_size = self.capacity() * T::get_stack_size(); (size + allocation_size, tracker) } } }; } macro_rules! impl_size_set_no_capacity { ($name:ident) => { impl GetSize for $name where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), elem| { // We assume that values are held inside the heap. let (elem_size, tracker) = T::get_size_with_tracker(elem, tracker); (size + elem_size, tracker) }); (size, tracker) } } }; } impl_size_set_no_capacity!(BTreeSet); impl_size_set!(BinaryHeap); impl_size_set_no_capacity!(LinkedList); impl_size_set!(VecDeque); impl GetSize for BTreeMap where K: GetSize, V: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { self.iter() .fold((0, tracker), |(size, tracker), (key, value)| { let (key_size, tracker) = K::get_size_with_tracker(key, tracker); let (value_size, tracker) = V::get_size_with_tracker(value, tracker); (size + key_size + value_size, tracker) }) } } impl GetSize for HashMap where K: GetSize, V: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self .iter() .fold((0, tracker), |(size, tracker), (key, value)| { let (key_size, tracker) = K::get_heap_size_with_tracker(key, tracker); let (value_size, tracker) = V::get_heap_size_with_tracker(value, tracker); (size + key_size + value_size, tracker) }); let allocation_size = self.capacity() * <(K, V)>::get_stack_size(); (size + allocation_size, tracker) } } impl GetSize for HashSet where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), elem| { let (elem_size, tracker) = T::get_heap_size_with_tracker(elem, tracker); (size + elem_size, tracker) }); let allocation_size = self.capacity() * T::get_stack_size(); (size + allocation_size, tracker) } } impl_size_set!(Vec); macro_rules! impl_size_tuple { ($($t:ident, $T:ident),+) => { impl<$($T,)*> GetSize for ($($T,)*) where $( $T: GetSize, )* { #[allow(unused_mut, reason = "the macro supports a variadic number of elements")] #[expect(clippy::allow_attributes, reason = "the macro supports a variadic number of elements")] fn get_heap_size_with_tracker(&self, mut tracker: Tr) -> (usize, Tr) { let mut total = 0; let mut elem_size; let ($($t,)*) = self; $( (elem_size, tracker) = <$T>::get_heap_size_with_tracker($t, tracker); total += elem_size; )* (total, tracker) } } } } macro_rules! execute_tuple_macro_16 { ($name:ident) => { $name!(v1, V1); $name!(v1, V1, v2, V2); $name!(v1, V1, v2, V2, v3, V3); $name!(v1, V1, v2, V2, v3, V3, v4, V4); $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5); $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6); $name!(v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8 ); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9 ); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10 ); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11, V11 ); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11, V11, v12, V12 ); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11, V11, v12, V12, v13, V13 ); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11, V11, v12, V12, v13, V13, v14, V14 ); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11, V11, v12, V12, v13, V13, v14, V14, v15, V15 ); $name!( v1, V1, v2, V2, v3, V3, v4, V4, v5, V5, v6, V6, v7, V7, v8, V8, v9, V9, v10, V10, v11, V11, v12, V12, v13, V13, v14, V14, v15, V15, v16, V16 ); }; } execute_tuple_macro_16!(impl_size_tuple); impl GetSize for [T; SIZE] where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { self.iter().fold((0, tracker), |(size, tracker), element| { // The array stack size already accounts for the stack size of the elements of the array. let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }) } } get-size2-0.10.1/src/impls/feature/bytes.rs000064400000000000000000000005471046102023000165640ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for bytes::Bytes { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } impl GetSize for bytes::BytesMut { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } get-size2-0.10.1/src/impls/feature/chrono.rs000064400000000000000000000010251046102023000167160ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for chrono::NaiveDate {} impl GetSize for chrono::NaiveTime {} impl GetSize for chrono::NaiveDateTime {} impl GetSize for chrono::Utc {} impl GetSize for chrono::FixedOffset {} impl GetSize for chrono::TimeDelta {} impl GetSize for chrono::DateTime where Tz::Offset: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { ::get_heap_size_with_tracker(self.offset(), tracker) } } get-size2-0.10.1/src/impls/feature/chrono_tz.rs000064400000000000000000000000751046102023000174370ustar 00000000000000use crate::GetSize; impl GetSize for chrono_tz::TzOffset {} get-size2-0.10.1/src/impls/feature/compact_str.rs000064400000000000000000000005051046102023000177460ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for compact_str::CompactString { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { let size = if self.is_heap_allocated() { self.capacity() } else { 0 }; (size, tracker) } } get-size2-0.10.1/src/impls/feature/dashmap.rs000064400000000000000000000024321046102023000170460ustar 00000000000000use std::hash::{BuildHasher, Hash}; use crate::{GetSize, GetSizeTracker}; impl GetSize for dashmap::DashMap where K: GetSize + Eq + Hash, V: GetSize, S: BuildHasher + Clone, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), entry| { let (k_size, tracker) = K::get_heap_size_with_tracker(entry.key(), tracker); let (v_size, tracker) = V::get_heap_size_with_tracker(entry.value(), tracker); (size + k_size + v_size, tracker) }); let allocation_size = self.capacity() * <(K, V)>::get_stack_size(); (size + allocation_size, tracker) } } impl GetSize for dashmap::DashSet where T: GetSize + Eq + Hash, S: BuildHasher + Clone, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), entry| { let (elem_size, tracker) = T::get_heap_size_with_tracker(entry.key(), tracker); (size + elem_size, tracker) }); let allocation_size = self.capacity() * T::get_stack_size(); (size + allocation_size, tracker) } } get-size2-0.10.1/src/impls/feature/half.rs000064400000000000000000000001221046102023000163350ustar 00000000000000use crate::GetSize; impl GetSize for half::f16 {} impl GetSize for half::bf16 {} get-size2-0.10.1/src/impls/feature/hashbrown.rs000064400000000000000000000031751046102023000174310ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for hashbrown::HashMap where K: GetSize + Eq + std::hash::Hash, V: GetSize, H: std::hash::BuildHasher, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self .iter() .fold((0, tracker), |(size, tracker), (key, value)| { let (key_size, tracker) = K::get_heap_size_with_tracker(key, tracker); let (value_size, tracker) = V::get_heap_size_with_tracker(value, tracker); (size + key_size + value_size, tracker) }); (size + self.allocation_size(), tracker) } } impl GetSize for hashbrown::HashSet where T: GetSize + Eq + std::hash::Hash, H: std::hash::BuildHasher, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); (size + self.allocation_size(), tracker) } } impl GetSize for hashbrown::HashTable where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); (size + self.allocation_size(), tracker) } } get-size2-0.10.1/src/impls/feature/indexmap.rs000064400000000000000000000023631046102023000172410ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for indexmap::IndexMap where K: GetSize, V: GetSize, S: std::hash::BuildHasher, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self .iter() .fold((0, tracker), |(size, tracker), (key, value)| { let (key_size, tracker) = K::get_heap_size_with_tracker(key, tracker); let (value_size, tracker) = V::get_heap_size_with_tracker(value, tracker); (size + key_size + value_size, tracker) }); let allocation_size = self.capacity() * <(K, V)>::get_stack_size(); (size + allocation_size, tracker) } } impl GetSize for indexmap::IndexSet where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); let allocation_size = self.capacity() * T::get_stack_size(); (size + allocation_size, tracker) } } get-size2-0.10.1/src/impls/feature/mod.rs000064400000000000000000000013311046102023000162050ustar 00000000000000#![allow(clippy::allow_attributes, reason = "needed if features are enabled")] #[cfg(feature = "bytes")] mod bytes; #[cfg(feature = "chrono")] mod chrono; #[cfg(feature = "chrono-tz")] mod chrono_tz; #[cfg(feature = "compact-str")] mod compact_str; #[cfg(feature = "dashmap")] mod dashmap; #[cfg(feature = "half")] mod half; #[cfg(feature = "hashbrown")] mod hashbrown; #[cfg(feature = "indexmap")] mod indexmap; #[cfg(feature = "ordermap")] mod ordermap; #[cfg(feature = "orx-concurrent-vec")] mod orx_concurrent_vec; #[cfg(feature = "parking_lot")] mod parking_lot; #[cfg(feature = "roaring")] mod roaring; #[cfg(feature = "smallvec")] mod smallvec; #[cfg(feature = "thin-vec")] mod thin_vec; #[cfg(feature = "url")] mod url; get-size2-0.10.1/src/impls/feature/ordermap.rs000064400000000000000000000023631046102023000172450ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for ordermap::OrderMap where K: GetSize, V: GetSize, S: std::hash::BuildHasher, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self .iter() .fold((0, tracker), |(size, tracker), (key, value)| { let (key_size, tracker) = K::get_heap_size_with_tracker(key, tracker); let (value_size, tracker) = V::get_heap_size_with_tracker(value, tracker); (size + key_size + value_size, tracker) }); let allocation_size = self.capacity() * <(K, V)>::get_stack_size(); (size + allocation_size, tracker) } } impl GetSize for ordermap::OrderSet where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); let allocation_size = self.capacity() * T::get_stack_size(); (size + allocation_size, tracker) } } get-size2-0.10.1/src/impls/feature/orx_concurrent_vec.rs000064400000000000000000000016601046102023000213420ustar 00000000000000use orx_concurrent_vec::{ConcurrentElement, ConcurrentVec, IntoConcurrentPinnedVec}; use crate::{GetSize, GetSizeTracker}; // `ConcurrentVec::new()` eagerly allocates an initial fragment, so // `capacity()` is nonzero even for an empty vec. Backing `SplitVec` // fragment headers are not counted (bounded by a small constant for // the default Doubling growth strategy). impl GetSize for ConcurrentVec where T: GetSize, P: IntoConcurrentPinnedVec>, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (heap, tracker) = self.iter().fold((0usize, tracker), |(size, tr), elem| { let (elem_size, tr) = elem.map(|t: &T| T::get_heap_size_with_tracker(t, tr)); (size + elem_size, tr) }); let allocation = self.capacity() * core::mem::size_of::>(); (heap + allocation, tracker) } } get-size2-0.10.1/src/impls/feature/parking_lot.rs000064400000000000000000000034721046102023000177470ustar 00000000000000use crate::{GetSize, GetSizeTracker}; // parking_lot's Mutex/RwLock are infallible (no poisoning) so these are // simpler than the std::sync variants in `impls/sync_impls.rs` — no // `unwrap_or_else(PoisonError::into_inner)` recovery needed. impl GetSize for parking_lot::Mutex where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let guard = self.lock(); T::get_heap_size_with_tracker(&*guard, tracker) } } impl GetSize for parking_lot::RwLock where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let guard = self.read(); T::get_heap_size_with_tracker(&*guard, tracker) } } // Tracker-side mirrors of the std::sync impls in `crate::tracker`. // Letting a `parking_lot::Mutex` work as a tracker keeps API // parity with the existing `Mutex` / `RwLock` / // `Arc>` / `Arc>` patterns. impl GetSizeTracker for parking_lot::Mutex { fn track(&mut self, addr: *const A) -> bool { GetSizeTracker::track(self.get_mut(), addr) } } impl GetSizeTracker for parking_lot::RwLock { fn track(&mut self, addr: *const A) -> bool { GetSizeTracker::track(self.get_mut(), addr) } } impl GetSizeTracker for std::sync::Arc> { fn track(&mut self, addr: *const A) -> bool { let mut guard = self.lock(); GetSizeTracker::track(&mut *guard, addr) } } impl GetSizeTracker for std::sync::Arc> { fn track(&mut self, addr: *const A) -> bool { let mut guard = self.write(); GetSizeTracker::track(&mut *guard, addr) } } get-size2-0.10.1/src/impls/feature/roaring.rs000064400000000000000000000030211046102023000170650ustar 00000000000000use crate::{GetSize, GetSizeTracker}; // Container allocations live in a private `Vec`; `statistics()` // is the only public proxy for their byte totals. Per-container key/tag // fields and the outer `Vec` slots are not counted — bounded // by 65 536 containers per bitmap, negligible vs. up to ~512 MiB of // container payload. impl GetSize for roaring::RoaringBitmap { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let s = self.statistics(); let bytes = s.n_bytes_array_containers + s.n_bytes_bitset_containers + s.n_bytes_run_containers; // u64 → usize: bounded ~512 MiB so fits everywhere; saturate // defensively in release, surface the invariant breach in debug. debug_assert!(bytes <= usize::MAX as u64); (usize::try_from(bytes).unwrap_or(usize::MAX), tracker) } } // Mirrors the `BTreeMap` impl in `collections.rs` — per-entry // stack + heap of both K and V, no node-padding accounting. impl GetSize for roaring::RoaringTreemap { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { self.bitmaps() .fold((0, tracker), |(size, tracker), (key, bitmap)| { let (key_size, tracker) = u32::get_size_with_tracker(&key, tracker); let (bm_size, tracker) = roaring::RoaringBitmap::get_size_with_tracker(bitmap, tracker); (size + key_size + bm_size, tracker) }) } } get-size2-0.10.1/src/impls/feature/smallvec.rs000064400000000000000000000011511046102023000172340ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for smallvec::SmallVec where A::Item: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (mut size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = ::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); if self.len() > self.inline_size() { size += self.capacity() * ::get_stack_size(); } (size, tracker) } } get-size2-0.10.1/src/impls/feature/thin_vec.rs000064400000000000000000000014321046102023000172270ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for thin_vec::ThinVec where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { if self.capacity() == 0 { // If it's the singleton we might not be a heap pointer. return (0, tracker); } let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); let metadata_size = std::mem::size_of::() * 2; // Capacity and length. let allocation_size = self.capacity() * T::get_stack_size(); (size + metadata_size + allocation_size, tracker) } } get-size2-0.10.1/src/impls/feature/url.rs000064400000000000000000000003121046102023000162260ustar 00000000000000use crate::{GetSize, GetSizeTracker}; impl GetSize for url::Url { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.as_str().len(), tracker) } } get-size2-0.10.1/src/impls/mod.rs000064400000000000000000000001501046102023000145500ustar 00000000000000mod collections; mod feature; mod ownership; mod primitives; mod ranges; mod std_types; mod sync_impls; get-size2-0.10.1/src/impls/ownership.rs000064400000000000000000000043371046102023000160220ustar 00000000000000use std::borrow::Cow; use std::rc::{Rc, Weak as RcWeak}; use std::sync::{Arc, Weak as ArcWeak}; use crate::{GetSize, GetSizeTracker}; impl GetSize for Cow<'_, T> where T: ToOwned + ?Sized, T::Owned: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { match self { Self::Borrowed(_borrowed) => (0, tracker), Self::Owned(owned) => ::get_heap_size_with_tracker(owned, tracker), } } } impl GetSize for &[T] where T: GetSize {} impl GetSize for &T {} impl GetSize for &mut T {} impl GetSize for *const T {} impl GetSize for *mut T {} impl GetSize for Box where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { T::get_size_with_tracker(&**self, tracker) } } impl GetSize for Rc where T: GetSize, { fn get_heap_size_with_tracker(&self, mut tracker: Tr) -> (usize, Tr) { if tracker.track(Self::as_ptr(self)) { T::get_size_with_tracker(&**self, tracker) } else { (0, tracker) } } } impl GetSize for RcWeak {} impl GetSize for Arc where T: GetSize, { fn get_heap_size_with_tracker(&self, mut tracker: Tr) -> (usize, Tr) { if tracker.track(Self::as_ptr(self)) { T::get_size_with_tracker(&**self, tracker) } else { (0, tracker) } } } impl GetSize for ArcWeak {} impl GetSize for Option where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { match self { None => (0, tracker), Some(value) => T::get_heap_size_with_tracker(value, tracker), } } } impl GetSize for Result where T: GetSize, E: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { // The result's stack size already accounts for the values stack size. match self { Ok(value) => T::get_heap_size_with_tracker(value, tracker), Err(err) => E::get_heap_size_with_tracker(err, tracker), } } } get-size2-0.10.1/src/impls/primitives.rs000064400000000000000000000035241046102023000161740ustar 00000000000000use std::convert::Infallible; use std::marker::{PhantomData, PhantomPinned}; use std::num::{ NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize, }; use std::sync::atomic::{ AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize, Ordering, }; use std::time::{Duration, Instant, SystemTime}; use crate::GetSize; impl GetSize for () {} impl GetSize for bool {} impl GetSize for u8 {} impl GetSize for u16 {} impl GetSize for u32 {} impl GetSize for u64 {} impl GetSize for u128 {} impl GetSize for usize {} impl GetSize for NonZeroU8 {} impl GetSize for NonZeroU16 {} impl GetSize for NonZeroU32 {} impl GetSize for NonZeroU64 {} impl GetSize for NonZeroU128 {} impl GetSize for NonZeroUsize {} impl GetSize for i8 {} impl GetSize for i16 {} impl GetSize for i32 {} impl GetSize for i64 {} impl GetSize for i128 {} impl GetSize for isize {} impl GetSize for NonZeroI8 {} impl GetSize for NonZeroI16 {} impl GetSize for NonZeroI32 {} impl GetSize for NonZeroI64 {} impl GetSize for NonZeroI128 {} impl GetSize for NonZeroIsize {} impl GetSize for f32 {} impl GetSize for f64 {} impl GetSize for char {} impl GetSize for AtomicBool {} impl GetSize for AtomicI8 {} impl GetSize for AtomicI16 {} impl GetSize for AtomicI32 {} impl GetSize for AtomicI64 {} impl GetSize for AtomicIsize {} impl GetSize for AtomicU8 {} impl GetSize for AtomicU16 {} impl GetSize for AtomicU32 {} impl GetSize for AtomicU64 {} impl GetSize for AtomicUsize {} impl GetSize for Ordering {} impl GetSize for std::cmp::Ordering {} impl GetSize for Infallible {} impl GetSize for PhantomData {} impl GetSize for PhantomPinned {} impl GetSize for Instant {} impl GetSize for Duration {} impl GetSize for SystemTime {} get-size2-0.10.1/src/impls/ranges.rs000064400000000000000000000027271046102023000152640ustar 00000000000000use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; use crate::{GetSize, GetSizeTracker}; /// Helper macro used to sum the heap sizes of specific fields. macro_rules! impl_sum_of_fields { ($name:ident, $($field:ident),+) => { impl GetSize for $name { #[allow(unused_mut, reason = "the macro supports a variadic number of elements")] #[expect(clippy::allow_attributes, reason = "the macro supports a variadic number of elements")] fn get_heap_size_with_tracker(&self, mut tracker: Tr) -> (usize, Tr) { let mut size = 0; let mut elem_size; $( (elem_size, tracker) = self.$field.get_heap_size_with_tracker(tracker); size += elem_size; )+ (size, tracker) } } }; } impl_sum_of_fields!(Range, start, end); impl_sum_of_fields!(RangeFrom, start); impl_sum_of_fields!(RangeTo, end); impl_sum_of_fields!(RangeToInclusive, end); impl GetSize for RangeFull {} impl GetSize for RangeInclusive { #[inline] fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (start_size, tracker) = (*self.start()).get_heap_size_with_tracker(tracker); let (end_size, tracker) = (*self.end()).get_heap_size_with_tracker(tracker); (start_size + end_size, tracker) } } get-size2-0.10.1/src/impls/std_types.rs000064400000000000000000000106031046102023000160130ustar 00000000000000use std::ffi::{CStr, CString, OsStr, OsString}; use std::io::{BufReader, BufWriter, Write}; use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::Arc; use crate::{GetSize, GetSizeTracker}; impl GetSize for String { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.capacity(), tracker) } } impl GetSize for &str {} impl GetSize for CString { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.as_bytes_with_nul().len(), tracker) } } impl GetSize for &CStr { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.to_bytes_with_nul().len(), tracker) } } impl GetSize for OsString { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } impl GetSize for &OsStr { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } impl GetSize for PathBuf { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.capacity(), tracker) } } impl GetSize for &Path {} impl GetSize for std::fs::DirBuilder {} impl GetSize for std::fs::DirEntry {} impl GetSize for std::fs::File {} impl GetSize for std::fs::FileType {} impl GetSize for std::fs::Metadata {} impl GetSize for std::fs::OpenOptions {} impl GetSize for std::fs::Permissions {} impl GetSize for std::fs::ReadDir {} impl GetSize for BufReader where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (total, tracker) = T::get_heap_size_with_tracker(self.get_ref(), tracker); (total + self.capacity(), tracker) } } impl GetSize for BufWriter where T: GetSize + Write, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (total, tracker) = T::get_heap_size_with_tracker(self.get_ref(), tracker); (total + self.capacity(), tracker) } } impl GetSize for Box<[T]> where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); let allocation_size = self.len() * T::get_stack_size(); (size + allocation_size, tracker) } } impl GetSize for Box { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } impl GetSize for Rc<[T]> where T: GetSize, { fn get_heap_size_with_tracker(&self, mut tracker: Tr) -> (usize, Tr) { if !tracker.track(Self::as_ptr(self).cast::<()>()) { return (0, tracker); } let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); let allocation_size = self.len() * T::get_stack_size(); (size + allocation_size, tracker) } } impl GetSize for Rc { fn get_heap_size_with_tracker(&self, mut tracker: T) -> (usize, T) { if !tracker.track(Self::as_ptr(self).cast::<()>()) { return (0, tracker); } (self.len(), tracker) } } impl GetSize for Arc<[T]> where T: GetSize, { fn get_heap_size_with_tracker(&self, mut tracker: Tr) -> (usize, Tr) { if !tracker.track(Self::as_ptr(self).cast::<()>()) { return (0, tracker); } let (size, tracker) = self.iter().fold((0, tracker), |(size, tracker), element| { let (elem_size, tracker) = T::get_heap_size_with_tracker(element, tracker); (size + elem_size, tracker) }); let allocation_size = self.len() * T::get_stack_size(); (size + allocation_size, tracker) } } impl GetSize for Arc { fn get_heap_size_with_tracker(&self, mut tracker: T) -> (usize, T) { if !tracker.track(Self::as_ptr(self).cast::<()>()) { return (0, tracker); } (self.len(), tracker) } } get-size2-0.10.1/src/impls/sync_impls.rs000064400000000000000000000036071046102023000161630ustar 00000000000000use std::cell::RefCell; use std::sync::{Mutex, OnceLock, RwLock}; use crate::{GetSize, GetSizeTracker}; impl GetSize for Mutex where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { // We assume that a `Mutex` holds its data on the stack. let guard = self .lock() .unwrap_or_else(std::sync::PoisonError::into_inner); T::get_heap_size_with_tracker(&*guard, tracker) } } impl GetSize for RwLock where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { // We assume that a `RwLock` holds its data on the stack. let guard = self .read() .unwrap_or_else(std::sync::PoisonError::into_inner); T::get_heap_size_with_tracker(&*guard, tracker) } } impl GetSize for RefCell where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { // We assume that a `RefCell` holds its data on the stack. // Use try_borrow to avoid panicking if the RefCell is already mutably borrowed match self.try_borrow() { Ok(borrowed) => T::get_heap_size_with_tracker(&*borrowed, tracker), Err(_) => { // If the RefCell is already mutably borrowed, we cannot safely access it. // Return 0 for heap size to avoid panic, though this is a rare edge case. (0, tracker) } } } } impl GetSize for OnceLock where T: GetSize, { fn get_heap_size_with_tracker(&self, tracker: Tr) -> (usize, Tr) { // We assume that a `OnceLock` holds its data on the stack. match self.get() { None => (0, tracker), Some(value) => T::get_heap_size_with_tracker(value, tracker), } } } get-size2-0.10.1/src/lib.md000064400000000000000000000272111046102023000133760ustar 00000000000000Determine the size in bytes an object occupies inside RAM. The [`GetSize`] trait can be used to determine the size of an object inside the stack as well as in the heap. The [`size_of`](std::mem::size_of) function provided by the standard library can already be used to determine the size of an object in the stack, but many application (e.g. for caching) do also need to know the number of bytes occupied inside the heap, for which this library provides an appropriate trait. #### Example We use [`GetSize`] to determine number of bytes occupied by both a [`String`] and a [`Vec`] of bytes. Note that the [`Vec`] has already allocated a capacity of `1024` bytes, and does thus correctly show a heap size of `1024`, even if only `1` byte is currently in use. ```rust use get_size2::GetSize; fn main() { let value = String::from("Hello World!"); assert_eq!(String::get_stack_size(), std::mem::size_of::()); assert_eq!(value.get_heap_size(), 12); assert_eq!(value.get_size(), std::mem::size_of::() + 12); let mut buffer = Vec::with_capacity(1024); // 1KB allocated on the heap. buffer.push(1u8); // 1 byte in use. assert_eq!(buffer.len(), 1); assert_eq!(buffer.get_heap_size(), 1024); } ``` # Ownership based accounting This library follows the idea that only bytes owned by a certain object should be accounted for, and not bytes owned by different objects which are only borrowed. This means in particular that objects referenced by pointers are ignored. #### Example ```rust use get_size2::GetSize; #[derive(GetSize)] struct Test<'a> { value: &'a String, } fn main() { let value = String::from("hello"); // This string occupies 5 bytes at the heap, but a pointer is treated as not occupying // anything at the heap. assert_eq!(value.get_heap_size(), 5); assert_eq!(GetSize::get_heap_size(&&value), 0); // Fully qualified syntax // WARNING: Due to rust's automatic dereferencing, a simple pointer will be dereferenced // to the original value, causing the borrowed bytes to be accounted for too. assert_eq!((&value).get_heap_size(), 5); // The above gets rewritten by to compiler into: // assert_eq!(value.get_heap_size(), 5); // Our derive macro uses fully qualified syntax, so auto-dereferencing does // not occur. let value = Test { value: &value, }; // The String is now only borrowed, leading to its heap bytes not being // accounted for. assert_eq!(value.get_heap_size(), 0); } ``` On the other hand references implemented as shared ownership are treated as owned values. It is your responsibility to ensure that the bytes occupied by them are not counted twice in your application. The `ignore` attribute might be helpful, [see below](#ignoring-certain-values). #### Example ```rust use std::sync::Arc; use get_size2::GetSize; fn main() { let value = String::from("hello"); assert_eq!(value.get_heap_size(), 5); // From a technical point of view, Arcs own the data they reference. // Given so their heap data gets accounted for too. // Note that an Arc does store the String's stack bytes also inside the heap. let value = Arc::new(value); assert_eq!(value.get_heap_size(), std::mem::size_of::() + 5); } ``` # How to implement The [`GetSize`] trait is already implemented for most objects defined by the standard library, like [`Vec`](std::vec::Vec), [`HashMap`](std::collections::HashMap), [`String`] as well as all the primitive values, like [`u8`], [`i32`] etc. Unless you have a complex data structure which requires a manual implementation, you can easily derive [`GetSize`] for your own structs and enums. The derived implementation will implement [`GetSize::get_heap_size`] by simply calling [`GetSize::get_heap_size`] on all values contained inside the struct or enum variant and return the sum of them. You will need to activate the `derive` feature first, which is disabled by default. Add the following to your `cargo.toml`: ```toml get-size2 = { version = "^0.7", features = ["derive"] } ``` Note that the derive macro _does not support unions_. You have to manually implement it for them. ### Examples Deriving [`GetSize`] for a struct: ```rust use get_size2::GetSize; #[derive(GetSize)] pub struct OwnStruct { value1: String, value2: u64, } fn main() { let test = OwnStruct { value1: "Hello".into(), value2: 123, }; assert_eq!(test.get_heap_size(), 5); } ``` Deriving [`GetSize`] for an enum: ```rust use get_size2::GetSize; #[derive(GetSize)] pub enum TestEnum { Variant1(u8, u16, u32), Variant2(String), Variant3, Variant4{x: String, y: String}, } #[derive(GetSize)] pub enum TestEnumNumber { Zero = 0, One = 1, Two = 2, } fn main() { let test = TestEnum::Variant1(1, 2, 3); assert_eq!(test.get_heap_size(), 0); let test = TestEnum::Variant2("Hello".into()); assert_eq!(test.get_heap_size(), 5); let test = TestEnum::Variant3; assert_eq!(test.get_heap_size(), 0); let test = TestEnum::Variant4{x: "Hello".into(), y: "world".into()}; assert_eq!(test.get_heap_size(), 5 + 5); let test = TestEnumNumber::One; assert_eq!(test.get_heap_size(), 0); } ``` The derive macro does also work with generics. The generated trait implementation will by default require all generic types to implement [`GetSize`] themselves, but this [can be changed](#ignoring-certain-generic-types). ```rust use get_size2::GetSize; #[derive(GetSize)] struct TestStructGenerics { value1: A, value2: B, } #[derive(GetSize)] enum TestEnumGenerics { Variant1(A), Variant2(B), } fn main() { let test: TestStructGenerics = TestStructGenerics { value1: "Hello".into(), value2: 123, }; assert_eq!(test.get_heap_size(), 5); let test = String::from("Hello"); let test: TestEnumGenerics = TestEnumGenerics::Variant1(test); assert_eq!(test.get_heap_size(), 5); let test: TestEnumGenerics = TestEnumGenerics::Variant2(100); assert_eq!(test.get_heap_size(), 0); } ``` ## Dealing with external types which do not implement `GetSize` Deriving [`GetSize`] is straight forward if all the types contained in your data structure implement [`GetSize`] themselves, but this might not always be the case. For that reason the derive macro offers some helpers to assist you in that case. Note that the helper attributes are supported for structs (named and tuple; `size_fn` requires named fields). For enums, only `ignore` is supported on named fields. ### Ignoring certain values You can tell the derive macro to ignore certain struct fields by adding the `ignore` attribute to them. The generated implementation of [`GetSize::get_heap_size`] will then simple skip this field. #### Example The idiomatic use case for this helper is if you use shared ownership and do not want your data to be counted twice. ```rust use std::sync::Arc; use get_size2::GetSize; #[derive(GetSize)] struct PrimaryStore { id: u64, shared_data: Arc>, } #[derive(GetSize)] struct SecondaryStore { id: u64, #[get_size(ignore)] shared_data: Arc>, } fn main() { let shared_data = Arc::new(Vec::with_capacity(1024)); let primary_data = PrimaryStore { id: 1, shared_data: Arc::clone(&shared_data), }; let secondary_data = SecondaryStore { id: 2, shared_data, }; // Note that Arc does also store the Vec's stack data on the heap. assert_eq!(primary_data.get_heap_size(), Vec::::get_stack_size() + 1024); assert_eq!(secondary_data.get_heap_size(), 0); } ``` #### Example But you may also use this as a band aid, if a certain struct fields type does not implement [`GetSize`]. Be aware though that this will result in an implementation which will return incorrect results, unless the heap size of that type is indeed always zero and can thus be ignored. It is therefor advisable to use one of the next two helper options instead. ```rust use get_size2::GetSize; // Does not implement GetSize! struct TestStructNoGetSize { value: String, } // Implements GetSize, even though one field's type does not implement it. #[derive(GetSize)] struct TestStruct { name: String, #[get_size(ignore)] ignored_value: TestStructNoGetSize, } fn main() { let ignored_value = TestStructNoGetSize { value: "Hello world!".into(), }; let test = TestStruct { name: "Adam".into(), ignored_value, }; // Note that the result is lower then it should be. assert_eq!(test.get_heap_size(), 4); } ``` ### Returning a fixed value In same cases you may be dealing with external types which allocate a fixed amount of bytes at the heap. In this case you may use the `size` attribute to always account the given field with a fixed value. ```rust use get_size2::GetSize; # # struct Buffer1024 {} # # impl Buffer1024 { # fn new() -> Self { # Self {} # } # } #[derive(GetSize)] struct TestStruct { id: u64, #[get_size(size = 1024)] buffer: Buffer1024, // Always allocates exactly 1KB at the heap. } fn main() { let test = TestStruct { id: 1, buffer: Buffer1024::new(), }; assert_eq!(test.get_heap_size(), 1024); } ``` ### Using a helper function In same cases you may be dealing with an external data structure for which you know how to calculate its heap size using its public methods. In that case you may either use the newtype pattern to implement [`GetSize`] for it directly, or you can use the `size_fn` attribute, which will call the given function in order to calculate the fields heap size. The latter is especially useful if you can make use of a certain trait to calculate the heap size for multiple types. Note that unlike in other crates, the name of the function to be called is **not** encapsulated by double-quotes ("), but rather given directly. ```rust use get_size2::GetSize; # # type ExternalVecAlike = Vec; #[derive(GetSize)] struct TestStruct { id: u64, #[get_size(size_fn = vec_alike_helper)] buffer: ExternalVecAlike, } // NOTE: We assume that slice.len()==slice.capacity() fn vec_alike_helper(slice: &V) -> usize where V: AsRef<[T]>, { std::mem::size_of::() * slice.as_ref().len() } fn main() { let buffer = vec![0u8; 512]; let buffer: ExternalVecAlike = buffer.into(); let test = TestStruct { id: 1, buffer, }; assert_eq!(test.get_heap_size(), 512); } ``` ### Ignoring certain generic types If your struct uses generics, but the fields at which they are stored are ignored or get handled by helpers because the generic does not implement [`GetSize`], you will have to mark these generics with a special struct level `ignore` attribute. Otherwise the derived [`GetSize`] implementation would still require these generics to implement [`GetSize`], even though there is no need for it. ```rust use get_size2::GetSize; #[derive(GetSize)] #[get_size(ignore(B, C, D))] struct TestStructHelpers { value1: A, #[get_size(size = 100)] value2: B, #[get_size(size_fn = get_size_helper)] value3: C, #[get_size(ignore)] value4: D, } // Does not implement GetSize struct NoGS {} fn get_size_helper(_value: &C) -> usize { 50 } fn main() { let test: TestStructHelpers = TestStructHelpers { value1: "Hello".into(), value2: NoGS {}, value3: NoGS {}, value4: 123, }; assert_eq!(test.get_heap_size(), 5 + 100 + 50); } ``` # Tracking shared ownership To avoid double-counting shared ownership (e.g. `Rc`, `Arc`), use a tracker: ```rust use get_size2::{GetSize, StandardTracker}; fn main() { let value = std::sync::Arc::new(String::from("hello")); let (heap_size, _tracker) = value.get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(heap_size, std::mem::size_of::() + 5); } ``` get-size2-0.10.1/src/lib.rs000064400000000000000000000047671046102023000134350ustar 00000000000000#![doc = include_str!("./lib.md")] #![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(feature = "derive")] #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use get_size_derive2::*; mod impls; mod tracker; pub use tracker::*; #[cfg(test)] mod tests; /// Determines how many bytes the object occupies inside the heap. pub fn heap_size(value: &T) -> usize { value.get_heap_size() } /// Determine the size in bytes an object occupies inside RAM. pub trait GetSize: Sized { /// Determines how may bytes this object occupies inside the stack. /// /// The default implementation uses [`std::mem::size_of`] and should work for almost all types. #[must_use] fn get_stack_size() -> usize { std::mem::size_of::() } /// Determines how many bytes this object occupies inside the heap. /// /// The default implementation simply delegates to [`get_heap_size_with_tracker`](Self::get_heap_size_with_tracker) /// with a noop tracker. This method is not meant to be implemented directly, and only exists for convenience. fn get_heap_size(&self) -> usize { let tracker = NoTracker::new(true); Self::get_heap_size_with_tracker(self, tracker).0 } /// Determines how many bytes this object occupies inside the heap while using a `tracker`. /// /// The default implementation returns 0, assuming the object is fully allocated on the stack. /// It must be adjusted as appropriate for objects which hold data inside the heap. fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (0, tracker) } /// Determines the total size of the object. /// /// The default implementation simply adds up the results of [`get_stack_size`](Self::get_stack_size) /// and [`get_heap_size`](Self::get_heap_size) and is not meant to be changed. fn get_size(&self) -> usize { Self::get_stack_size() + GetSize::get_heap_size(self) } /// Determines the total size of the object while using a `tracker`. /// /// The default implementation simply adds up the results of [`get_stack_size`](Self::get_stack_size) /// and [`get_heap_size_with_tracker`](Self::get_heap_size_with_tracker) and is not meant to /// be changed. fn get_size_with_tracker(&self, tracker: T) -> (usize, T) { let stack_size = Self::get_stack_size(); let (heap_size, tracker) = Self::get_heap_size_with_tracker(self, tracker); (stack_size + heap_size, tracker) } } get-size2-0.10.1/src/tests/feature.rs000064400000000000000000000267731046102023000154650ustar 00000000000000use std::mem::size_of; use get_size2::*; #[test] fn chrono() { use chrono::TimeZone; let timedelta = chrono::TimeDelta::seconds(5); assert_eq!(timedelta.get_heap_size(), 0); let datetime = chrono::Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(); assert_eq!(datetime.naive_utc().get_heap_size(), 0); assert_eq!(datetime.naive_utc().date().get_heap_size(), 0); assert_eq!(datetime.naive_utc().time().get_heap_size(), 0); assert_eq!(datetime.timezone().get_heap_size(), 0); assert_eq!(datetime.fixed_offset().timezone().get_heap_size(), 0); assert_eq!(datetime.get_heap_size(), 0); } #[test] fn chrono_tz() { use chrono::TimeZone; let datetime = chrono_tz::UTC .with_ymd_and_hms(2014, 7, 8, 9, 10, 11) .unwrap(); assert_eq!(datetime.offset().get_heap_size(), 0); } #[test] fn url() { const URL_STR: &str = "https://example.com/path?a=b&c=d"; let url = url::Url::parse(URL_STR).unwrap(); assert_eq!(url.get_heap_size(), URL_STR.len()); } #[test] fn bytes() { const BYTES_STR: &str = "Hello world"; let bytes = bytes::Bytes::from(BYTES_STR); assert_eq!(bytes.get_heap_size(), BYTES_STR.len()); let mut bytes_mut = bytes::BytesMut::from(BYTES_STR); assert_eq!(bytes_mut.get_heap_size(), BYTES_STR.len()); bytes_mut.truncate(0); assert_eq!(bytes_mut.get_heap_size(), 0); } #[test] fn compact_str() { const STR: &str = "Hello world"; const LONG_STR: &str = "A much looooonger string that exceeds 24 bytes."; let value = compact_str::CompactString::from(STR); assert_eq!(value.get_heap_size(), 0); let mut value = compact_str::CompactString::from(LONG_STR); assert_eq!(value.get_heap_size(), value.capacity()); value.shrink_to_fit(); assert_eq!(value.len(), value.capacity()); assert_eq!(value.get_heap_size(), LONG_STR.len()); } #[test] fn test_dashmap() { const VALUE_STR: &str = "Hello world"; let map: dashmap::DashMap = dashmap::DashMap::new(); assert_eq!(map.get_heap_size(), 0); map.insert(0, String::from(VALUE_STR)); assert!(map.get_heap_size() >= size_of::<(i32, String)>() + VALUE_STR.len()); let set: dashmap::DashSet = dashmap::DashSet::new(); assert_eq!(set.get_heap_size(), 0); set.insert(String::from(VALUE_STR)); assert!(set.get_heap_size() >= size_of::() + VALUE_STR.len()); } #[test] fn test_half() { let a = half::f16::from_f32(1.5); assert_eq!(a.get_heap_size(), 0); assert_eq!(a.get_size(), size_of::()); let b = half::bf16::from_f32(1.5); assert_eq!(b.get_heap_size(), 0); assert_eq!(b.get_size(), size_of::()); } #[test] fn hashbrown() { use std::hash::{BuildHasher, RandomState}; const VALUE_STR: &str = "A very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooonng string."; let hasher = RandomState::new(); let mut map = hashbrown::HashTable::new(); assert_eq!(map.get_heap_size(), 0); map.insert_unique( hasher.hash_one(VALUE_STR), String::from(VALUE_STR), |value| hasher.hash_one(value), ); assert!(map.get_heap_size() >= size_of::() + VALUE_STR.len()); let mut map = hashbrown::HashMap::::default(); assert_eq!(map.get_heap_size(), 0); map.insert(0, String::from(VALUE_STR)); assert!(map.get_heap_size() >= size_of::<(i32, String)>() + VALUE_STR.len()); let mut set = hashbrown::HashSet::::default(); assert_eq!(set.get_heap_size(), 0); set.insert(String::from(VALUE_STR)); assert!(set.get_heap_size() >= size_of::() + VALUE_STR.len()); } #[test] fn smallvec() { const ITEM_STR: &str = "Hello world"; let mut vec = smallvec::SmallVec::<[String; 2]>::from([String::new(), String::from(ITEM_STR)]); assert_eq!(vec.get_heap_size(), ITEM_STR.len()); vec.push(String::new()); assert_eq!( vec.get_heap_size(), ITEM_STR.len() + std::mem::size_of::() * vec.capacity() ); vec.shrink_to_fit(); assert_eq!( vec.get_heap_size(), ITEM_STR.len() + std::mem::size_of::() * 3 ); } #[test] fn thin_vec() { const ITEM_STR: &str = "Hello world"; assert_eq!(thin_vec::ThinVec::::default().get_heap_size(), 0); let mut vec = thin_vec::ThinVec::::from([String::new(), String::from(ITEM_STR)]); assert_eq!( vec.get_heap_size(), ITEM_STR.len() + std::mem::size_of::() * vec.capacity() + std::mem::size_of::() * 2 ); vec.shrink_to_fit(); assert_eq!( vec.get_heap_size(), ITEM_STR.len() + std::mem::size_of::() * vec.len() + std::mem::size_of::() * 2 ); } #[test] fn test_indexmap() { use std::hash::RandomState; const VALUE_STR: &str = "A very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooonng string."; let hasher = RandomState::new(); let mut map = indexmap::IndexMap::with_capacity_and_hasher(1, hasher); assert_eq!(map.get_heap_size(), 40); map.insert(VALUE_STR, String::from(VALUE_STR)); assert!(map.get_heap_size() >= size_of::<(&'static str, String)>() + VALUE_STR.len()); let mut map = indexmap::IndexMap::::default(); assert_eq!(map.get_heap_size(), 0); map.insert(0, String::from(VALUE_STR)); assert!(map.get_heap_size() >= size_of::<(i32, String)>() + VALUE_STR.len()); let mut set = indexmap::IndexSet::::default(); assert_eq!(set.get_heap_size(), 0); set.insert(String::from(VALUE_STR)); assert!(set.get_heap_size() >= size_of::() + VALUE_STR.len()); } #[test] fn test_parking_lot() { use std::sync::Arc; const S: &str = "Hello world"; let v = vec![String::from(S)]; let expected = size_of::() + S.len(); let m = parking_lot::Mutex::new(v.clone()); assert_eq!(m.get_heap_size(), expected); let r = parking_lot::RwLock::new(v); assert_eq!(r.get_heap_size(), expected); let tracker = Arc::new(parking_lot::Mutex::new(StandardTracker::new())); let (size, _) = r.get_heap_size_with_tracker(tracker); assert_eq!(size, expected); } #[test] fn test_ordermap() { use std::hash::RandomState; const VALUE_STR: &str = "A very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooonng string."; let hasher = RandomState::new(); let mut map = ordermap::OrderMap::with_capacity_and_hasher(1, hasher); assert_eq!(map.get_heap_size(), 40); map.insert(VALUE_STR, String::from(VALUE_STR)); assert!(map.get_heap_size() >= size_of::<(&'static str, String)>() + VALUE_STR.len()); let mut map = ordermap::OrderMap::::default(); assert_eq!(map.get_heap_size(), 0); map.insert(0, String::from(VALUE_STR)); assert!(map.get_heap_size() >= size_of::<(i32, String)>() + VALUE_STR.len()); let mut set = ordermap::OrderSet::::default(); assert_eq!(set.get_heap_size(), 0); set.insert(String::from(VALUE_STR)); assert!(set.get_heap_size() >= size_of::() + VALUE_STR.len()); } #[test] fn test_roaring_bitmap() { // Empty bitmap: no containers, no allocations. let empty = roaring::RoaringBitmap::new(); assert_eq!(empty.get_heap_size(), 0); // Dense run that fits in one array container: should equal what // `statistics()` reports for an array container — `capacity * 4`. let dense: roaring::RoaringBitmap = (1..100).collect(); let stats = dense.statistics(); assert_eq!(stats.n_containers, 1); assert_eq!(stats.n_array_containers, 1); assert_eq!(dense.get_heap_size() as u64, stats.n_bytes_array_containers); assert!(dense.get_heap_size() > 0); // Bitmap container kicks in past ~4096 entries; verify we count // the fixed 8 KiB allocation. Equality against the sum of all three // flavor totals catches regressions that drop a flavor. let wide: roaring::RoaringBitmap = (0..5000).collect(); let stats = wide.statistics(); assert!(stats.n_bitset_containers >= 1); assert_eq!( wide.get_heap_size() as u64, stats.n_bytes_array_containers + stats.n_bytes_bitset_containers + stats.n_bytes_run_containers ); // Run containers are produced by `optimize()` when a container has // long dense runs. Verify we count run-container bytes too. let mut run = (0..10_000).collect::(); run.optimize(); let stats = run.statistics(); assert!(stats.n_run_containers >= 1); assert_eq!( run.get_heap_size() as u64, stats.n_bytes_array_containers + stats.n_bytes_bitset_containers + stats.n_bytes_run_containers ); // Tracker-variant: threading a real tracker through must return the // same size as the no-tracker path. let tracker = StandardTracker::new(); let (size, _) = wide.get_heap_size_with_tracker(tracker); assert_eq!(size, wide.get_heap_size()); } #[test] fn test_roaring_treemap() { let empty = roaring::RoaringTreemap::new(); assert_eq!(empty.get_heap_size(), 0); // Two high-32-bit partitions → two inner RoaringBitmaps. The second // partition holds many values so the per-bitmap heap size is // non-trivial (exercises propagation through the BTreeMap walk). let mut tm = roaring::RoaringTreemap::new(); tm.insert(1); for v in 0..5000u64 { tm.insert((1u64 << 32) + v); } let mut bitmap_count = 0; let mut expected_inner: usize = 0; for (_, bitmap) in tm.bitmaps() { bitmap_count += 1; expected_inner += bitmap.get_heap_size() + size_of::() + size_of::(); } assert_eq!(bitmap_count, 2); assert_eq!(tm.get_heap_size(), expected_inner); // Tracker-variant: threading a tracker through the BTreeMap walk // must match the no-tracker path. let tracker = StandardTracker::new(); let (size, _) = tm.get_heap_size_with_tracker(tracker); assert_eq!(size, tm.get_heap_size()); } fn test_orx_concurrent_vec() { use orx_concurrent_vec::{ConcurrentElement, ConcurrentVec}; const S: &str = "Hello world"; let empty: ConcurrentVec = ConcurrentVec::new(); assert_eq!( empty.get_heap_size(), empty.capacity() * size_of::>() ); let vec: ConcurrentVec = ConcurrentVec::new(); vec.extend(0u32..16); assert_eq!( vec.get_heap_size(), vec.capacity() * size_of::>() ); let vec: ConcurrentVec = ConcurrentVec::new(); vec.push(String::from(S)); vec.push(String::from(S)); let expected = vec.capacity() * size_of::>() + S.len() * 2; assert_eq!(vec.get_heap_size(), expected); let tracker = StandardTracker::new(); let (size, _) = vec.get_heap_size_with_tracker(tracker); assert_eq!(size, vec.get_heap_size()); } get-size2-0.10.1/src/tests/mod.rs000064400000000000000000000437111046102023000146000ustar 00000000000000#![expect(dead_code, clippy::unwrap_used, reason = "This is a test module")] use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; use std::ffi::{CStr, CString, OsStr, OsString}; use std::io::{BufReader, BufWriter}; use std::mem::size_of; use std::path::{Path, PathBuf}; use std::rc::{Rc, Weak as RcWeak}; use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak as ArcWeak}; use get_size2::*; mod feature; #[derive(GetSize)] pub struct TestStruct { value1: String, value2: u64, } #[test] fn derive_struct() { let test = TestStruct { value1: "Hello".into(), value2: 123, }; assert_eq!(test.get_heap_size(), 5); } #[derive(GetSize)] pub struct TestStructGenerics { value1: A, value2: B, } #[test] fn derive_struct_with_generics() { let test: TestStructGenerics = TestStructGenerics { value1: "Hello".into(), value2: 123, }; assert_eq!(test.get_heap_size(), 5); } #[derive(GetSize)] #[get_size(ignore(B, C))] struct TestStructGenericsIgnore { value1: A, #[get_size(ignore)] value2: B, #[get_size(ignore)] value3: C, } struct TestStructNoGetSize { value: String, } #[test] fn derive_struct_with_generics_and_ignore() { let no_impl = TestStructNoGetSize { value: "World!".into(), }; let test: TestStructGenericsIgnore = TestStructGenericsIgnore { value1: "Hello".into(), value2: 123, value3: no_impl, }; assert_eq!(test.get_heap_size(), 5); } #[derive(GetSize)] #[get_size(ignore(B, C))] struct TestStructHelpers { value1: A, #[get_size(size = 100)] value2: B, #[get_size(size_fn = get_size_helper)] value3: C, } const fn get_size_helper(_value: &C) -> usize { 50 } #[test] fn derive_struct_with_generics_and_helpers() { let no_impl = TestStructNoGetSize { value: "World!".into(), }; let test: TestStructHelpers = TestStructHelpers { value1: "Hello".into(), value2: 123, value3: no_impl, }; assert_eq!(test.get_heap_size(), 5 + 100 + 50); } #[derive(GetSize)] pub struct TestStructGenericsLifetimes<'a, A, B> { value1: A, value2: &'a B, } #[test] fn derive_struct_with_generics_and_lifetimes() { let value = 123u64; let test: TestStructGenericsLifetimes<'_, String, u64> = TestStructGenericsLifetimes { value1: "Hello".into(), value2: &value, }; assert_eq!(test.get_heap_size(), 5); } #[derive(GetSize)] pub enum TestEnum { Variant1(u8, u16, u32), Variant2(String), Variant3(i64, Vec), Variant4(String, i32, Vec, bool, &'static str), Variant5(f64, TestStruct), Variant6, Variant7 { x: String, y: String }, } #[test] fn derive_enum() { let test = TestEnum::Variant1(1, 2, 3); assert_eq!(test.get_heap_size(), 0); let test = TestEnum::Variant2("Hello".into()); assert_eq!(test.get_heap_size(), 5); let test = TestEnum::Variant3(-12, vec![1, 2, 3]); assert_eq!(test.get_heap_size(), 6); let s: String = "Test".into(); assert_eq!(s.get_heap_size(), 4); let v = vec![1, 2, 3, 4]; assert_eq!(v.get_heap_size(), 16); let test = TestEnum::Variant4(s, -123, v, false, "Hello world!"); assert_eq!(test.get_heap_size(), 4 + 16); let test_struct = TestStruct { value1: "Hello world".into(), value2: 123, }; let test = TestEnum::Variant5(12.34, test_struct); assert_eq!(test.get_heap_size(), 11); let test = TestEnum::Variant6; assert_eq!(test.get_heap_size(), 0); let test = TestEnum::Variant7 { x: "Hello".into(), y: "world".into(), }; assert_eq!(test.get_heap_size(), 5 + 5); } #[derive(GetSize)] pub enum TestEnumGenerics<'a, A, B, C> { Variant1(A), Variant2(B), Variant3(&'a C), } #[test] fn derive_enum_generics() { let test: TestEnumGenerics<'_, u64, String, TestStruct> = TestEnumGenerics::Variant1(123); assert_eq!(test.get_heap_size(), 0); let test: TestEnumGenerics<'_, u64, String, TestStruct> = TestEnumGenerics::Variant2("Hello".into()); assert_eq!(test.get_heap_size(), 5); let test_struct = TestStruct { value1: "Hello world".into(), value2: 123, }; let test: TestEnumGenerics<'_, u64, String, TestStruct> = TestEnumGenerics::Variant3(&test_struct); assert_eq!(test.get_heap_size(), 0); } const MINIMAL_NODE_SIZE: usize = 3; #[derive(Clone, GetSize)] enum Node where T: Default, { Block(T), Blocks(Box<[T; MINIMAL_NODE_SIZE * MINIMAL_NODE_SIZE * MINIMAL_NODE_SIZE]>), Nodes(Box<[Self; 8]>), } #[test] fn derive_enum_generics_issue1() { let test: Node = Node::Block("test".into()); assert_eq!(test.get_heap_size(), 4); let test: Node = Node::Blocks(Box::new([123; 27])); assert_eq!(test.get_heap_size(), 8 * 27); let t1: Node = Node::Block(123); let t2 = t1.clone(); let t3 = t1.clone(); let t4 = t1.clone(); let t5 = t1.clone(); let t6 = t1.clone(); let t7 = t1.clone(); let t8 = t1.clone(); let test: Node = Node::Nodes(Box::new([t1, t2, t3, t4, t5, t6, t7, t8])); assert_eq!(test.get_heap_size(), 8 * std::mem::size_of::>()); } #[derive(GetSize)] pub enum TestEnum2 { Zero = 0, One = 1, Two = 2, } #[test] fn derive_enum_c_style() { assert_eq!(TestEnum2::Zero.get_heap_size(), 0); assert_eq!(TestEnum2::One.get_heap_size(), 0); assert_eq!(TestEnum2::Two.get_heap_size(), 0); } #[derive(GetSize)] pub struct TestNewType(u64); #[test] fn derive_newtype() { let test = TestNewType(0); assert_eq!(u64::get_stack_size(), test.get_size()); } #[test] fn tracker() { #[derive(GetSize, Clone)] struct RcWrapper(Rc); let shared = RcWrapper(Rc::new(5)); let (size, _) = (shared.clone(), shared.clone()).get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(size, shared.get_heap_size()); let vec = vec![shared.clone(); 100]; let (size, _) = vec.get_heap_size_with_tracker(StandardTracker::new()); assert_eq!( size, (std::mem::size_of::>() * 100) + shared.get_heap_size() ); } #[test] fn boxed_slice() { let boxed = vec![1u8; 10].into_boxed_slice(); assert_eq!(boxed.get_heap_size(), size_of::() * boxed.len()); let boxed = vec![1u32; 10].into_boxed_slice(); assert_eq!(boxed.get_heap_size(), size_of::() * boxed.len()); let boxed = vec![&1u8; 10].into_boxed_slice(); assert_eq!(boxed.get_heap_size(), size_of::<&u8>() * boxed.len()); let rc = Rc::<[u8]>::from([1u8; 10]); assert_eq!(rc.get_heap_size(), size_of::() * rc.len()); let arc = Arc::<[u8]>::from([1u8; 10]); assert_eq!(arc.get_heap_size(), size_of::() * arc.len()); let shared_rc = Rc::<[String]>::from([String::from("hello"), String::from("world")]); let (size, _) = (shared_rc.clone(), shared_rc.clone()).get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(size, shared_rc.get_heap_size()); let shared_arc = Arc::<[String]>::from([String::from("hello"), String::from("world")]); let (size, _) = (shared_arc.clone(), shared_arc.clone()).get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(size, shared_arc.get_heap_size()); } #[test] fn boxed_str() { let boxed: Box = "a".to_owned().into(); assert_eq!(boxed.get_heap_size(), size_of::() * boxed.len()); let rc: Rc = "a".to_owned().into(); assert_eq!(rc.get_heap_size(), size_of::() * boxed.len()); let (size, _) = (rc.clone(), rc.clone()).get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(size, rc.get_heap_size()); let arc: Arc = "a".to_owned().into(); assert_eq!(arc.get_heap_size(), size_of::() * boxed.len()); let (size, _) = (arc.clone(), arc.clone()).get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(size, arc.get_heap_size()); } #[test] fn cow() { use std::borrow::Cow; let cow: Cow<'_, str> = Cow::Borrowed("Hello world"); assert_eq!(cow.get_heap_size(), 0); let cow: Cow<'_, str> = Cow::Owned("Hello world".into()); assert_eq!(cow.get_heap_size(), 11); } #[test] fn once_lock() { let lock: OnceLock = OnceLock::new(); assert_eq!(lock.get_heap_size(), 0); let lock_filled: OnceLock = { let l = OnceLock::new(); l.set(String::from("HalloTest")).unwrap(); l }; assert_eq!( lock_filled.get_heap_size(), lock_filled.get().unwrap().capacity() ); } #[test] fn test_enum() { #[derive(GetSize)] enum Enum { A { #[get_size(ignore)] b: B, }, } struct B; } #[test] fn test_ignore_attribute_on_enum_field() { #[derive(GetSize)] enum WithIgnore { A { #[get_size(ignore)] data: Vec, }, } #[derive(GetSize)] enum WithoutIgnore { A { data: Vec }, } let heap_vec = vec![0u8; 100]; let with = WithIgnore::A { data: heap_vec.clone(), }; let without = WithoutIgnore::A { data: heap_vec }; let size_with_ignore = with.get_heap_size(); let size_without_ignore = without.get_heap_size(); assert!(size_with_ignore < size_without_ignore); let expected_size = size_without_ignore - size_with_ignore; assert!( expected_size >= 100, "Expected heap size contribution from Vec to be at least 100" ); } #[test] fn refcell() { let cell = RefCell::new(42u32); assert_eq!(cell.get_heap_size(), 0); assert_eq!(cell.get_size(), size_of::>()); let cell = RefCell::new(String::from("Hello, World!")); assert_eq!(cell.get_heap_size(), 13); assert_eq!(cell.get_size(), size_of::>() + 13); let cell = RefCell::new(String::new()); assert_eq!(cell.get_heap_size(), 0); let vec_data = vec![1u32, 2, 3, 4, 5]; let expected_heap_size = vec_data.capacity() * size_of::(); let cell = RefCell::new(vec_data); assert_eq!(cell.get_heap_size(), expected_heap_size); assert_eq!( cell.get_size(), size_of::>>() + expected_heap_size ); let inner = RefCell::new(String::from("nested")); let outer = RefCell::new(inner); assert_eq!(outer.get_heap_size(), 6); let cell = RefCell::new(String::from("borrowed")); { let _borrowed = cell.borrow(); assert_eq!(cell.get_heap_size(), 8); } assert_eq!(cell.get_heap_size(), 8); let cell = RefCell::new(String::from("mutable")); { let _borrowed = cell.borrow_mut(); } assert_eq!(cell.get_heap_size(), 7); let boxed = Box::new(vec![1u32, 2, 3]); let cell = RefCell::new(boxed); let expected_heap_size = size_of::>() + 3 * size_of::(); assert_eq!(cell.get_heap_size(), expected_heap_size); let cell = RefCell::new(String::from("tracker")); let (heap_size, _tracker) = cell.get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(heap_size, 7); assert_eq!(heap_size, cell.get_heap_size()); let cell = RefCell::new(()); assert_eq!(cell.get_heap_size(), 0); assert_eq!(cell.get_size(), size_of::>()); } #[test] fn covers_heap_size_function() { let value = String::from("heap"); assert_eq!(heap_size(&value), value.get_heap_size()); } #[test] fn covers_ranges() { let range = String::from("ab")..String::from("cde"); let range_expected = range.start.get_heap_size() + range.end.get_heap_size(); assert_eq!(range.get_heap_size(), range_expected); let from = (String::from("abcdef"))..; assert_eq!(from.get_heap_size(), from.start.get_heap_size()); let to = ..String::from("xyz"); assert_eq!(to.get_heap_size(), to.end.get_heap_size()); let to_inclusive = ..=String::from("xyz"); assert_eq!( to_inclusive.get_heap_size(), to_inclusive.end.get_heap_size() ); let full = ..; assert_eq!(full.get_heap_size(), 0); let inclusive = String::from("left")..=String::from("right"); let inclusive_expected = inclusive.start().get_heap_size() + inclusive.end().get_heap_size(); assert_eq!(inclusive.get_heap_size(), inclusive_expected); } #[test] fn covers_collections_remaining_branches() { let mut btree_set = BTreeSet::new(); btree_set.insert(String::from("set")); assert!(btree_set.get_heap_size() >= btree_set.iter().map(GetSize::get_size).sum::()); let mut linked = LinkedList::new(); linked.push_back(String::from("linked")); assert!(linked.get_heap_size() >= linked.iter().map(GetSize::get_size).sum::()); let mut btree_map = BTreeMap::new(); btree_map.insert(String::from("k"), String::from("value")); assert!(btree_map.get_heap_size() >= 6); let mut hash_map = HashMap::new(); hash_map.insert(String::from("k"), String::from("value")); assert!(hash_map.get_heap_size() >= std::mem::size_of::<(String, String)>()); let mut hash_set = HashSet::new(); hash_set.insert(String::from("value")); assert!(hash_set.get_heap_size() >= std::mem::size_of::()); let mut heap = BinaryHeap::new(); heap.push(String::from("value")); assert!(heap.get_heap_size() >= std::mem::size_of::()); let mut deque = VecDeque::new(); deque.push_back(String::from("value")); assert!(deque.get_heap_size() >= std::mem::size_of::()); } #[test] fn covers_ownership_remaining_branches() { let arc = Arc::new(String::from("arc")); let pair = (Arc::clone(&arc), Arc::clone(&arc)); let (tracked_size, _) = pair.get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(tracked_size, arc.as_ref().get_size()); let none_value: Option = None; assert_eq!(none_value.get_heap_size(), 0); let err_value: Result = Err(String::from("err")); assert!(err_value.get_heap_size() >= 3); let rc = Rc::new(String::from("weak")); let weak: RcWeak = Rc::downgrade(&rc); assert_eq!(weak.get_heap_size(), 0); let arc2 = Arc::new(String::from("weak")); let weak2: ArcWeak = Arc::downgrade(&arc2); assert_eq!(weak2.get_heap_size(), 0); } #[test] fn covers_std_types_remaining_branches() { let c_string = match CString::new("abc") { Ok(v) => v, Err(err) => panic!("CString::new failed: {err}"), }; assert_eq!(c_string.get_heap_size(), 4); let c_str: &CStr = c_string.as_c_str(); assert_eq!(c_str.get_heap_size(), 4); let os_string = OsString::from("hello"); assert_eq!(os_string.get_heap_size(), os_string.len()); let os_str: &OsStr = os_string.as_os_str(); assert_eq!(os_str.get_heap_size(), os_str.len()); let path_buf = PathBuf::from("folder/file.txt"); assert!(path_buf.get_heap_size() >= path_buf.as_os_str().len()); let path: &Path = path_buf.as_path(); assert_eq!(path.get_heap_size(), 0); let reader = BufReader::with_capacity(32, &b"input"[..]); assert!(reader.get_heap_size() >= 32); let writer = BufWriter::with_capacity(16, Vec::::new()); assert!(writer.get_heap_size() >= 16); } #[test] fn covers_sync_impls_and_tracker_paths() { let cell = RefCell::new(String::from("mutably-borrowed")); let borrowed = cell.borrow_mut(); assert_eq!(cell.get_heap_size(), 0); drop(borrowed); assert!(cell.get_heap_size() >= "mutably-borrowed".len()); let empty_lock: OnceLock = OnceLock::new(); assert_eq!(empty_lock.get_heap_size(), 0); let full_lock = OnceLock::from(String::from("set")); assert!(full_lock.get_heap_size() >= 3); let mutex = Mutex::new(String::from("poisoned")); std::thread::scope(|scope| { let handle = scope.spawn(|| { let _guard = match mutex.lock() { Ok(guard) => guard, Err(err) => err.into_inner(), }; panic!("intentional poison"); }); assert!(handle.join().is_err()); }); assert!(mutex.get_heap_size() >= 8); let rwlock = RwLock::new(String::from("poisoned")); std::thread::scope(|scope| { let handle = scope.spawn(|| { let _guard = match rwlock.write() { Ok(guard) => guard, Err(err) => err.into_inner(), }; panic!("intentional poison"); }); assert!(handle.join().is_err()); }); assert!(rwlock.get_heap_size() >= 8); } #[test] fn covers_tracker_trait_forwarders() { let value = 123_u64; let addr = &raw const value; let mut base = StandardTracker::new(); let mut by_ref = &mut base; assert!(GetSizeTracker::track(&mut by_ref, addr)); assert!(!GetSizeTracker::track(&mut by_ref, addr)); let mut boxed = Box::new(StandardTracker::new()); assert!(GetSizeTracker::track(&mut boxed, addr)); assert!(!GetSizeTracker::track(&mut boxed, addr)); let mut locked = Mutex::new(StandardTracker::new()); assert!(GetSizeTracker::track(&mut locked, addr)); assert!(!GetSizeTracker::track(&mut locked, addr)); let mut rw_locked = RwLock::new(StandardTracker::new()); assert!(GetSizeTracker::track(&mut rw_locked, addr)); assert!(!GetSizeTracker::track(&mut rw_locked, addr)); let mut arc_mutex = Arc::new(Mutex::new(StandardTracker::new())); assert!(GetSizeTracker::track(&mut arc_mutex, addr)); assert!(!GetSizeTracker::track(&mut arc_mutex, addr)); let mut arc_rwlock = Arc::new(RwLock::new(StandardTracker::new())); assert!(GetSizeTracker::track(&mut arc_rwlock, addr)); assert!(!GetSizeTracker::track(&mut arc_rwlock, addr)); let mut tracker = StandardTracker::new(); assert!(tracker.track(addr)); tracker.clear(); assert!(tracker.track(addr)); let mut no_tracker = NoTracker::new(false); assert!(!no_tracker.answer()); assert!(!no_tracker.track(addr)); no_tracker.set_answer(true); assert!(no_tracker.answer()); assert!(no_tracker.track(addr)); } get-size2-0.10.1/src/tracker.rs000064400000000000000000000061621046102023000143110ustar 00000000000000use std::collections::HashSet; use std::sync::{Arc, Mutex, RwLock}; /// A tracker which makes sure that shared ownership objects are only accounted for once. pub trait GetSizeTracker { /// Tracks an arbitrary object located at `addr`. /// /// Returns `true` if the reference, as indexed by the pointed to `addr`, has not yet /// been seen by this tracker. Otherwise it returns `false`. fn track(&mut self, addr: *const A) -> bool; } impl GetSizeTracker for &mut T { fn track(&mut self, addr: *const A) -> bool { GetSizeTracker::track(*self, addr) } } impl GetSizeTracker for Box { fn track(&mut self, addr: *const A) -> bool { GetSizeTracker::track(&mut **self, addr) } } impl GetSizeTracker for Mutex { fn track(&mut self, addr: *const A) -> bool { let tracker = self .get_mut() .unwrap_or_else(std::sync::PoisonError::into_inner); GetSizeTracker::track(&mut *tracker, addr) } } impl GetSizeTracker for RwLock { fn track(&mut self, addr: *const A) -> bool { let mut tracker = self .write() .unwrap_or_else(std::sync::PoisonError::into_inner); GetSizeTracker::track(&mut *tracker, addr) } } impl GetSizeTracker for Arc> { fn track(&mut self, addr: *const A) -> bool { let mut tracker = self .lock() .unwrap_or_else(std::sync::PoisonError::into_inner); GetSizeTracker::track(&mut *tracker, addr) } } impl GetSizeTracker for Arc> { fn track(&mut self, addr: *const A) -> bool { let mut tracker = self .write() .unwrap_or_else(std::sync::PoisonError::into_inner); GetSizeTracker::track(&mut *tracker, addr) } } /// A simple standard tracker which can be used to track shared ownership references. #[derive(Debug, Default)] pub struct StandardTracker { inner: HashSet, } impl StandardTracker { #[must_use] pub fn new() -> Self { Self::default() } pub fn clear(&mut self) { self.inner.clear(); } } impl GetSizeTracker for StandardTracker { fn track(&mut self, addr: *const A) -> bool { self.inner.insert(addr.addr()) } } /// A pseudo tracker which does not track anything. #[derive(Debug, Clone, Copy, Default)] pub struct NoTracker { answer: bool, } impl NoTracker { /// Creates a new pseudo tracker, which will always return the given `answer`. #[must_use] pub const fn new(answer: bool) -> Self { Self { answer } } /// Get the answer which will always be returned by this pseudo tracker. #[must_use] pub const fn answer(&self) -> bool { self.answer } /// Changes the answer which will always be returned by this pseudo tracker. pub const fn set_answer(&mut self, answer: bool) { self.answer = answer; } } impl GetSizeTracker for NoTracker { fn track(&mut self, _addr: *const A) -> bool { self.answer } }