aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2025-09-06 13:20:32 -0700
committerFranck Cuny <franck@fcuny.net>2025-09-06 13:22:39 -0700
commit0fb5af8a16909066c11dc282cf43373e721051dc (patch)
treeb68f9009c129f09e1f5b0d3592ef3cd70c3452e0
parentcertcheck to see x509 certification details (diff)
downloadx-0fb5af8a16909066c11dc282cf43373e721051dc.tar.gz
a utility to gathers detailed information about Apple Silicon System
-rw-r--r--Cargo.lock1330
-rw-r--r--Cargo.toml3
-rw-r--r--cmd/apple-silicon-info/README.org15
-rw-r--r--cmd/apple-silicon-info/main.go281
-rw-r--r--cmd/apple-silicon-info/main_test.go197
-rw-r--r--rust-toolchain.toml3
-rw-r--r--src/apple_silicon/Cargo.lock65
-rw-r--r--src/apple_silicon/Cargo.toml18
-rw-r--r--src/apple_silicon/README.md1
-rw-r--r--src/apple_silicon/src/bin/apple_silicon.rs12
-rw-r--r--src/apple_silicon/src/error.rs23
-rw-r--r--src/apple_silicon/src/lib.rs2
-rw-r--r--src/apple_silicon/src/soc.rs302
-rw-r--r--treefmt.nix3
14 files changed, 493 insertions, 1762 deletions
diff --git a/Cargo.lock b/Cargo.lock
deleted file mode 100644
index 5c31fb2..0000000
--- a/Cargo.lock
+++ /dev/null
@@ -1,1330 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "aho-corasick"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "android-tzdata"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
-
-[[package]]
-name = "android_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "anstream"
-version = "0.6.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "is_terminal_polyfill",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-query"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
-dependencies = [
- "windows-sys 0.60.2",
-]
-
-[[package]]
-name = "anstyle-wincon"
-version = "3.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
-dependencies = [
- "anstyle",
- "once_cell_polyfill",
- "windows-sys 0.60.2",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.99"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
-
-[[package]]
-name = "apple_silicon"
-version = "0.1.0"
-dependencies = [
- "thiserror 2.0.16",
-]
-
-[[package]]
-name = "asn1-rs"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048"
-dependencies = [
- "asn1-rs-derive",
- "asn1-rs-impl",
- "displaydoc",
- "nom",
- "num-traits",
- "rusticata-macros",
- "thiserror 1.0.69",
- "time",
-]
-
-[[package]]
-name = "asn1-rs-derive"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
-[[package]]
-name = "asn1-rs-impl"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-
-[[package]]
-name = "aws-lc-rs"
-version = "1.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba"
-dependencies = [
- "aws-lc-sys",
- "zeroize",
-]
-
-[[package]]
-name = "aws-lc-sys"
-version = "0.30.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff"
-dependencies = [
- "bindgen",
- "cc",
- "cmake",
- "dunce",
- "fs_extra",
-]
-
-[[package]]
-name = "bindgen"
-version = "0.69.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
-dependencies = [
- "bitflags",
- "cexpr",
- "clang-sys",
- "itertools",
- "lazy_static",
- "lazycell",
- "log",
- "prettyplease",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash",
- "shlex",
- "syn",
- "which",
-]
-
-[[package]]
-name = "bitflags"
-version = "2.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
-
-[[package]]
-name = "bumpalo"
-version = "3.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
-
-[[package]]
-name = "cc"
-version = "1.2.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc"
-dependencies = [
- "jobserver",
- "libc",
- "shlex",
-]
-
-[[package]]
-name = "cexpr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
-dependencies = [
- "nom",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
-
-[[package]]
-name = "chrono"
-version = "0.4.41"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
-dependencies = [
- "android-tzdata",
- "iana-time-zone",
- "num-traits",
- "windows-link",
-]
-
-[[package]]
-name = "clang-sys"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
-dependencies = [
- "glob",
- "libc",
- "libloading",
-]
-
-[[package]]
-name = "clap"
-version = "4.5.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57"
-dependencies = [
- "clap_builder",
- "clap_derive",
-]
-
-[[package]]
-name = "clap_builder"
-version = "4.5.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41"
-dependencies = [
- "anstream",
- "anstyle",
- "clap_lex",
- "strsim",
-]
-
-[[package]]
-name = "clap_derive"
-version = "4.5.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "clap_lex"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
-
-[[package]]
-name = "cmake"
-version = "0.1.54"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "colorchoice"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
-
-[[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
-
-[[package]]
-name = "data-encoding"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
-
-[[package]]
-name = "der-parser"
-version = "9.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553"
-dependencies = [
- "asn1-rs",
- "displaydoc",
- "nom",
- "num-bigint",
- "num-traits",
- "rusticata-macros",
-]
-
-[[package]]
-name = "deranged"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
-dependencies = [
- "powerfmt",
-]
-
-[[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 = "dunce"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
-
-[[package]]
-name = "either"
-version = "1.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
-
-[[package]]
-name = "errno"
-version = "0.3.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
-dependencies = [
- "libc",
- "windows-sys 0.60.2",
-]
-
-[[package]]
-name = "fs_extra"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
-
-[[package]]
-name = "getrandom"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.11.1+wasi-snapshot-preview1",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
-dependencies = [
- "cfg-if",
- "libc",
- "r-efi",
- "wasi 0.14.3+wasi-0.2.4",
-]
-
-[[package]]
-name = "glob"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
-
-[[package]]
-name = "heck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-
-[[package]]
-name = "home"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "iana-time-zone"
-version = "0.1.63"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
-dependencies = [
- "android_system_properties",
- "core-foundation-sys",
- "iana-time-zone-haiku",
- "js-sys",
- "log",
- "wasm-bindgen",
- "windows-core",
-]
-
-[[package]]
-name = "iana-time-zone-haiku"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "is_terminal_polyfill"
-version = "1.70.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
-
-[[package]]
-name = "itertools"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
-dependencies = [
- "either",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
-
-[[package]]
-name = "jobserver"
-version = "0.1.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
-dependencies = [
- "getrandom 0.3.3",
- "libc",
-]
-
-[[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 = "lazy_static"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-
-[[package]]
-name = "lazycell"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
-
-[[package]]
-name = "libc"
-version = "0.2.175"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
-
-[[package]]
-name = "libloading"
-version = "0.8.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
-dependencies = [
- "cfg-if",
- "windows-targets 0.53.3",
-]
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
-
-[[package]]
-name = "log"
-version = "0.4.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
-
-[[package]]
-name = "memchr"
-version = "2.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
-
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[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-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-conv"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
-
-[[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-traits"
-version = "0.2.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "oid-registry"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9"
-dependencies = [
- "asn1-rs",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.21.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
-
-[[package]]
-name = "once_cell_polyfill"
-version = "1.70.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
-
-[[package]]
-name = "openssl-probe"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
-
-[[package]]
-name = "powerfmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-
-[[package]]
-name = "prettyplease"
-version = "0.2.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
-dependencies = [
- "proc-macro2",
- "syn",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.101"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "r-efi"
-version = "5.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
-
-[[package]]
-name = "regex"
-version = "1.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
-
-[[package]]
-name = "ring"
-version = "0.17.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
-dependencies = [
- "cc",
- "cfg-if",
- "getrandom 0.2.16",
- "libc",
- "untrusted",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
-[[package]]
-name = "rusticata-macros"
-version = "4.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
-dependencies = [
- "nom",
-]
-
-[[package]]
-name = "rustix"
-version = "0.38.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
-dependencies = [
- "bitflags",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "rustls"
-version = "0.23.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc"
-dependencies = [
- "aws-lc-rs",
- "log",
- "once_cell",
- "ring",
- "rustls-pki-types",
- "rustls-webpki",
- "subtle",
- "zeroize",
-]
-
-[[package]]
-name = "rustls-native-certs"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
-dependencies = [
- "openssl-probe",
- "rustls-pemfile",
- "rustls-pki-types",
- "schannel",
- "security-framework",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
-dependencies = [
- "rustls-pki-types",
-]
-
-[[package]]
-name = "rustls-pki-types"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
-dependencies = [
- "zeroize",
-]
-
-[[package]]
-name = "rustls-webpki"
-version = "0.103.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
-dependencies = [
- "aws-lc-rs",
- "ring",
- "rustls-pki-types",
- "untrusted",
-]
-
-[[package]]
-name = "rustversion"
-version = "1.0.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
-
-[[package]]
-name = "schannel"
-version = "0.1.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "security-framework"
-version = "2.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
-dependencies = [
- "bitflags",
- "core-foundation",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.219"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.219"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "shlex"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-
-[[package]]
-name = "strsim"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
-
-[[package]]
-name = "subtle"
-version = "2.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
-
-[[package]]
-name = "syn"
-version = "2.0.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
-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 = "thiserror"
-version = "1.0.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
-dependencies = [
- "thiserror-impl 1.0.69",
-]
-
-[[package]]
-name = "thiserror"
-version = "2.0.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
-dependencies = [
- "thiserror-impl 2.0.16",
-]
-
-[[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 = "thiserror-impl"
-version = "2.0.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "time"
-version = "0.3.41"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
-dependencies = [
- "deranged",
- "itoa",
- "num-conv",
- "powerfmt",
- "serde",
- "time-core",
- "time-macros",
-]
-
-[[package]]
-name = "time-core"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
-
-[[package]]
-name = "time-macros"
-version = "0.2.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
-dependencies = [
- "num-conv",
- "time-core",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
-
-[[package]]
-name = "untrusted"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
-
-[[package]]
-name = "wasi"
-version = "0.11.1+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
-
-[[package]]
-name = "wasi"
-version = "0.14.3+wasi-0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95"
-dependencies = [
- "wit-bindgen",
-]
-
-[[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 = "webpki-roots"
-version = "0.26.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
-dependencies = [
- "webpki-roots 1.0.2",
-]
-
-[[package]]
-name = "webpki-roots"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
-dependencies = [
- "rustls-pki-types",
-]
-
-[[package]]
-name = "which"
-version = "4.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
-dependencies = [
- "either",
- "home",
- "once_cell",
- "rustix",
-]
-
-[[package]]
-name = "windows-core"
-version = "0.61.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
-dependencies = [
- "windows-implement",
- "windows-interface",
- "windows-link",
- "windows-result",
- "windows-strings",
-]
-
-[[package]]
-name = "windows-implement"
-version = "0.60.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "windows-interface"
-version = "0.59.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "windows-link"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
-
-[[package]]
-name = "windows-result"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
-dependencies = [
- "windows-link",
-]
-
-[[package]]
-name = "windows-strings"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
-dependencies = [
- "windows-link",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[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-sys"
-version = "0.60.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
-dependencies = [
- "windows-targets 0.53.3",
-]
-
-[[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 0.52.6",
- "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-targets"
-version = "0.53.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
-dependencies = [
- "windows-link",
- "windows_aarch64_gnullvm 0.53.0",
- "windows_aarch64_msvc 0.53.0",
- "windows_i686_gnu 0.53.0",
- "windows_i686_gnullvm 0.53.0",
- "windows_i686_msvc 0.53.0",
- "windows_x86_64_gnu 0.53.0",
- "windows_x86_64_gnullvm 0.53.0",
- "windows_x86_64_msvc 0.53.0",
-]
-
-[[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_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
-
-[[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_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
-
-[[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_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
-
-[[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_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
-
-[[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_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
-
-[[package]]
-name = "wit-bindgen"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814"
-
-[[package]]
-name = "x509-info"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "chrono",
- "clap",
- "rustls",
- "rustls-native-certs",
- "webpki-roots 0.26.11",
- "x509-parser",
-]
-
-[[package]]
-name = "x509-parser"
-version = "0.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69"
-dependencies = [
- "asn1-rs",
- "data-encoding",
- "der-parser",
- "lazy_static",
- "nom",
- "oid-registry",
- "rusticata-macros",
- "thiserror 1.0.69",
- "time",
-]
-
-[[package]]
-name = "zeroize"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
diff --git a/Cargo.toml b/Cargo.toml
deleted file mode 100644
index f0b7ea9..0000000
--- a/Cargo.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-[workspace]
-members = ["src/apple_silicon/"]
-resolver = "3"
diff --git a/cmd/apple-silicon-info/README.org b/cmd/apple-silicon-info/README.org
new file mode 100644
index 0000000..682a11c
--- /dev/null
+++ b/cmd/apple-silicon-info/README.org
@@ -0,0 +1,15 @@
+* socinfo
+
+A lightweight macOS utility that gathers detailed information about Apple Silicon System-on-Chip (SoC) specifications.
+
+** What it does
+
+=socinfo= queries your Mac's hardware through system utilities to retrieve:
+
+- CPU brand name and core configuration
+- GPU core count
+- Performance and efficiency core breakdown
+- Thermal Design Power (TDP) specifications
+- Memory bandwidth specifications
+
+The tool automatically detects your specific Apple Silicon variant (M1, M1 Pro/Max/Ultra, M2, M2 Pro/Max/Ultra, M3, M3 Pro/Max) and provides the corresponding technical specifications.
diff --git a/cmd/apple-silicon-info/main.go b/cmd/apple-silicon-info/main.go
new file mode 100644
index 0000000..f733d7e
--- /dev/null
+++ b/cmd/apple-silicon-info/main.go
@@ -0,0 +1,281 @@
+package main
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "os/exec"
+ "strconv"
+ "strings"
+)
+
+// Custom error types
+var (
+ ErrParse = errors.New("socinfo parsing error")
+ ErrCommand = errors.New("command execution error")
+ ErrConvert = errors.New("conversion error")
+)
+
+type (
+ Watts = uint32
+ Bandwidth = uint32
+ CoreCount = uint16
+)
+
+// SocInfo represents information about the Silicon chip
+type SocInfo struct {
+ CPUBrandName string `json:"cpu_brand_name"`
+ NumCPUCores CoreCount `json:"num_cpu_cores"`
+ NumGPUCores CoreCount `json:"num_gpu_cores"`
+ CPUMaxPower *Watts `json:"cpu_max_power,omitempty"`
+ GPUMaxPower *Watts `json:"gpu_max_power,omitempty"`
+ CPUMaxBW *Bandwidth `json:"cpu_max_bw,omitempty"`
+ GPUMaxBW *Bandwidth `json:"gpu_max_bw,omitempty"`
+ ECoreCount CoreCount `json:"e_core_count"`
+ PCoreCount CoreCount `json:"p_core_count"`
+}
+
+// AppleChip represents different Apple Silicon variants
+type AppleChip int
+
+const (
+ M1 AppleChip = iota
+ M1Pro
+ M1Max
+ M1Ultra
+ M2
+ M2Pro
+ M2Max
+ M2Ultra
+ M3
+ M3Pro
+ M3Max
+ Unknown
+)
+
+// ChipSpecs holds the specifications for each chip variant
+type ChipSpecs struct {
+ CPUTDP Watts
+ GPUTDP Watts
+ CPUBW Bandwidth
+ GPUBW Bandwidth
+}
+
+// fromBrandString determines the Apple chip type from brand string
+func fromBrandString(brand string) AppleChip {
+ switch {
+ case strings.Contains(brand, "M1 Pro"):
+ return M1Pro
+ case strings.Contains(brand, "M1 Max"):
+ return M1Max
+ case strings.Contains(brand, "M1 Ultra"):
+ return M1Ultra
+ case strings.Contains(brand, "M1"):
+ return M1
+ case strings.Contains(brand, "M2 Pro"):
+ return M2Pro
+ case strings.Contains(brand, "M2 Max"):
+ return M2Max
+ case strings.Contains(brand, "M2 Ultra"):
+ return M2Ultra
+ case strings.Contains(brand, "M2"):
+ return M2
+ case strings.Contains(brand, "M3 Pro"):
+ return M3Pro
+ case strings.Contains(brand, "M3 Max"):
+ return M3Max
+ case strings.Contains(brand, "M3"):
+ return M3
+ default:
+ return Unknown
+ }
+}
+
+// getSpecs returns the specifications for the chip
+func (chip AppleChip) getSpecs() ChipSpecs {
+ switch chip {
+ case M1:
+ return ChipSpecs{CPUTDP: 20, GPUTDP: 20, CPUBW: 70, GPUBW: 70}
+ case M1Pro:
+ return ChipSpecs{CPUTDP: 30, GPUTDP: 30, CPUBW: 200, GPUBW: 200}
+ case M1Max:
+ return ChipSpecs{CPUTDP: 30, GPUTDP: 60, CPUBW: 250, GPUBW: 400}
+ case M1Ultra:
+ return ChipSpecs{CPUTDP: 60, GPUTDP: 120, CPUBW: 500, GPUBW: 800}
+ case M2:
+ return ChipSpecs{CPUTDP: 25, GPUTDP: 15, CPUBW: 100, GPUBW: 100}
+ case M2Pro:
+ return ChipSpecs{CPUTDP: 30, GPUTDP: 35, CPUBW: 0, GPUBW: 0}
+ case M2Max:
+ return ChipSpecs{CPUTDP: 30, GPUTDP: 40, CPUBW: 0, GPUBW: 0}
+ default:
+ return ChipSpecs{CPUTDP: 0, GPUTDP: 0, CPUBW: 0, GPUBW: 0}
+ }
+}
+
+// SystemCommand interface for testable command execution
+type SystemCommand interface {
+ Execute(binary string, args ...string) ([]byte, error)
+}
+
+// RealCommand implements SystemCommand for actual system calls
+type RealCommand struct{}
+
+func (r *RealCommand) Execute(binary string, args ...string) ([]byte, error) {
+ cmd := exec.Command(binary, args...)
+ output, err := cmd.Output()
+ if err != nil {
+ return nil, fmt.Errorf("%w: %v", ErrCommand, err)
+ }
+ return output, nil
+}
+
+const sysctlPath = "/usr/sbin/sysctl"
+
+// getCPUInfo retrieves CPU information using sysctl
+func getCPUInfo(cmd SystemCommand) (string, CoreCount, CoreCount, CoreCount, error) {
+ args := []string{
+ "-n", // don't display the variable name
+ "machdep.cpu.brand_string",
+ "machdep.cpu.core_count",
+ "hw.perflevel0.logicalcpu",
+ "hw.perflevel1.logicalcpu",
+ }
+
+ output, err := cmd.Execute(sysctlPath, args...)
+ if err != nil {
+ return "", 0, 0, 0, err
+ }
+
+ lines := strings.Split(strings.TrimSpace(string(output)), "\n")
+ if len(lines) < 4 {
+ return "", 0, 0, 0, fmt.Errorf("%w: insufficient output lines", ErrParse)
+ }
+
+ cpuBrandName := lines[0]
+
+ numCPUCores, err := strconv.ParseUint(lines[1], 10, 16)
+ if err != nil {
+ return "", 0, 0, 0, fmt.Errorf("%w: parsing cpu cores: %v", ErrConvert, err)
+ }
+
+ numPerformanceCores, err := strconv.ParseUint(lines[2], 10, 16)
+ if err != nil {
+ return "", 0, 0, 0, fmt.Errorf("%w: parsing performance cores: %v", ErrConvert, err)
+ }
+
+ numEfficiencyCores, err := strconv.ParseUint(lines[3], 10, 16)
+ if err != nil {
+ return "", 0, 0, 0, fmt.Errorf("%w: parsing efficiency cores: %v", ErrConvert, err)
+ }
+
+ return cpuBrandName, CoreCount(
+ numCPUCores,
+ ), CoreCount(
+ numPerformanceCores,
+ ), CoreCount(
+ numEfficiencyCores,
+ ), nil
+}
+
+// getGPUInfo retrieves GPU information using system_profiler
+func getGPUInfo(cmd SystemCommand) (CoreCount, error) {
+ args := []string{"-detailLevel", "basic", "SPDisplaysDataType"}
+
+ output, err := cmd.Execute("/usr/sbin/system_profiler", args...)
+ if err != nil {
+ return 0, err
+ }
+
+ scanner := bufio.NewScanner(strings.NewReader(string(output)))
+ for scanner.Scan() {
+ line := scanner.Text()
+ trimmed := strings.TrimSpace(line)
+ if strings.HasPrefix(trimmed, "Total Number of Cores") {
+ parts := strings.Split(trimmed, ": ")
+ if len(parts) == 2 {
+ cores, err := strconv.ParseUint(strings.TrimSpace(parts[1]), 10, 16)
+ if err != nil {
+ return 0, fmt.Errorf("%w: parsing gpu cores: %v", ErrConvert, err)
+ }
+ return CoreCount(cores), nil
+ }
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ return 0, fmt.Errorf("%w: scanning output: %v", ErrParse, err)
+ }
+
+ return 0, fmt.Errorf("%w: GPU core count not found", ErrParse)
+}
+
+// NewSocInfo creates a new SocInfo instance by gathering system information
+func NewSocInfo() (*SocInfo, error) {
+ cmd := &RealCommand{}
+ return NewSocInfoWithCommand(cmd)
+}
+
+// NewSocInfoWithCommand creates a new SocInfo instance with a custom command executor (for testing)
+func NewSocInfoWithCommand(cmd SystemCommand) (*SocInfo, error) {
+ cpuBrandName, numCPUCores, eCoreCount, pCoreCount, err := getCPUInfo(cmd)
+ if err != nil {
+ return nil, err
+ }
+
+ numGPUCores, err := getGPUInfo(cmd)
+ if err != nil {
+ return nil, err
+ }
+
+ chip := fromBrandString(cpuBrandName)
+ specs := chip.getSpecs()
+
+ var cpuMaxPower, gpuMaxPower *Watts
+ var cpuMaxBW, gpuMaxBW *Bandwidth
+
+ if specs.CPUTDP > 0 {
+ cpuMaxPower = &specs.CPUTDP
+ }
+ if specs.GPUTDP > 0 {
+ gpuMaxPower = &specs.GPUTDP
+ }
+ if specs.CPUBW > 0 {
+ cpuMaxBW = &specs.CPUBW
+ }
+ if specs.GPUBW > 0 {
+ gpuMaxBW = &specs.GPUBW
+ }
+
+ return &SocInfo{
+ CPUBrandName: cpuBrandName,
+ NumCPUCores: numCPUCores,
+ NumGPUCores: numGPUCores,
+ CPUMaxPower: cpuMaxPower,
+ GPUMaxPower: gpuMaxPower,
+ CPUMaxBW: cpuMaxBW,
+ GPUMaxBW: gpuMaxBW,
+ ECoreCount: eCoreCount,
+ PCoreCount: pCoreCount,
+ }, nil
+}
+
+func main() {
+ socInfo, err := NewSocInfo()
+ if err != nil {
+ fmt.Printf("Error getting SoC info: %v\n", err)
+ return
+ }
+
+ var cpuPower Watts
+ if socInfo.CPUMaxPower != nil {
+ cpuPower = *socInfo.CPUMaxPower
+ }
+
+ fmt.Printf("Our CPU is an %s, and we have %d CPU cores, and %d GPU cores. The TDP is %d.\n",
+ socInfo.CPUBrandName,
+ socInfo.NumCPUCores,
+ socInfo.NumGPUCores,
+ cpuPower,
+ )
+}
diff --git a/cmd/apple-silicon-info/main_test.go b/cmd/apple-silicon-info/main_test.go
new file mode 100644
index 0000000..a9b7caf
--- /dev/null
+++ b/cmd/apple-silicon-info/main_test.go
@@ -0,0 +1,197 @@
+package main
+
+import (
+ "errors"
+ "testing"
+)
+
+type MockCommand struct {
+ output string
+ err error
+}
+
+func NewMockCommand(output string) *MockCommand {
+ return &MockCommand{output: output}
+}
+
+func NewMockCommandWithError(err error) *MockCommand {
+ return &MockCommand{err: err}
+}
+
+func (m *MockCommand) Execute(binary string, args ...string) ([]byte, error) {
+ if m.err != nil {
+ return nil, m.err
+ }
+ return []byte(m.output), nil
+}
+
+func TestGetGPUInfo(t *testing.T) {
+ mockOutput := `Graphics/Displays:
+ Apple M2:
+ Total Number of Cores: 10`
+
+ cmd := NewMockCommand(mockOutput)
+
+ result, err := getGPUInfo(cmd)
+ if err != nil {
+ t.Fatalf("Expected no error, got: %v", err)
+ }
+
+ expected := CoreCount(10)
+ if result != expected {
+ t.Errorf("Expected %d GPU cores, got %d", expected, result)
+ }
+}
+
+func TestGetGPUInfoNotFound(t *testing.T) {
+ mockOutput := `Graphics/Displays:
+ Apple M2:
+ Some other field: 10`
+
+ cmd := NewMockCommand(mockOutput)
+
+ _, err := getGPUInfo(cmd)
+ if err == nil {
+ t.Fatal("Expected error when GPU cores not found, got nil")
+ }
+}
+
+func TestGetCPUInfoSuccess(t *testing.T) {
+ mockOutput := "Apple M2\n8\n4\n4\n"
+ cmd := NewMockCommand(mockOutput)
+
+ brand, cores, pCores, eCores, err := getCPUInfo(cmd)
+ if err != nil {
+ t.Fatalf("Expected no error, got: %v", err)
+ }
+
+ if brand != "Apple M2" {
+ t.Errorf("Expected brand 'Apple M2', got '%s'", brand)
+ }
+ if cores != 8 {
+ t.Errorf("Expected 8 cores, got %d", cores)
+ }
+ if pCores != 4 {
+ t.Errorf("Expected 4 performance cores, got %d", pCores)
+ }
+ if eCores != 4 {
+ t.Errorf("Expected 4 efficiency cores, got %d", eCores)
+ }
+}
+
+func TestGetCPUInfoMissingCoreCount(t *testing.T) {
+ mockOutput := "Apple M2\n"
+ cmd := NewMockCommand(mockOutput)
+
+ _, _, _, _, err := getCPUInfo(cmd)
+ if err == nil {
+ t.Fatal("Expected error with insufficient output, got nil")
+ }
+}
+
+func TestGetCPUInfoInvalidCoreCount(t *testing.T) {
+ mockOutput := "Apple M2\ninvalid\n4\n4\n"
+ cmd := NewMockCommand(mockOutput)
+
+ _, _, _, _, err := getCPUInfo(cmd)
+ if err == nil {
+ t.Fatal("Expected error with invalid core count, got nil")
+ }
+}
+
+func TestFromBrandString(t *testing.T) {
+ tests := []struct {
+ brand string
+ expected AppleChip
+ }{
+ {"Apple M1", M1},
+ {"Apple M1 Pro", M1Pro},
+ {"Apple M1 Max", M1Max},
+ {"Apple M1 Ultra", M1Ultra},
+ {"Apple M2", M2},
+ {"Apple M2 Pro", M2Pro},
+ {"Apple M2 Max", M2Max},
+ {"Apple M2 Ultra", M2Ultra},
+ {"Apple M3", M3},
+ {"Apple M3 Pro", M3Pro},
+ {"Apple M3 Max", M3Max},
+ {"Intel Core i7", Unknown},
+ }
+
+ for _, test := range tests {
+ result := fromBrandString(test.brand)
+ if result != test.expected {
+ t.Errorf("For brand '%s', expected %v, got %v", test.brand, test.expected, result)
+ }
+ }
+}
+
+func TestChipGetSpecs(t *testing.T) {
+ tests := []struct {
+ chip AppleChip
+ expected ChipSpecs
+ }{
+ {M1, ChipSpecs{CPUTDP: 20, GPUTDP: 20, CPUBW: 70, GPUBW: 70}},
+ {M1Pro, ChipSpecs{CPUTDP: 30, GPUTDP: 30, CPUBW: 200, GPUBW: 200}},
+ {M2, ChipSpecs{CPUTDP: 25, GPUTDP: 15, CPUBW: 100, GPUBW: 100}},
+ {Unknown, ChipSpecs{CPUTDP: 0, GPUTDP: 0, CPUBW: 0, GPUBW: 0}},
+ }
+
+ for _, test := range tests {
+ result := test.chip.getSpecs()
+ if result != test.expected {
+ t.Errorf("For chip %v, expected %+v, got %+v", test.chip, test.expected, result)
+ }
+ }
+}
+
+func TestNewSocInfoWithCommand(t *testing.T) {
+ sysctlOutput := "Apple M2\n8\n4\n4\n"
+
+ profilerOutput := `Graphics/Displays:
+ Apple M2:
+ Total Number of Cores: 10`
+
+ cmd := &MockCommandMultiple{
+ outputs: map[string]string{
+ "/usr/sbin/sysctl": sysctlOutput,
+ "/usr/sbin/system_profiler": profilerOutput,
+ },
+ }
+
+ socInfo, err := NewSocInfoWithCommand(cmd)
+ if err != nil {
+ t.Fatalf("Expected no error, got: %v", err)
+ }
+
+ if socInfo.CPUBrandName != "Apple M2" {
+ t.Errorf("Expected CPU brand 'Apple M2', got '%s'", socInfo.CPUBrandName)
+ }
+ if socInfo.NumCPUCores != 8 {
+ t.Errorf("Expected 8 CPU cores, got %d", socInfo.NumCPUCores)
+ }
+ if socInfo.NumGPUCores != 10 {
+ t.Errorf("Expected 10 GPU cores, got %d", socInfo.NumGPUCores)
+ }
+ if socInfo.CPUMaxPower == nil || *socInfo.CPUMaxPower != 25 {
+ t.Errorf("Expected CPU max power 25W, got %v", socInfo.CPUMaxPower)
+ }
+}
+
+type MockCommandMultiple struct {
+ outputs map[string]string
+ err error
+}
+
+func (m *MockCommandMultiple) Execute(binary string, args ...string) ([]byte, error) {
+ if m.err != nil {
+ return nil, m.err
+ }
+
+ output, exists := m.outputs[binary]
+ if !exists {
+ return nil, errors.New("binary not found in mock")
+ }
+
+ return []byte(output), nil
+}
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
deleted file mode 100644
index a978b3e..0000000
--- a/rust-toolchain.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-[toolchain]
-channel = "1.89"
-components = ["rustfmt", "clippy", "rust-analyzer"]
diff --git a/src/apple_silicon/Cargo.lock b/src/apple_silicon/Cargo.lock
deleted file mode 100644
index 1ee0f1d..0000000
--- a/src/apple_silicon/Cargo.lock
+++ /dev/null
@@ -1,65 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "apple_silicon"
-version = "0.1.0"
-dependencies = [
- "thiserror",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.93"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "thiserror"
-version = "2.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "2.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/src/apple_silicon/Cargo.toml b/src/apple_silicon/Cargo.toml
deleted file mode 100644
index 65dcf5e..0000000
--- a/src/apple_silicon/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "apple_silicon"
-version = "0.1.0"
-edition = "2021"
-description = "A common line tool for Apple Silicon"
-
-license = "MIT"
-authors = ["Franck Cuny <franck@fcuny.net>"]
-repository = "https://github.com/fcuny/apple_silicon"
-homepage = "https://github.com/fcuny/apple_silicon"
-categories = ["command-line-utilities"]
-
-[[bin]]
-name = "apple_silicon"
-path = "src/bin/apple_silicon.rs"
-
-[dependencies]
-thiserror = "2.0.11"
diff --git a/src/apple_silicon/README.md b/src/apple_silicon/README.md
deleted file mode 100644
index 7d83327..0000000
--- a/src/apple_silicon/README.md
+++ /dev/null
@@ -1 +0,0 @@
-A command line utility to report information about Apple Silicon (inspired by [`asitop`](https://github.com/tlkh/asitop/tree/74ebe2cbc23d5b1eec874aebb1b9bacfe0e670cd)).
diff --git a/src/apple_silicon/src/bin/apple_silicon.rs b/src/apple_silicon/src/bin/apple_silicon.rs
deleted file mode 100644
index 0f71eeb..0000000
--- a/src/apple_silicon/src/bin/apple_silicon.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-use apple_silicon::soc::SocInfo;
-
-fn main() {
- let cpu_info = SocInfo::new().unwrap();
- println!(
- "our CPU is an {}, and we have {} CPU cores, and {} GPU cores. The TDP is {}.",
- cpu_info.cpu_brand_name,
- cpu_info.num_cpu_cores,
- cpu_info.num_gpu_cores,
- cpu_info.cpu_max_power.unwrap(),
- );
-}
diff --git a/src/apple_silicon/src/error.rs b/src/apple_silicon/src/error.rs
deleted file mode 100644
index a70b9b5..0000000
--- a/src/apple_silicon/src/error.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-#[derive(thiserror::Error, Debug)]
-pub enum Error {
- #[error("socinfo parsing error: `{0}`")]
- Parse(String),
-
- #[error("I/O error: `{source}`")]
- Io {
- #[from]
- source: std::io::Error,
- },
-
- #[error("utf8 conversion error: `{source}`")]
- Utf8Conversion {
- #[from]
- source: std::string::FromUtf8Error,
- },
-
- #[error("integer parsing error: `{source}`")]
- ParseInt {
- #[from]
- source: std::num::ParseIntError,
- },
-}
diff --git a/src/apple_silicon/src/lib.rs b/src/apple_silicon/src/lib.rs
deleted file mode 100644
index 74bd62c..0000000
--- a/src/apple_silicon/src/lib.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-pub mod error;
-pub mod soc;
diff --git a/src/apple_silicon/src/soc.rs b/src/apple_silicon/src/soc.rs
deleted file mode 100644
index 0e2bf5c..0000000
--- a/src/apple_silicon/src/soc.rs
+++ /dev/null
@@ -1,302 +0,0 @@
-use crate::error::Error;
-
-use std::process::{Command, Output};
-
-pub type Result<T> = std::result::Result<T, Error>;
-pub type Watts = u32;
-pub type Bandwidth = u32;
-pub type CoreCount = u16;
-
-/// Information about the Silicon chip
-pub struct SocInfo {
- /// The CPU brand name string
- pub cpu_brand_name: String,
- /// Number of CPU cores
- pub num_cpu_cores: CoreCount,
- /// Number of GPU cores
- pub num_gpu_cores: CoreCount,
- /// Maximum CPU power in watts (if available)
- pub cpu_max_power: Option<Watts>,
- /// Maximum GPU power in watts (if available)
- pub gpu_max_power: Option<Watts>,
- /// Maximum CPU bandwidth in GB/s (if available)
- pub cpu_max_bw: Option<Bandwidth>,
- /// Maximum GPU bandwidth in GB/s (if available)
- pub gpu_max_bw: Option<Bandwidth>,
- /// Number of efficiency cores
- pub e_core_count: CoreCount,
- /// Number of performance cores
- pub p_core_count: CoreCount,
-}
-
-#[derive(Debug, PartialEq)]
-enum AppleChip {
- M1,
- M1Pro,
- M1Max,
- M1Ultra,
- M2,
- M2Pro,
- M2Max,
- M2Ultra,
- M3,
- M3Pro,
- M3Max,
- Unknown,
-}
-
-struct ChipSpecs {
- cpu_tdp: Watts,
- gpu_tdp: Watts,
- cpu_bw: Bandwidth,
- gpu_bw: Bandwidth,
-}
-
-impl AppleChip {
- fn from_brand_string(brand: &str) -> Self {
- match brand {
- s if s.contains("M1 Pro") => AppleChip::M1Pro,
- s if s.contains("M1 Max") => AppleChip::M1Max,
- s if s.contains("M1 Ultra") => AppleChip::M1Ultra,
- s if s.contains("M1") => AppleChip::M1,
- s if s.contains("M2 Pro") => AppleChip::M2Pro,
- s if s.contains("M2 Max") => AppleChip::M2Max,
- s if s.contains("M2 Ultra") => AppleChip::M2Ultra,
- s if s.contains("M2") => AppleChip::M2,
- s if s.contains("M3 Pro") => AppleChip::M3Pro,
- s if s.contains("M3 Max") => AppleChip::M3Max,
- s if s.contains("M3") => AppleChip::M3,
- _ => AppleChip::Unknown,
- }
- }
-
- fn get_specs(&self) -> ChipSpecs {
- match self {
- AppleChip::M1 => ChipSpecs {
- cpu_tdp: 20,
- gpu_tdp: 20,
- cpu_bw: 70,
- gpu_bw: 70,
- },
- AppleChip::M1Pro => ChipSpecs {
- cpu_tdp: 30,
- gpu_tdp: 30,
- cpu_bw: 200,
- gpu_bw: 200,
- },
- AppleChip::M1Max => ChipSpecs {
- cpu_tdp: 30,
- gpu_tdp: 60,
- cpu_bw: 250,
- gpu_bw: 400,
- },
- AppleChip::M1Ultra => ChipSpecs {
- cpu_tdp: 60,
- gpu_tdp: 120,
- cpu_bw: 500,
- gpu_bw: 800,
- },
- AppleChip::M2 => ChipSpecs {
- cpu_tdp: 25,
- gpu_tdp: 15,
- cpu_bw: 100,
- gpu_bw: 100,
- },
- AppleChip::M2Pro => ChipSpecs {
- cpu_tdp: 30,
- gpu_tdp: 35,
- cpu_bw: 0,
- gpu_bw: 0,
- },
- AppleChip::M2Max => ChipSpecs {
- cpu_tdp: 30,
- gpu_tdp: 40,
- cpu_bw: 0,
- gpu_bw: 0,
- },
- // Add more variants as needed
- _ => ChipSpecs {
- cpu_tdp: 0,
- gpu_tdp: 0,
- cpu_bw: 0,
- gpu_bw: 0,
- },
- }
- }
-}
-
-impl SocInfo {
- pub fn new() -> Result<SocInfo> {
- let (cpu_brand_name, num_cpu_cores, e_core_count, p_core_count) = cpu_info(&RealCommand)?;
- let num_gpu_cores = gpu_info(&RealCommand)?;
-
- let chip = AppleChip::from_brand_string(&cpu_brand_name);
- let specs = chip.get_specs();
-
- Ok(SocInfo {
- cpu_brand_name,
- num_cpu_cores,
- num_gpu_cores,
- cpu_max_power: Some(specs.cpu_tdp),
- gpu_max_power: Some(specs.gpu_tdp),
- cpu_max_bw: Some(specs.cpu_bw),
- gpu_max_bw: Some(specs.gpu_bw),
- e_core_count,
- p_core_count,
- })
- }
-}
-
-// https://github.com/tlkh/asitop/blob/74ebe2cbc23d5b1eec874aebb1b9bacfe0e670cd/asitop/utils.py#L94
-const SYSCTL_PATH: &str = "/usr/sbin/sysctl";
-
-fn cpu_info(cmd: &impl SystemCommand) -> Result<(String, u16, u16, u16)> {
- let binary = SYSCTL_PATH;
- let args = &[
- // don't display the variable name
- "-n",
- "machdep.cpu.brand_string",
- "machdep.cpu.core_count",
- "hw.perflevel0.logicalcpu",
- "hw.perflevel1.logicalcpu",
- ];
-
- let output = cmd.execute(binary, args)?;
- let buffer = String::from_utf8(output.stdout)?;
-
- let mut iter = buffer.split('\n');
- let cpu_brand_name = match iter.next() {
- Some(s) => s.to_string(),
- None => return Err(Error::Parse(buffer.to_string())),
- };
-
- let num_cpu_cores = match iter.next() {
- Some(s) => s.parse::<u16>()?,
- None => return Err(Error::Parse(buffer.to_string())),
- };
-
- let num_performance_cores = match iter.next() {
- Some(s) => s.parse::<u16>()?,
- None => return Err(Error::Parse(buffer.to_string())),
- };
-
- let num_efficiency_cores = match iter.next() {
- Some(s) => s.parse::<u16>()?,
- None => return Err(Error::Parse(buffer.to_string())),
- };
-
- Ok((
- cpu_brand_name,
- num_cpu_cores,
- num_performance_cores,
- num_efficiency_cores,
- ))
-}
-
-// https://github.com/tlkh/asitop/blob/74ebe2cbc23d5b1eec874aebb1b9bacfe0e670cd/asitop/utils.py#L120
-fn gpu_info(cmd: &impl SystemCommand) -> Result<u16> {
- let binary = "/usr/sbin/system_profiler";
- let args = &["-detailLevel", "basic", "SPDisplaysDataType"];
-
- let output = cmd.execute(binary, args)?;
- let buffer = String::from_utf8(output.stdout)?;
-
- let num_gpu_cores_line = buffer
- .lines()
- .find(|&line| line.trim_start().starts_with("Total Number of Cores"));
-
- let num_gpu_cores = match num_gpu_cores_line {
- Some(s) => match s.split(": ").last() {
- Some(s) => s.parse::<u16>()?,
- None => return Err(Error::Parse(buffer.to_string())),
- },
- None => return Err(Error::Parse(buffer.to_string())),
- };
-
- Ok(num_gpu_cores)
-}
-
-/// Trait for system command execution
-pub trait SystemCommand {
- fn execute(&self, binary: &str, args: &[&str]) -> Result<Output>;
-}
-
-/// Real command executor
-pub struct RealCommand;
-
-impl SystemCommand for RealCommand {
- fn execute(&self, binary: &str, args: &[&str]) -> Result<Output> {
- Ok(Command::new(binary).args(args).output()?)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::os::unix::process::ExitStatusExt;
-
- struct MockCommand {
- output: Vec<u8>,
- }
-
- impl MockCommand {
- fn new(output: &str) -> Self {
- Self {
- output: output.as_bytes().to_vec(),
- }
- }
- }
-
- impl SystemCommand for MockCommand {
- fn execute(&self, _binary: &str, _args: &[&str]) -> Result<Output> {
- Ok(Output {
- status: std::process::ExitStatus::from_raw(0),
- stdout: self.output.clone(),
- stderr: Vec::new(),
- })
- }
- }
-
- #[test]
- fn test_gpu_info() {
- let mock_output = r#"Graphics/Displays:
- Apple M2:
- Total Number of Cores: 10"#;
- let cmd = MockCommand::new(mock_output);
-
- let result = gpu_info(&cmd);
- assert_eq!(result.unwrap(), 10);
- }
-
- #[test]
- fn test_cpu_info_success() {
- let mock_output = "Apple M2\n8\n4\n4\n";
- let cmd = MockCommand::new(mock_output);
-
- let result = cpu_info(&cmd);
- assert!(result.is_ok());
- let (brand, cores, p_cores, e_cores) = result.unwrap();
- assert_eq!(brand, "Apple M2");
- assert_eq!(cores, 8);
- assert_eq!(p_cores, 4);
- assert_eq!(e_cores, 4);
- }
-
- #[test]
- fn test_cpu_info_missing_core_count() {
- let mock_output = "Apple M2\n";
- let cmd = MockCommand::new(mock_output);
-
- let result = cpu_info(&cmd);
- assert!(matches!(result, Err(Error::ParseInt { .. })));
- }
-
- #[test]
- fn test_cpu_info_invalid_core_count() {
- let mock_output = "Apple M2\ninvalid\n";
- let cmd = MockCommand::new(mock_output);
-
- let result = cpu_info(&cmd);
- assert!(matches!(result, Err(Error::ParseInt { .. })));
- }
-}
diff --git a/treefmt.nix b/treefmt.nix
index b2e04da..f4b9728 100644
--- a/treefmt.nix
+++ b/treefmt.nix
@@ -24,9 +24,6 @@
programs.actionlint.enable = true;
# Markdown
programs.mdformat.enable = true;
- # Rust
- programs.rustfmt.enable = true;
- programs.taplo.enable = true;
# Nix
programs.nixfmt = {
enable = true;