commit 0722e3dac04cf8b61bc55a4edbc9519b090ad480 Author: sevki Date: Fri Sep 20 14:59:04 2024 +0100 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..99bd36b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,589 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[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 = "cc" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "windows-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "enumflags2" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "insta" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "serde", + "similar", +] + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "okid" +version = "0.1.1" +dependencies = [ + "blake3", + "digest", + "enumflags2", + "hex", + "insta", + "serde", + "serde_bytes", + "sha1", + "sha2", + "sha3", + "ulid", + "uuid", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[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-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +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 = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "similar" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ulid" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f903f293d11f31c0c29e4148f6dc0d033a7f80cebc0282bea147611667d289" +dependencies = [ + "getrandom", + "rand", + "web-time", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[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.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[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", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2c530b9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "okid" +version = "0.1.1" +edition = "2021" +publish = ["oksoftware"] + +[dependencies] +blake3 = { version = "1.5.4", optional = true } +digest = "0.10.7" +enumflags2 = "0.7.10" +hex = { version = "0.4.3", features = ["serde"] } +serde = { version = "1.0.210", features = ["derive"] } +serde_bytes = "0.11.15" +sha1 = { version = "0.10.6", optional = true } +sha2 = { version = "0.10.8", optional = true } +sha3 = { version = "0.10.8", optional = true } +ulid = { version = "1.1.3", optional = true } +uuid = { version = "1.10.0", optional = true } + +[features] +default = ["sha1", "sha2", "sha3", "blake3"] +sha1 = ["dep:sha1"] +sha2 = ["dep:sha2"] +sha3 = ["dep:sha3"] +blake3 = ["dep:blake3"] +uuid = ["dep:uuid"] +ulid = ["dep:ulid"] + +[dev-dependencies] +insta = { version = "1.40.0", features = ["yaml"] } diff --git a/README.md b/README.md new file mode 100644 index 0000000..9243995 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# okid + + + +IDs represented as self identifying strings. diff --git a/okid.png b/okid.png new file mode 100644 index 0000000..514e194 Binary files /dev/null and b/okid.png differ diff --git a/src/blake3.rs b/src/blake3.rs new file mode 100644 index 0000000..ffdc25c --- /dev/null +++ b/src/blake3.rs @@ -0,0 +1,35 @@ +use std::fmt::Display; + +use crate::{BinaryId, BinaryType, Digest}; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub(super) struct Blake3([u8; 32]); + +impl From for BinaryId { + fn from(value: blake3::Hasher) -> Self { + let data = value.finalize(); + let data = data.as_bytes(); + let mut buf = [0; 32]; + if data.len() == 32 { + buf.copy_from_slice(data); + } + + Self { + hash_type: BinaryType::Blake3, + digest: Digest { + blake3: Blake3(buf), + }, + } + } +} + +impl Display for Blake3 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let buf = self.0; + // Write the hex digest + for byte in buf { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..3c0647a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,244 @@ +//! okid is a library for generating cannocial self-describing binary identifiers for +//! git commits, sha1, sha256, sha512 hashes, ULIDs, UUIDs, datatime, extended, +//! and random identifiers, etc. +#![doc(html_logo_url = "https://assets.ok.software/okid.png")] +#![doc(html_favicon_url = "https://assets.ok.software/okid.png")] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![deny(missing_docs)] + +use std::fmt::Display; + +use enumflags2::{bitflags, BitFlags}; + +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "blake3")] +/// blake3 module +pub mod blake3; +#[cfg(feature = "sha1")] +/// sha1 module +pub mod sha1; +#[cfg(feature = "sha2")] +/// sha2 module +pub mod sha2; +#[cfg(feature = "sha3")] +/// sha3 module +pub mod sha3; + +#[repr(u8)] +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)] +pub(crate) enum BinaryType { + #[cfg(feature = "sha1")] + // Next bit means the size of the digest is of sha1 type + Sha1 = 1 << 0, + #[cfg(feature = "sha2")] + // Next bit means the size of the digest is of sha256 type + Sha256 = 1 << 1, + #[cfg(feature = "sha3")] + // Next bit means the size of the digest is of sha512 type + Sha3_512 = 1 << 2, + #[cfg(feature = "blake3")] + // Next bit means the size of the digest is of blake3 type + Blake3 = 1 << 3, +} + +impl From for BinaryType { + fn from(value: char) -> Self { + match value { + #[cfg(feature = "sha1")] + '1' => Self::Sha1, + #[cfg(feature = "sha2")] + '2' => Self::Sha256, + #[cfg(feature = "sha3")] + '3' => Self::Sha3_512, + #[cfg(feature = "blake3")] + 'b' => Self::Blake3, + _ => panic!("Invalid binary type"), + } + } +} + +impl BinaryType { + fn char_code(&self) -> char { + match self { + #[cfg(feature = "sha1")] + Self::Sha1 => '1', + #[cfg(feature = "sha2")] + Self::Sha256 => '2', + #[cfg(feature = "sha3")] + Self::Sha3_512 => '3', + #[cfg(feature = "blake3")] + Self::Blake3 => 'b', + } + } +} + +impl Display for BinaryType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + #[cfg(feature = "sha1")] + Self::Sha1 => write!(f, "sha1"), + #[cfg(feature = "sha2")] + Self::Sha256 => write!(f, "sha256"), + #[cfg(feature = "sha3")] + Self::Sha3_512 => write!(f, "sha3-512"), + #[cfg(feature = "blake3")] + Self::Blake3 => write!(f, "blake3"), + } + } +} + +/// Bird is a binary identifier representable as data +pub struct BinaryId { + hash_type: BinaryType, + /// The digest of the binary identifier + digest: Digest, +} + +#[bitflags] +#[repr(u8)] +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)] +enum CommonSettings { + Git = 0b10000000, + Obfuscated = 0b01000000, +} + +impl From for CommonSettings { + fn from(value: char) -> Self { + match value { + 'g' => Self::Git, + 'o' => Self::Obfuscated, + _ => panic!("Invalid common setting"), + } + } +} + +impl CommonSettings { + fn char_code(&self) -> char { + match self { + Self::Git => 'g', + Self::Obfuscated => 'o', + } + } +} + +impl Display for CommonSettings { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let settings = BitFlags::from_flag(*self); + let buf = "+".to_string(); + let settings = settings.iter().fold(vec![], |acc, x| { + let mut acc = acc; + acc.push(x.char_code()); + acc + }); + + let settings = settings + .iter() + .fold(String::new(), |acc, x| acc + &x.to_string()); + + write!(f, "{}", buf + settings.as_str()) + } +} + +/// Digest of the binary identifier +union Digest { + /// u64 bit fp like hashes, probably not secure + u64: u64, + #[cfg(feature = "sha1")] + /// SHA-1 digest + sha1: crate::sha1::Sha1, + #[cfg(feature = "sha2")] + /// SHA-256 digest + sha256: crate::sha2::Sha256, + #[cfg(feature = "sha3")] + /// SHA-512 digest + sha512: crate::sha3::Sha512, + #[cfg(feature = "blake3")] + blake3: crate::blake3::Blake3, +} + +impl From for Digest { + fn from(value: u64) -> Self { + Self { u64: value } + } +} + +impl Display for BinaryId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Write the binary type code + write!(f, "{}ː", self.hash_type.char_code())?; + + unsafe { + match self.hash_type { + #[cfg(feature = "sha1")] + BinaryType::Sha1 => self.digest.sha1.fmt(f), + #[cfg(feature = "sha2")] + BinaryType::Sha256 => self.digest.sha256.fmt(f), + #[cfg(feature = "sha3")] + BinaryType::Sha3_512 => self.digest.sha512.fmt(f), + #[cfg(feature = "blake3")] + BinaryType::Blake3 => self.digest.blake3.fmt(f), + } + } + } +} + +#[cfg(test)] +mod binary_id_tests { + + #[cfg(feature = "sha1")] + use sha1::Digest as sha1digest; + + use crate::BinaryId; + #[cfg(feature = "sha1")] + #[test] + fn test_display() { + let hasher = sha1::Sha1::new(); + let binary_id = BinaryId::from(hasher); + insta::assert_yaml_snapshot!(binary_id.to_string(), @r###" + 1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709 + "###); + } + #[cfg(feature = "sha1")] + #[test] + fn test_display_hello_world() { + let mut hasher = sha1::Sha1::new(); + hasher.update(b"hello world"); + let binary_id = BinaryId::from(hasher); + insta::assert_yaml_snapshot!(binary_id.to_string(), @r###" + 1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed + "###); + } + #[cfg(feature = "sha2")] + #[test] + fn test_display_hello_world_sha256() { + let mut hasher = sha2::Sha256::new(); + hasher.update(b"hello world"); + let binary_id = BinaryId::from(hasher); + insta::assert_yaml_snapshot!(binary_id.to_string(), @r###" + 2ː00b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 + "###); + } + + #[cfg(feature = "sha3")] + #[test] + fn test_display_hello_world_sha3() { + let mut hasher = sha3::Sha3_512::new(); + hasher.update(b"hello world"); + let binary_id = BinaryId::from(hasher); + insta::assert_yaml_snapshot!(binary_id.to_string(), @r###" + 3ː840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a + "###); + } + + #[cfg(feature = "blake3")] + #[test] + fn test_display_hello_world_blake3() { + let mut hasher = blake3::Hasher::new(); + hasher.update(b"hello world"); + let binary_id = BinaryId::from(hasher); + insta::assert_yaml_snapshot!(binary_id.to_string(), @r###" + bːd74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24 + "###); + } +} diff --git a/src/sha1.rs b/src/sha1.rs new file mode 100644 index 0000000..01caa7a --- /dev/null +++ b/src/sha1.rs @@ -0,0 +1,49 @@ +use std::fmt::Display; + +use digest::core_api::CoreWrapper; +use enumflags2::BitFlags; + +use super::{BinaryId, BinaryType, CommonSettings, Digest}; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub(super) struct Sha1(BitFlags, [u8; 20]); + +#[cfg(feature = "sha1")] +use sha1::Digest as sha1Digest; + +#[cfg(feature = "sha1")] +impl From for BinaryId { + fn from(value: sha1::Sha1) -> Self { + let data = value.finalize(); + let data = data.get(0..20).unwrap(); + let mut buf = [0; 20]; + if data.len() == 20 { + buf.copy_from_slice(data); + } + let empty: BitFlags = BitFlags::empty(); + Self { + hash_type: BinaryType::Sha1, + digest: Digest { + sha1: Sha1(empty, buf), + }, + } + } +} +impl From for BinaryId { + fn from(value: sha1::Sha1Core) -> Self { + CoreWrapper::from_core(value).into() + } +} + +impl Display for Sha1 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let settings = self.0; + let buf = self.1; + write!(f, "{:02x}", settings.bits())?; + // Write the hex digest + for byte in buf { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +} diff --git a/src/sha2.rs b/src/sha2.rs new file mode 100644 index 0000000..e256d16 --- /dev/null +++ b/src/sha2.rs @@ -0,0 +1,41 @@ +use enumflags2::BitFlags; +use sha2::Digest; +use std::fmt::Display; + +use crate::BinaryId; + +use super::CommonSettings; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub(super) struct Sha256(BitFlags, [u8; 32]); + +impl From for BinaryId { + fn from(value: sha2::Sha256) -> Self { + let data = value.finalize(); + let data = data.get(0..32).unwrap(); + let mut buf = [0; 32]; + if data.len() == 32 { + buf.copy_from_slice(data); + } + let empty: BitFlags = BitFlags::empty(); + Self { + hash_type: super::BinaryType::Sha256, + digest: super::Digest { + sha256: Sha256(empty, buf), + }, + } + } +} + +impl Display for Sha256 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let settings = self.0; + let buf = self.1; + write!(f, "{:02x}", settings.bits())?; + // Write the hex digest + for byte in buf { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +} diff --git a/src/sha3.rs b/src/sha3.rs new file mode 100644 index 0000000..c3d00c5 --- /dev/null +++ b/src/sha3.rs @@ -0,0 +1,44 @@ +use std::fmt::Display; + +use digest::core_api::CoreWrapper; +use sha3::Digest; + +use super::BinaryId; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub(super) struct Sha512([u8; 64]); + +impl From for BinaryId { + fn from(value: sha3::Sha3_512) -> Self { + let data = value.finalize(); + let data = data.get(0..64).unwrap(); + let mut buf = [0; 64]; + if data.len() == 64 { + buf.copy_from_slice(data); + } + + Self { + hash_type: super::BinaryType::Sha3_512, + digest: super::Digest { + sha512: Sha512(buf), + }, + } + } +} + +impl From for BinaryId { + fn from(value: sha3::Sha3_512Core) -> Self { + CoreWrapper::from_core(value).into() + } +} + +impl Display for Sha512 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let buf = self.0; + // Write the hex digest + for byte in buf { + write!(f, "{:02x}", byte)?; + } + Ok(()) + } +} diff --git a/src/snapshots/dgst__binary_id_tests__display.snap b/src/snapshots/dgst__binary_id_tests__display.snap new file mode 100644 index 0000000..09d09ae --- /dev/null +++ b/src/snapshots/dgst__binary_id_tests__display.snap @@ -0,0 +1,5 @@ +--- +source: src/lib.rs +expression: binary_id.to_string() +--- +1ː00da39a3ee5e6b4b0d3255bfef95601890afd80709 diff --git a/src/snapshots/dgst__binary_id_tests__display_hello_world.snap b/src/snapshots/dgst__binary_id_tests__display_hello_world.snap new file mode 100644 index 0000000..edb44c4 --- /dev/null +++ b/src/snapshots/dgst__binary_id_tests__display_hello_world.snap @@ -0,0 +1,5 @@ +--- +source: src/lib.rs +expression: binary_id.to_string() +--- +1ː002aae6c35c94fcfb415dbe95f408b9ce91ee846ed