get-size2-0.7.2/.cargo_vcs_info.json0000644000000001560000000000100126550ustar { "git": { "sha1": "28b42d90d34f29f1b19f9c5010c4d79345d7af1c" }, "path_in_vcs": "crates/get-size2" }get-size2-0.7.2/Cargo.lock0000644000000365700000000000100106410ustar # 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 = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[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.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" 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 = "derive-where" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" 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.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff47daa61505c85af126e9dd64af6a342a33dc0cccfe1be74ceadc7d352e6efd" dependencies = [ "attribute-derive", "quote", "syn", ] [[package]] name = "get-size2" version = "0.7.2" dependencies = [ "bytes", "chrono", "chrono-tz", "compact_str", "get-size-derive2", "hashbrown", "indexmap", "smallvec", "thin-vec", "url", ] [[package]] name = "hashbrown" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "icu_collections" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_normalizer" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", "icu_locale_core", "stable_deref_trait", "tinystr", "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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "indexmap" version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown", ] [[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.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "litemap" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[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 = "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.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" 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.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" 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 = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "siphasher" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[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.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" 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.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d" [[package]] name = "tinystr" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "unicode-ident" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "url" version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 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 = "writeable" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "yoke" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerotrie" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" dependencies = [ "displaydoc", "yoke", "zerofrom", ] [[package]] name = "zerovec" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", "syn", ] get-size2-0.7.2/Cargo.toml0000644000000074250000000000100106610ustar # 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.7.2" authors = [ "Denis Kerp", "Nicolas", ] build = false exclude = ["examples/*"] 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"] default = [] derive = ["get-size-derive2"] hashbrown = ["dep:hashbrown"] indexmap = ["dep:indexmap"] 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.get-size-derive2] version = "0.7.2" optional = true [dependencies.hashbrown] version = "0.16" optional = true default-features = false [dependencies.indexmap] version = "2.10" 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" cast_possible_truncation = "allow" cast_precision_loss = "allow" cast_sign_loss = "allow" clone_on_ref_ptr = "warn" create_dir = "warn" expect_used = "allow" implicit_hasher = "allow" missing_assert_message = "warn" module_name_repetitions = "allow" needless_doctest_main = "allow" panic_in_result_fn = "warn" str_to_string = "warn" todo = "warn" too_many_lines = "allow" 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.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_casts = "allow" trivial_numeric_casts = "warn" unsafe_code = "deny" unsafe_op_in_unsafe_fn = "warn" unused_extern_crates = "warn" unused_import_braces = "warn" unused_lifetimes = "warn" unused_qualifications = "allow" [lints.rust.future_incompatible] level = "warn" priority = -1 [lints.rust.nonstandard_style] level = "warn" priority = -1 [lints.rust.rust_2018_idioms] level = "warn" priority = -1 [lints.rustdoc] all = "warn" missing_crate_level_docs = "warn" get-size2-0.7.2/Cargo.toml.orig000064400000000000000000000034331046102023000143350ustar 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/*"] [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 } hashbrown = { version = "0.16", default-features = false, optional = true } indexmap = { version = "2.10", 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", "hashbrown", "indexmap", "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"] hashbrown = ["dep:hashbrown"] indexmap = ["dep:indexmap"] 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.7.2/LICENSE000064400000000000000000000021171046102023000124510ustar 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.7.2/README.md000064400000000000000000000141461046102023000127300ustar 00000000000000# get-size [![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/bircksn/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.1", 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 helpers are currently only available for regular structs, that is they do neither support tuple structs nor enums. #### 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 through there is no need for it. ## 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.7.2/src/lib.md000064400000000000000000000271631046102023000133330ustar 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: Duo 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.1", 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 helpers are currently only available for regular structs, that is they do neither support tuple structs nor enums. ### 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 through 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 through 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); } ``` get-size2-0.7.2/src/lib.rs000064400000000000000000000651641046102023000133620ustar 00000000000000#![doc = include_str!("./lib.md")] #![cfg_attr(docsrs, feature(doc_cfg))] use std::borrow::Cow; use std::cell::RefCell; use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; use 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::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; use std::rc::{Rc, Weak as RcWeak}; use std::sync::atomic::{ AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize, Ordering, }; use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak as ArcWeak}; use std::time::{Duration, Instant, SystemTime}; #[cfg(feature = "derive")] #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use get_size_derive2::*; mod tracker; pub use tracker::*; #[cfg(test)] mod test; /// 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) } } 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 {} /// This macro is similar to the derive macro; Generate a `GetSize` impl that /// adds the heap sizes of the fields that are specified. However, since we want /// to implement this also for third-party types where we cannot add the derive /// macro, we go this way. /// /// # Examples /// ```ignore /// impl_sum_of_fields!(Range, start, end); /// impl_sum_of_fields!(Person, name, address, phone); /// ``` 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) } } 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), } } } 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 value are hold 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) }) } } 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(Rc::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(Arc::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 results 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), } } } 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 at the stack. T::get_heap_size_with_tracker(&*(self.lock().expect("Mutex is poisoned")), 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 at the stack. T::get_heap_size_with_tracker(&*(self.read().expect("RwLock is poisoned")), 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 at 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 at the stack. match self.get() { None => (0, tracker), Some(value) => T::get_heap_size_with_tracker(value, tracker), } } } 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 std::ffi::CString { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.as_bytes_with_nul().len(), tracker) } } impl GetSize for &std::ffi::CStr { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.to_bytes_with_nul().len(), tracker) } } impl GetSize for std::ffi::OsString { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } impl GetSize for &std::ffi::OsStr { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } 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 std::io::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 std::io::BufWriter where T: GetSize + std::io::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 std::path::PathBuf { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.capacity(), tracker) } } impl GetSize for &std::path::Path {} 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, 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 Rc { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } impl GetSize for Arc<[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 Arc { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } #[cfg(feature = "chrono")] mod chrono { use 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) } } } #[cfg(feature = "chrono-tz")] impl GetSize for chrono_tz::TzOffset {} #[cfg(feature = "url")] impl GetSize for url::Url { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.as_str().len(), tracker) } } #[cfg(feature = "bytes")] impl GetSize for bytes::Bytes { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } #[cfg(feature = "bytes")] impl GetSize for bytes::BytesMut { fn get_heap_size_with_tracker(&self, tracker: T) -> (usize, T) { (self.len(), tracker) } } #[cfg(feature = "hashbrown")] 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) } } #[cfg(feature = "hashbrown")] 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) } } #[cfg(feature = "hashbrown")] 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) } } #[cfg(feature = "smallvec")] 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) } } #[cfg(feature = "thin-vec")] 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) } } #[cfg(feature = "compact-str")] 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) } } #[cfg(feature = "indexmap")] 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) } } #[cfg(feature = "indexmap")] 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.7.2/src/test.rs000064400000000000000000000432641046102023000135700ustar 00000000000000#![expect(dead_code, clippy::unwrap_used, reason = "This is a test module")] use std::cell::RefCell; use std::mem::size_of; use std::rc::Rc; use std::sync::Arc; use std::sync::OnceLock; use get_size2::*; #[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); // It is a pointer. } 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<[Node; 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() { let test = TestEnum2::Zero; assert_eq!(test.get_heap_size(), 0); let test = TestEnum2::One; assert_eq!(test.get_heap_size(), 0); let test = TestEnum2::Two; assert_eq!(test.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() { use std::mem::size_of; 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()); } #[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 arc: Arc = "a".to_owned().into(); assert_eq!(arc.get_heap_size(), size_of::() * boxed.len()); } #[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 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(); // `2014-07-08T09:10:11Z` 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(); // `2014-07-08T09:10:11Z` 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); } fn once_lock_get_size() { // empty OnceLock let lock: OnceLock = OnceLock::new(); assert_eq!(lock.get_heap_size(), 0); // filled OnceLock let lock_filled: OnceLock = { let l = OnceLock::new(); l.set(String::from("HalloTest")).unwrap(); l }; // The heap size of a OnceLock filled with a String is the size of the String's heap allocation. assert_eq!( lock_filled.get_heap_size(), lock_filled.get().unwrap().capacity() ); } #[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 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_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]; // known heap allocation 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(); println!("Size with ignore: {size_with_ignore}"); println!("Size without ignore: {size_without_ignore}"); // Size with ignore should be smaller than without assert!(size_with_ignore < size_without_ignore); // The ignored size should roughly match the allocation of Vec 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 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 refcell() { // Test RefCell with a simple type let cell = RefCell::new(42u32); assert_eq!(cell.get_heap_size(), 0); assert_eq!(cell.get_size(), size_of::>()); // Test RefCell with a String (has heap allocation) let cell = RefCell::new(String::from("Hello, World!")); assert_eq!(cell.get_heap_size(), 13); // "Hello, World!" is 13 bytes assert_eq!(cell.get_size(), size_of::>() + 13); // Test RefCell with an empty String let cell = RefCell::new(String::new()); assert_eq!(cell.get_heap_size(), 0); // Test RefCell with a Vec 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 ); // Test nested RefCell let inner = RefCell::new(String::from("nested")); let outer = RefCell::new(inner); // The outer RefCell should report the heap size of the String assert_eq!(outer.get_heap_size(), 6); // "nested" is 6 bytes // Test that we can get size while RefCell is borrowed let cell = RefCell::new(String::from("borrowed")); { let _borrowed = cell.borrow(); // This should still work even though the cell is borrowed assert_eq!(cell.get_heap_size(), 8); // "borrowed" is 8 bytes } // Also test after the borrow is released assert_eq!(cell.get_heap_size(), 8); // Test the edge case where RefCell is mutably borrowed let cell = RefCell::new(String::from("mutable")); { let mut _borrowed = cell.borrow_mut(); // While mutably borrowed, we cannot call get_heap_size on the same thread // without triggering the try_borrow failure path. // The implementation handles it gracefully by returning 0. } // After releasing the mutable borrow, it should work normally assert_eq!(cell.get_heap_size(), 7); // "mutable" is 7 bytes // Test RefCell with a Box let boxed = Box::new(vec![1u32, 2, 3]); let cell = RefCell::new(boxed); // The Box itself is on the heap, plus the Vec's allocation let expected_heap_size = size_of::>() + 3 * size_of::(); assert_eq!(cell.get_heap_size(), expected_heap_size); // Test RefCell with StandardTracker let cell = RefCell::new(String::from("tracker")); let (heap_size, _tracker) = cell.get_heap_size_with_tracker(StandardTracker::new()); assert_eq!(heap_size, 7); // "tracker" is 7 bytes assert_eq!(heap_size, cell.get_heap_size()); // Test RefCell with unit type let cell = RefCell::new(()); assert_eq!(cell.get_heap_size(), 0); assert_eq!(cell.get_size(), size_of::>()); } get-size2-0.7.2/src/tracker.rs000064400000000000000000000060331046102023000142350ustar 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().expect("Mutex was poisoned"); GetSizeTracker::track(&mut *tracker, addr) } } impl GetSizeTracker for RwLock { fn track(&mut self, addr: *const A) -> bool { let mut tracker = self.write().expect("RwLock was poisoned"); GetSizeTracker::track(&mut *tracker, addr) } } impl GetSizeTracker for Arc> { fn track(&mut self, addr: *const A) -> bool { let mut tracker = self.lock().expect("Mutex was poisoned"); GetSizeTracker::track(&mut *tracker, addr) } } impl GetSizeTracker for Arc> { fn track(&mut self, addr: *const A) -> bool { let mut tracker = self.write().expect("RwLock was poisoned"); 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 fn set_answer(&mut self, answer: bool) { self.answer = answer; } } impl GetSizeTracker for NoTracker { fn track(&mut self, _addr: *const A) -> bool { self.answer } }