freedesktop-icons-0.4.0/.cargo_vcs_info.json0000644000000001360000000000100144610ustar { "git": { "sha1": "2045e288773b984e3c91415a5fcb736d98509a15" }, "path_in_vcs": "" }freedesktop-icons-0.4.0/.gitignore000064400000000000000000000000231046102023000152340ustar 00000000000000/target Cargo.lock freedesktop-icons-0.4.0/Cargo.lock0000644000001205330000000000100124400ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "ahash" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0453232ace82dee0dd0b4c87a59bd90f7b53b314f3e0f61fe2ee7c8a16482289" [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cairo-rs" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae50b5510d86cf96ac2370e66d8dc960882f3df179d6a5a1e52bd94a1416c0f7" dependencies = [ "bitflags", "cairo-sys-rs", "glib", "libc", ] [[package]] name = "cairo-sys-rs" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f18b6bb8e43c7eb0f2aac7976afe0c61b6f5fc2ab7bc4c139537ea56c92290df" dependencies = [ "glib-sys", "libc", "system-deps", ] [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-expr" version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" dependencies = [ "smallvec", "target-lexicon", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "ciborium" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", "serde", ] [[package]] name = "ciborium-io" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", ] [[package]] name = "clap" version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" dependencies = [ "anstyle", "clap_lex", ] [[package]] name = "clap_lex" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "criterion" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", "is-terminal", "itertools", "num-traits", "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", "serde_derive", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", ] [[package]] name = "crossbeam-deque" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "dirs" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", "redox_users", "windows-sys 0.48.0", ] [[package]] name = "dlv-list" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" dependencies = [ "rand", ] [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "field-offset" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ "memoffset", "rustc_version", ] [[package]] name = "file-locker" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6c3e69656680c6c3d76750b46dfa64bf07626bd2130c540d6cf2d306ba595a8" dependencies = [ "nix", ] [[package]] name = "freedesktop-icons" version = "0.4.0" dependencies = [ "criterion", "dirs", "gtk4", "ini_core", "linicon", "once_cell", "speculoos", "thiserror", "tracing", "xdg", ] [[package]] name = "freedesktop_entry_parser" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db9c27b72f19a99a895f8ca89e2d26e4ef31013376e56fdafef697627306c3e4" dependencies = [ "nom", "thiserror", ] [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-macro", "futures-task", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "gdk-pixbuf" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6efc7705f7863d37b12ad6974cbb310d35d054f5108cdc1e69037742f573c4c" dependencies = [ "gdk-pixbuf-sys", "gio", "glib", "libc", ] [[package]] name = "gdk-pixbuf-sys" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67f2587c9202bf997476bbba6aaed4f78a11538a2567df002a5f57f5331d0b5c" dependencies = [ "gio-sys", "glib-sys", "gobject-sys", "libc", "system-deps", ] [[package]] name = "gdk4" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0196720118f880f71fe7da971eff58cc43a89c9cf73f46076b7cb1e60889b15" dependencies = [ "cairo-rs", "gdk-pixbuf", "gdk4-sys", "gio", "glib", "libc", "pango", ] [[package]] name = "gdk4-sys" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b0e1340bd15e7a78810cf39fed9e5d85f0a8f80b1d999d384ca17dcc452b60" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", "gio-sys", "glib-sys", "gobject-sys", "libc", "pango-sys", "pkg-config", "system-deps", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "gio" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a517657589a174be9f60c667f1fec8b7ac82ed5db4ebf56cf073a3b5955d8e2e" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-util", "gio-sys", "glib", "libc", "pin-project-lite", "smallvec", ] [[package]] name = "gio-sys" version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8446d9b475730ebef81802c1738d972db42fde1c5a36a627ebc4d665fc87db04" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", "windows-sys 0.59.0", ] [[package]] name = "glib" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f969edf089188d821a30cde713b6f9eb08b20c63fc2e584aba2892a7984a8cc0" dependencies = [ "bitflags", "futures-channel", "futures-core", "futures-executor", "futures-task", "futures-util", "gio-sys", "glib-macros", "glib-sys", "gobject-sys", "libc", "memchr", "smallvec", ] [[package]] name = "glib-macros" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68" dependencies = [ "heck", "proc-macro-crate", "proc-macro2", "quote", "syn", ] [[package]] name = "glib-sys" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b360ff0f90d71de99095f79c526a5888c9c92fc9ee1b19da06c6f5e75f0c2a53" dependencies = [ "libc", "system-deps", ] [[package]] name = "gobject-sys" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67a56235e971a63bfd75abb13ef70064e1346388723422a68580d8a6fbac6423" dependencies = [ "glib-sys", "libc", "system-deps", ] [[package]] name = "graphene-rs" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f39d3bcd2e24fd9c2874a56f277b72c03e728de9bdc95a8d4ef4c962f10ced98" dependencies = [ "glib", "graphene-sys", "libc", ] [[package]] name = "graphene-sys" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11a68d39515bf340e879b72cecd4a25c1332557757ada6e8aba8654b4b81d23a" dependencies = [ "glib-sys", "libc", "pkg-config", "system-deps", ] [[package]] name = "gsk4" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b9188db0a6219e708b6b6e7225718e459def664023dbddb8395ca1486d8102" dependencies = [ "cairo-rs", "gdk4", "glib", "graphene-rs", "gsk4-sys", "libc", "pango", ] [[package]] name = "gsk4-sys" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bca10fc65d68528a548efa3d8747934adcbe7058b73695c9a7f43a25352fce14" dependencies = [ "cairo-sys-rs", "gdk4-sys", "glib-sys", "gobject-sys", "graphene-sys", "libc", "pango-sys", "system-deps", ] [[package]] name = "gtk4" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b697ff938136625f6acf75f01951220f47a45adcf0060ee55b4671cf734dac44" dependencies = [ "cairo-rs", "field-offset", "futures-channel", "gdk-pixbuf", "gdk4", "gio", "glib", "graphene-rs", "gsk4", "gtk4-macros", "gtk4-sys", "libc", "pango", ] [[package]] name = "gtk4-macros" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ed1786c4703dd196baf7e103525ce0cf579b3a63a0570fe653b7ee6bac33999" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "syn", ] [[package]] name = "gtk4-sys" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af4b680cee5d2f786a2f91f1c77e95ecf2254522f0ca4edf3a2dce6cb35cecf" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", "gdk4-sys", "gio-sys", "glib-sys", "gobject-sys", "graphene-sys", "gsk4-sys", "libc", "pango-sys", "system-deps", ] [[package]] name = "half" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", ] [[package]] name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" dependencies = [ "ahash", ] [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "indexmap" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", ] [[package]] name = "ini_core" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a467a31a9f439b5262fa99c17084537bff57f24703d5a09a2b5c9657ec73a61" dependencies = [ "cfg-if", ] [[package]] name = "is-terminal" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" dependencies = [ "hermit-abi", "libc", "windows-sys 0.59.0", ] [[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags", "libc", ] [[package]] name = "linicon" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee8c5653188a809616c97296180a0547a61dba205bcdcbdd261dbd022a25fd9" dependencies = [ "file-locker", "freedesktop_entry_parser", "linicon-theme", "memmap2", "thiserror", ] [[package]] name = "linicon-theme" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4f8240c33bb08c5d8b8cdea87b683b05e61037aa76ff26bef40672cc6ecbb80" dependencies = [ "freedesktop_entry_parser", "rust-ini", ] [[package]] name = "log" version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] [[package]] name = "memoffset" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nix" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags", "cfg-if", "cfg_aliases", "libc", ] [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "num" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", "num-integer", "num-iter", "num-rational", "num-traits", ] [[package]] name = "num-bigint" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", ] [[package]] name = "num-complex" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-iter" version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-rational" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ "num-bigint", "num-integer", "num-traits", ] [[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.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-multimap" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" dependencies = [ "dlv-list", "hashbrown 0.9.1", ] [[package]] name = "pango" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e89bd74250a03a05cec047b43465469102af803be2bf5e5a1088f8b8455e087" dependencies = [ "gio", "glib", "libc", "pango-sys", ] [[package]] name = "pango-sys" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71787e0019b499a5eda889279e4adb455a4f3fdd6870cd5ab7f4a5aa25df6699" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", ] [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plotters" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "ppv-lite86" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rayon" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "redox_users" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", "thiserror", ] [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rust-ini" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" dependencies = [ "cfg-if", "ordered-multimap", ] [[package]] name = "rustc_version" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustversion" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "semver" version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "speculoos" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65881c9270d6157f30a09233305da51bed97eef9192d0ea21e57b1c8f05c3620" dependencies = [ "num", ] [[package]] name = "syn" version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "system-deps" version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" dependencies = [ "cfg-expr", "heck", "pkg-config", "toml", "version-compare", ] [[package]] name = "target-lexicon" version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", ] [[package]] name = "toml" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "tracing" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing-core" version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "version-compare" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" dependencies = [ "memchr", ] [[package]] name = "xdg" version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", "syn", ] freedesktop-icons-0.4.0/Cargo.toml0000644000000027540000000000100124670ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "freedesktop-icons" version = "0.4.0" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "A Freedesktop Icons lookup crate" readme = "README.md" keywords = [ "icons", "gui", "freedesktop", ] license = "MIT" repository = "https://github.com/oknozor/freedestkop-icons" [features] default = [] local_tests = [] [lib] name = "freedesktop_icons" path = "src/lib.rs" [[bench]] name = "simple_lookup" path = "benches/simple_lookup.rs" harness = false [[bench]] name = "tests" path = "benches/tests.rs" [dependencies.dirs] version = "5.0.1" [dependencies.ini_core] version = "0.2.0" [dependencies.once_cell] version = "1.19.0" [dependencies.thiserror] version = "1.0.56" [dependencies.tracing] version = "0.1.41" [dependencies.xdg] version = "2.5.2" [dev-dependencies.criterion] version = "0.5" [dev-dependencies.gtk4] version = "0.9" [dev-dependencies.linicon] version = "2.3.0" [dev-dependencies.speculoos] version = "0.11.0" freedesktop-icons-0.4.0/Cargo.toml.orig0000644000000010710000000000100134150ustar [package] name = "freedesktop-icons" version = "0.4.0" edition = "2021" license = "MIT" description = "A Freedesktop Icons lookup crate" repository = "https://github.com/oknozor/freedestkop-icons" readme = "README.md" keywords = ["icons", "gui", "freedesktop"] [dependencies] dirs = "5.0.1" thiserror = "1.0.56" once_cell = "1.19.0" xdg = "2.5.2" tracing = "0.1.41" ini_core = "0.2.0" [dev-dependencies] speculoos = "0.11.0" linicon = "2.3.0" gtk4 = "0.9" criterion = "0.5" [features] default = [] local_tests = [] [[bench]] name = "simple_lookup" harness = false freedesktop-icons-0.4.0/Cargo.toml.orig000064400000000000000000000010711046102023000161370ustar 00000000000000[package] name = "freedesktop-icons" version = "0.4.0" edition = "2021" license = "MIT" description = "A Freedesktop Icons lookup crate" repository = "https://github.com/oknozor/freedestkop-icons" readme = "README.md" keywords = ["icons", "gui", "freedesktop"] [dependencies] dirs = "5.0.1" thiserror = "1.0.56" once_cell = "1.19.0" xdg = "2.5.2" tracing = "0.1.41" ini_core = "0.2.0" [dev-dependencies] speculoos = "0.11.0" linicon = "2.3.0" gtk4 = "0.9" criterion = "0.5" [features] default = [] local_tests = [] [[bench]] name = "simple_lookup" harness = false freedesktop-icons-0.4.0/LICENSE000064400000000000000000000020571046102023000142620ustar 00000000000000MIT License Copyright (c) 2022 Paul Delafosse 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. freedesktop-icons-0.4.0/README.md000064400000000000000000000023701046102023000145320ustar 00000000000000 # freedesktop-icons ![crates.io-badge](https://img.shields.io/crates/v/freedesktop-icons) ![docrs-badge](https://img.shields.io/docsrs/freedesktop-icons) This crate provides a [freedesktop icon](https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#implementation_notes) lookup implementation. It exposes a single `lookup` function to find icons based on their `name`, `theme`, `size` and `scale`. ## Example **Simple lookup:** The following snippet get an icon from the default 'hicolor' theme with the default scale (`1`) and the default size (`24`). ```rust use freedesktop_icons::lookup; let icon = lookup("firefox").find(); ``` **Complex lookup:** If you have specific requirements for your lookup you can use the provided builder functions: ```rust use freedesktop_icons::lookup; let icon = lookup("firefox") .with_size(48) .with_scale(2) .with_theme("Arc") .find(); ``` **Cache:** If your application is going to repeat the same icon lookups multiple times you can use the internal cache to improve performance. ```rust use freedesktop_icons::lookup; let icon = lookup("firefox") .with_size(48) .with_scale(2) .with_theme("Arc") .with_cache() .find(); ```freedesktop-icons-0.4.0/src/cache.rs000064400000000000000000000034551046102023000154600ustar 00000000000000use once_cell::sync::Lazy; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::sync::Mutex; pub(crate) static CACHE: Lazy = Lazy::new(Cache::default); type IconMap = BTreeMap<(String, u16, u16), CacheEntry>; type ThemeMap = BTreeMap; #[derive(Default)] pub(crate) struct Cache(Mutex); #[derive(Debug, Clone, PartialEq)] pub enum CacheEntry { // We already looked for this and nothing was found, indicates we should not try to perform a lookup. NotFound, // We have this entry. Found(PathBuf), // We don't know this entry yet, indicate we should perform a lookup. Unknown, } impl Cache { pub fn insert>( &self, theme: &str, size: u16, scale: u16, icon_name: &str, icon_path: &Option

, ) { let mut theme_map = self.0.lock().unwrap(); let entry = icon_path .as_ref() .map(|path| CacheEntry::Found(path.as_ref().to_path_buf())) .unwrap_or(CacheEntry::NotFound); match theme_map.get_mut(theme) { Some(icon_map) => { icon_map.insert((icon_name.to_string(), size, scale), entry); } None => { let mut icon_map = BTreeMap::new(); icon_map.insert((icon_name.to_string(), size, scale), entry); theme_map.insert(theme.to_string(), icon_map); } } } pub fn get(&self, theme: &str, size: u16, scale: u16, icon_name: &str) -> CacheEntry { let theme_map = self.0.lock().unwrap(); theme_map .get(theme) .map(|icon_map| icon_map.get(&(icon_name.to_string(), size, scale))) .and_then(|path| path.cloned()) .unwrap_or(CacheEntry::Unknown) } } freedesktop-icons-0.4.0/src/lib.rs000064400000000000000000000340661046102023000151650ustar 00000000000000//! # freedesktop-icons //! //! This crate provides a [freedesktop icon](https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#implementation_notes) lookup implementation. //! //! It exposes a single lookup function to find icons based on their `name`, `theme`, `size` and `scale`. //! //! ## Example //! //! **Simple lookup:** //! //! The following snippet get an icon from the default 'hicolor' theme //! with the default scale (`1`) and the default size (`24`). //! //! ```rust //! # fn main() { //! use freedesktop_icons::lookup; //! //! let icon = lookup("firefox").find(); //! # } //!``` //! //! **Complex lookup:** //! //! If you have specific requirements for your lookup you can use the provided builder functions: //! //! ```rust //! # fn main() { //! use freedesktop_icons::lookup; //! //! let icon = lookup("firefox") //! .with_size(48) //! .with_scale(2) //! .with_theme("Arc") //! .find(); //! # } //!``` //! **Cache:** //! //! If your application is going to repeat the same icon lookups multiple times //! you can use the internal cache to improve performance. //! //! ```rust //! # fn main() { //! use freedesktop_icons::lookup; //! //! let icon = lookup("firefox") //! .with_size(48) //! .with_scale(2) //! .with_theme("Arc") //! .with_cache() //! .find(); //! # } //! ``` use theme::BASE_PATHS; use crate::cache::{CacheEntry, CACHE}; use crate::theme::{try_build_icon_path, THEMES}; use std::io::BufRead; use std::path::PathBuf; mod cache; mod theme; /// Return the list of installed themes on the system /// /// ## Example /// ```rust,no_run /// # fn main() { /// use freedesktop_icons::list_themes; /// /// let themes: Vec = list_themes(); /// /// assert_eq!(themes, vec![ /// "Adwaita", "Arc", "Breeze Light", "HighContrast", "Papirus", "Papirus-Dark", /// "Papirus-Light", "Breeze", "Breeze Dark", "Breeze", "ePapirus", "ePapirus-Dark", "Hicolor" /// ]) /// # } pub fn list_themes() -> Vec { let mut themes = THEMES .values() .flatten() .map(|path| &path.index) .filter_map(|index| { let file = std::fs::File::open(index).ok()?; let mut reader = std::io::BufReader::new(file); let mut line = String::new(); while let Ok(read) = reader.read_line(&mut line) { if read == 0 { break; } if let Some(name) = line.strip_prefix("Name=") { return Some(name.trim().to_owned()); } line.clear(); } None }) .collect::>(); themes.dedup(); themes } /// Return the default GTK theme if set. /// /// ## Example /// ```rust, no_run /// use freedesktop_icons::default_theme_gtk; /// /// let theme = default_theme_gtk(); /// /// assert_eq!(Some("Adwaita"), theme.as_deref()); /// ``` pub fn default_theme_gtk() -> Option { // Calling gsettings is the simplest way to retrieve the default icon theme without adding // GTK as a dependency. There seems to be several ways to set the default GTK theme // including a file in XDG_CONFIG_HOME as well as an env var. Gsettings is the most // straightforward method. let gsettings = std::process::Command::new("gsettings") .args(["get", "org.gnome.desktop.interface", "icon-theme"]) .output() .ok()?; // Only return the theme if it's in the cache. if gsettings.status.success() { let name = String::from_utf8(gsettings.stdout).ok()?; let name = name.trim().trim_matches('\''); THEMES.get(name).and_then(|themes| { themes.first().and_then(|path| { let file = std::fs::File::open(&path.index).ok()?; let mut reader = std::io::BufReader::new(file); let mut line = String::new(); while let Ok(read) = reader.read_line(&mut line) { if read == 0 { break; } if let Some(name) = line.strip_prefix("Name=") { return Some(name.trim().to_owned()); } line.clear(); } None }) }) } else { None } } /// The lookup builder struct, holding all the lookup query parameters. pub struct LookupBuilder<'a> { name: &'a str, cache: bool, force_svg: bool, scale: u16, size: u16, theme: &'a str, } /// Build an icon lookup for the given icon name. /// /// ## Example /// ```rust /// # fn main() { /// use freedesktop_icons::lookup; /// /// let icon = lookup("firefox").find(); /// # } pub fn lookup(name: &str) -> LookupBuilder { LookupBuilder::new(name) } impl<'a> LookupBuilder<'a> { /// Restrict the lookup to the given icon size. /// /// ## Example /// ```rust /// # fn main() { /// use freedesktop_icons::lookup; /// /// let icon = lookup("firefox") /// .with_size(48) /// .find(); /// # } pub fn with_size(mut self, size: u16) -> Self { self.size = size; self } /// Restrict the lookup to the given scale. /// /// ## Example /// ```rust /// # fn main() { /// use freedesktop_icons::lookup; /// /// let icon = lookup("firefox") /// .with_scale(2) /// .find(); /// # } pub fn with_scale(mut self, scale: u16) -> Self { self.scale = scale; self } /// Add the given theme to the current lookup : /// ## Example /// ```rust /// # fn main() { /// use freedesktop_icons::lookup; /// /// let icon = lookup("firefox") /// .with_theme("Papirus") /// .find(); /// # } pub fn with_theme<'b: 'a>(mut self, theme: &'b str) -> Self { self.theme = theme; self } /// Store the result of the lookup in cache, subsequent /// lookup will first try to get the cached icon. /// This can drastically increase lookup performances for application /// that repeat the same lookups, an application launcher for instance. /// /// ## Example /// ```rust /// # fn main() { /// use freedesktop_icons::lookup; /// /// let icon = lookup("firefox") /// .with_scale(2) /// .with_cache() /// .find(); /// # } pub fn with_cache(mut self) -> Self { self.cache = true; self } /// By default [`find`] will prioritize Png over Svg icon. /// Use this if you need to prioritize Svg icons. This could be useful /// if you need a modifiable icon, to match a user theme for instance. /// /// ## Example /// ```rust /// # fn main() { /// use freedesktop_icons::lookup; /// /// let icon = lookup("firefox") /// .force_svg() /// .find(); /// # } pub fn force_svg(mut self) -> Self { self.force_svg = true; self } /// Execute the current lookup /// if no icon is found in the current theme fallback to /// `/usr/share/icons/hicolor` theme and then to `/usr/share/pixmaps`. pub fn find(self) -> Option { // Lookup for an icon in the given theme and fallback to 'hicolor' default theme self.lookup_in_theme() } fn new<'b: 'a>(name: &'b str) -> Self { Self { name, cache: false, force_svg: false, scale: 1, size: 24, theme: "hicolor", } } // Recursively lookup for icon in the given theme and its parents fn lookup_in_theme(&self) -> Option { // If cache is activated, attempt to get the icon there first // If the icon was previously search but not found, we return // `None` early, otherwise, attempt to perform a lookup if self.cache { if let CacheEntry::Found(icon) = self.cache_lookup(self.theme) { return Some(icon); } } // Then lookup in the given theme THEMES .get(self.theme) .or_else(|| THEMES.get("hicolor")) .and_then(|icon_themes| { let icon = icon_themes .iter() .find_map(|theme| { theme.try_get_icon(self.name, self.size, self.scale, self.force_svg) }) .or_else(|| { // Fallback to the parent themes recursively let mut parents = icon_themes .iter() .flat_map(|t| { let file = theme::read_ini_theme(&t.index); t.inherits(file.as_ref()) .into_iter() .map(String::from) .collect::>() }) .collect::>(); parents.dedup(); parents.into_iter().find_map(|parent| { THEMES.get(&parent).and_then(|parent| { parent.iter().find_map(|t| { t.try_get_icon(self.name, self.size, self.scale, self.force_svg) }) }) }) }) .or_else(|| { THEMES.get("hicolor").and_then(|icon_themes| { icon_themes.iter().find_map(|theme| { theme.try_get_icon(self.name, self.size, self.scale, self.force_svg) }) }) }) .or_else(|| { for theme_base_dir in BASE_PATHS.iter() { if let Some(icon) = try_build_icon_path(self.name, theme_base_dir, self.force_svg) { return Some(icon); } } None }) .or_else(|| { try_build_icon_path(self.name, "/usr/share/pixmaps", self.force_svg) }) .or_else(|| { let p = PathBuf::from(&self.name); if let (Some(name), Some(parent)) = (p.file_stem(), p.parent()) { try_build_icon_path(&name.to_string_lossy(), parent, self.force_svg) } else { None } }); if self.cache { self.store(self.theme, icon) } else { icon } }) } #[inline] fn cache_lookup(&self, theme: &str) -> CacheEntry { CACHE.get(theme, self.size, self.scale, self.name) } #[inline] fn store(&self, theme: &str, icon: Option) -> Option { CACHE.insert(theme, self.size, self.scale, self.name, &icon); icon } } // WARNING: these test are highly dependent on your installed icon-themes. // If you want to run them, make sure you have 'Papirus' and 'Arc' icon-themes installed. #[cfg(test)] #[cfg(feature = "local_tests")] mod test { use crate::{lookup, CacheEntry, CACHE}; use speculoos::prelude::*; use std::path::PathBuf; #[test] fn simple_lookup() { let firefox = lookup("firefox").find(); asserting!("Lookup with no parameters should return an existing icon") .that(&firefox) .is_some() .is_equal_to(PathBuf::from( "/usr/share/icons/hicolor/22x22/apps/firefox.png", )); } #[test] fn theme_lookup() { let firefox = lookup("firefox").with_theme("Papirus").find(); asserting!("Lookup with no parameters should return an existing icon") .that(&firefox) .is_some() .is_equal_to(PathBuf::from( "/usr/share/icons/Papirus/24x24/apps/firefox.svg", )); } #[test] fn should_fallback_to_parent_theme() { let icon = lookup("video-single-display-symbolic") .with_theme("Arc") .find(); asserting!("Lookup for an icon in the Arc theme should find the icon in its parent") .that(&icon) .is_some() .is_equal_to(PathBuf::from( "/usr/share/icons/Adwaita/symbolic/devices/video-single-display-symbolic.svg", )); } #[test] fn should_fallback_to_pixmaps_utlimately() { let archlinux_logo = lookup("archlinux-logo") .with_size(16) .with_scale(1) .with_theme("Papirus") .find(); asserting!("When lookup fail in theme, icon should be found in '/usr/share/pixmaps'") .that(&archlinux_logo) .is_some() .is_equal_to(PathBuf::from("/usr/share/pixmaps/archlinux-logo.png")); } #[test] fn compare_to_linincon_with_theme() { let lin_wireshark = linicon::lookup_icon("wireshark") .next() .unwrap() .unwrap() .path; let wireshark = lookup("wireshark") .with_size(16) .with_scale(1) .with_theme("Papirus") .find(); asserting!("Given the same input parameter, lookup should output be the same as linincon") .that(&wireshark) .is_some() .is_equal_to(lin_wireshark); } #[test] fn should_not_attempt_to_lookup_a_not_found_cached_icon() { let not_found = lookup("not-found").with_cache().find(); assert_that!(not_found).is_none(); let expected_cache_result = CACHE.get("hicolor", 24, 1, "not-found"); asserting!("When lookup fails a first time, subsequent attempts should fail from cache") .that(&expected_cache_result) .is_equal_to(CacheEntry::NotFound); } } freedesktop-icons-0.4.0/src/theme/directories.rs000064400000000000000000000046531046102023000200340ustar 00000000000000#[derive(Debug)] pub struct Directory<'a> { pub name: &'a str, pub size: i16, pub scale: i16, pub type_: DirectoryType, pub maxsize: i16, pub minsize: i16, pub threshold: i16, } impl Directory<'_> { pub fn match_size(&self, size: u16, scale: u16) -> bool { let scale = scale as i16; let size = size as i16; if self.scale != scale { false } else { match self.type_ { DirectoryType::Fixed => self.size == size, DirectoryType::Scalable => self.minsize <= size && size <= self.maxsize, DirectoryType::Threshold => { self.size - self.threshold <= size && size <= self.size + self.threshold } } } } pub fn directory_size_distance(&self, size: u16, scale: u16) -> i16 { let scaled_size = self.size * self.scale; let min_scaled_size = self.minsize * self.scale; let max_scaled_size = self.maxsize * self.scale; let scale = scale as i16; let size = size as i16; let scaled_requested_size = size * scale; match self.type_ { DirectoryType::Fixed => scaled_size - scaled_requested_size, DirectoryType::Scalable => { if scaled_requested_size < min_scaled_size { min_scaled_size - scaled_requested_size } else if scaled_requested_size < max_scaled_size { scaled_requested_size - max_scaled_size } else { 0 } } DirectoryType::Threshold => { if scaled_requested_size < (self.size - self.threshold) * scale { min_scaled_size - scaled_requested_size } else if scaled_requested_size > (self.size + self.threshold) * scale { scaled_requested_size - max_scaled_size } else { 0 } } } } } #[derive(Debug)] pub enum DirectoryType { Fixed, Scalable, Threshold, } impl Default for DirectoryType { fn default() -> Self { Self::Threshold } } impl From<&str> for DirectoryType { fn from(value: &str) -> Self { match value { "Fixed" => DirectoryType::Fixed, "Scalable" => DirectoryType::Scalable, _ => DirectoryType::Threshold, } } } freedesktop-icons-0.4.0/src/theme/error.rs000064400000000000000000000003771046102023000166500ustar 00000000000000use std::io; use std::path::PathBuf; use thiserror::Error; #[derive(Error, Debug)] pub(crate) enum ThemeError { #[error("No 'index.theme' file for {0}")] ThemeIndexNotFound(PathBuf), #[error("IoError: {0}")] IoError(#[from] io::Error), } freedesktop-icons-0.4.0/src/theme/mod.rs000064400000000000000000000164401046102023000162740ustar 00000000000000use crate::theme::error::ThemeError; use crate::theme::paths::ThemePath; use once_cell::sync::Lazy; pub(crate) use paths::BASE_PATHS; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; mod directories; pub mod error; mod parse; mod paths; type Result = std::result::Result; pub static THEMES: Lazy>> = Lazy::new(get_all_themes); pub fn read_ini_theme(path: &Path) -> String { std::fs::read_to_string(path).unwrap_or_default() } #[derive(Debug)] pub struct Theme { pub path: ThemePath, pub index: PathBuf, } impl Theme { pub fn try_get_icon( &self, name: &str, size: u16, scale: u16, force_svg: bool, ) -> Option { let file = read_ini_theme(&self.index); self.try_get_icon_exact_size(file.as_str(), name, size, scale, force_svg) .or_else(|| self.try_get_icon_closest_size(file.as_str(), name, size, scale, force_svg)) } fn try_get_icon_exact_size( &self, file: &str, name: &str, size: u16, scale: u16, force_svg: bool, ) -> Option { self.match_size(file, size, scale) .find_map(|path| try_build_icon_path(name, path, force_svg)) } fn match_size<'a>( &'a self, file: &'a str, size: u16, scale: u16, ) -> impl Iterator + 'a { let dirs = self.get_all_directories(file); dirs.filter(move |directory| directory.match_size(size, scale)) .map(|dir| dir.name) .map(|dir| self.path().join(dir)) } fn try_get_icon_closest_size( &self, file: &str, name: &str, size: u16, scale: u16, force_svg: bool, ) -> Option { self.closest_match_size(file, size, scale) .iter() .find_map(|path| try_build_icon_path(name, path, force_svg)) } fn closest_match_size(&self, file: &str, size: u16, scale: u16) -> Vec { let dirs = self.get_all_directories(file); let mut dirs: Vec<_> = dirs .filter_map(|directory| { let distance = directory.directory_size_distance(size, scale); if distance < i16::MAX { Some((directory, distance.abs())) } else { None } }) .collect(); dirs.sort_by(|(_, a), (_, b)| a.cmp(b)); dirs.iter() .map(|(dir, _)| dir) .map(|dir| dir.name) .map(|dir| self.path().join(dir)) .collect() } fn path(&self) -> &PathBuf { &self.path.0 } } pub(super) fn try_build_icon_path>( name: &str, path: P, force_svg: bool, ) -> Option { if force_svg { try_build_svg(name, path.as_ref()) .or_else(|| try_build_png(name, path.as_ref())) .or_else(|| try_build_xmp(name, path.as_ref())) } else { try_build_png(name, path.as_ref()) .or_else(|| try_build_svg(name, path.as_ref())) .or_else(|| try_build_xmp(name, path.as_ref())) } } fn try_build_svg>(name: &str, path: P) -> Option { let path = path.as_ref(); let svg = path.join(format!("{name}.svg")); if svg.exists() { Some(svg) } else { None } } fn try_build_png>(name: &str, path: P) -> Option { let path = path.as_ref(); let png = path.join(format!("{name}.png")); if png.exists() { Some(png) } else { None } } fn try_build_xmp>(name: &str, path: P) -> Option { let path = path.as_ref(); let xmp = path.join(format!("{name}.xmp")); if xmp.exists() { Some(xmp) } else { None } } // Iter through the base paths and get all theme directories pub(super) fn get_all_themes() -> BTreeMap> { let mut icon_themes = BTreeMap::<_, Vec<_>>::new(); let mut found_indices = BTreeMap::new(); let mut to_revisit = Vec::new(); for theme_base_dir in BASE_PATHS.iter() { let dir_iter = match theme_base_dir.read_dir() { Ok(dir) => dir, Err(why) => { tracing::error!(?why, dir = ?theme_base_dir, "unable to read icon theme directory"); continue; } }; for entry in dir_iter.filter_map(std::io::Result::ok) { let name = entry.file_name(); let fallback_index = found_indices.get(&name); if let Some(theme) = Theme::from_path(entry.path(), fallback_index) { if fallback_index.is_none() { found_indices.insert(name.clone(), theme.index.clone()); } let name = name.to_string_lossy().to_string(); icon_themes.entry(name).or_default().push(theme); } else if entry.path().is_dir() { to_revisit.push(entry); } } } for entry in to_revisit { let name = entry.file_name(); let fallback_index = found_indices.get(&name); if let Some(theme) = Theme::from_path(entry.path(), fallback_index) { let name = name.to_string_lossy().to_string(); icon_themes.entry(name).or_default().push(theme); } } icon_themes } impl Theme { pub(crate) fn from_path>(path: P, index: Option<&PathBuf>) -> Option { let path = path.as_ref(); let has_index = path.join("index.theme").exists() || index.is_some(); if !has_index || !path.is_dir() { return None; } let path = ThemePath(path.into()); match (index, path.index()) { (Some(index), _) => Some(Theme { path, index: index.clone(), }), (None, Ok(index)) => Some(Theme { path, index }), _ => None, } } } #[cfg(test)] mod test { use crate::THEMES; use speculoos::prelude::*; use std::path::PathBuf; #[test] fn get_one_icon() { let themes = THEMES.get("Adwaita").unwrap(); println!( "{:?}", themes.iter().find_map(|t| { let file = crate::theme::read_ini_theme(&t.index); t.try_get_icon_exact_size(file.as_str(), "edit-delete-symbolic", 24, 1, false) }) ); } #[test] fn should_get_png_first() { let themes = THEMES.get("hicolor").unwrap(); let icon = themes.iter().find_map(|t| { let file = crate::theme::read_ini_theme(&t.index); t.try_get_icon_exact_size(file.as_str(), "blueman", 24, 1, true) }); assert_that!(icon).is_some().is_equal_to(PathBuf::from( "/usr/share/icons/hicolor/22x22/apps/blueman.png", )); } #[test] fn should_get_svg_first() { let themes = THEMES.get("hicolor").unwrap(); let icon = themes.iter().find_map(|t| { let file = crate::theme::read_ini_theme(&t.index); t.try_get_icon_exact_size(file.as_str(), "blueman", 24, 1, false) }); assert_that!(icon).is_some().is_equal_to(PathBuf::from( "/usr/share/icons/hicolor/22x22/apps/blueman.png", )); } } freedesktop-icons-0.4.0/src/theme/parse.rs000064400000000000000000000114301046102023000166210ustar 00000000000000use crate::theme::directories::{Directory, DirectoryType}; use crate::theme::Theme; fn icon_theme_section(file: &str) -> impl Iterator + '_ { ini_core::Parser::new(file) .skip_while(|item| *item != ini_core::Item::Section("Icon Theme")) .take_while(|item| match item { ini_core::Item::Section(value) => *value == "Icon Theme", _ => true, }) .filter_map(|item| { if let ini_core::Item::Property(key, value) = item { Some((key, value?)) } else { None } }) } #[derive(Debug)] enum DirectorySection<'a> { Property(&'a str, &'a str), EndSection, Section(&'a str), } fn sections(file: &str) -> impl Iterator { ini_core::Parser::new(file).filter_map(move |item| match item { ini_core::Item::Property(key, Some(value)) => Some(DirectorySection::Property(key, value)), ini_core::Item::Section(section) => Some(DirectorySection::Section(section)), ini_core::Item::SectionEnd => Some(DirectorySection::EndSection), _ => None, }) } impl Theme { pub(super) fn get_all_directories<'a>( &'a self, file: &'a str, ) -> impl Iterator> + 'a { let mut iterator = sections(file); std::iter::from_fn(move || { let mut name = ""; let mut size = None; let mut max_size = None; let mut min_size = None; let mut threshold = None; let mut scale = None; // let mut context = None; let mut dtype = DirectoryType::default(); #[allow(clippy::while_let_on_iterator)] while let Some(event) = iterator.next() { match event { DirectorySection::Property(key, value) => { if name.is_empty() || name == "Icon Theme" { continue; } match key { "Size" => size = str::parse(value).ok(), "Scale" => scale = str::parse(value).ok(), // "Context" => context = Some(value), "Type" => dtype = DirectoryType::from(value), "MaxSize" => max_size = str::parse(value).ok(), "MinSize" => min_size = str::parse(value).ok(), "Threshold" => threshold = str::parse(value).ok(), _ => (), } } DirectorySection::Section(new_name) => { name = new_name; size = None; max_size = None; min_size = None; threshold = None; scale = None; dtype = DirectoryType::default(); } DirectorySection::EndSection => { if name.is_empty() || name == "Icon Theme" { continue; } let size = size.take()?; return Some(Directory { name, size, scale: scale.unwrap_or(1), // context, type_: dtype, maxsize: max_size.unwrap_or(size), minsize: min_size.unwrap_or(size), threshold: threshold.unwrap_or(2), }); } } } None }) } pub fn inherits<'a>(&self, file: &'a str) -> Vec<&'a str> { icon_theme_section(file) .find(|&(key, _)| key == "Inherits") .map(|(_, parents)| { parents .split(',') // Filtering out 'hicolor' since we are going to fallback there anyway .filter(|parent| parent != &"hicolor") .collect() }) .unwrap_or_default() } } #[cfg(test)] mod test { use crate::THEMES; use speculoos::prelude::*; #[test] fn should_get_theme_parents() { for theme in THEMES.get("Arc").unwrap() { let file = crate::theme::read_ini_theme(&theme.index); let parents = theme.inherits(&file); assert_that!(parents).does_not_contain("hicolor"); assert_that!(parents).is_equal_to(vec![ "Moka", "Faba", "elementary", "Adwaita", "gnome", ]); } } } freedesktop-icons-0.4.0/src/theme/paths.rs000064400000000000000000000042401046102023000166270ustar 00000000000000use std::path::PathBuf; use dirs::home_dir; use once_cell::sync::Lazy; use xdg::BaseDirectories; use crate::theme; use crate::theme::error::ThemeError; pub(crate) static BASE_PATHS: Lazy> = Lazy::new(icon_theme_base_paths); /// Look in $HOME/.icons (for backwards compatibility), in $XDG_DATA_DIRS/icons, in $XDG_DATA_DIRS/pixmaps and in /usr/share/pixmaps (in that order). /// Paths that are not found are filtered out. fn icon_theme_base_paths() -> Vec { let mut data_dirs: Vec<_> = BaseDirectories::new() .map(|bd| { let mut data_dirs: Vec<_> = bd .get_data_dirs() .into_iter() .flat_map(|p| [p.join("icons"), p.join("pixmaps")]) .collect(); let data_home = bd.get_data_home(); data_dirs.push(data_home.join("icons")); data_dirs.push(data_home.join("pixmaps")); data_dirs }) .unwrap_or_default(); match home_dir().map(|home| home.join(".icons")) { Some(home_icon_dir) => data_dirs.push(home_icon_dir), None => tracing::warn!("No $HOME directory found"), } data_dirs.into_iter().filter(|p| p.exists()).collect() } #[derive(Clone, Debug)] pub struct ThemePath(pub PathBuf); impl ThemePath { pub(super) fn index(&self) -> theme::Result { let index = self.0.join("index.theme"); if !index.exists() { return Err(ThemeError::ThemeIndexNotFound(index)); } Ok(index) } } #[cfg(test)] mod test { use crate::theme::paths::icon_theme_base_paths; use crate::theme::{get_all_themes, Theme}; use speculoos::prelude::*; #[test] fn should_get_all_themes() { let themes = get_all_themes(); assert_that!(themes.get("hicolor")).is_some(); } #[test] fn should_get_theme_paths_ordered() { let base_paths = icon_theme_base_paths(); assert_that!(base_paths).is_not_empty() } #[test] fn should_read_theme_index() { let themes = get_all_themes(); let themes: Vec<&Theme> = themes.values().flatten().collect(); assert_that!(themes).is_not_empty(); } }