diff --git a/Cargo.lock b/Cargo.lock
index 0a6ebcf..5f97feb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -68,6 +68,18 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "arrayref"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+
[[package]]
name = "atty"
version = "0.2.14"
@@ -91,6 +103,21 @@ version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+[[package]]
+name = "blake3"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+ "memmap2",
+ "rayon",
+]
+
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -117,6 +144,15 @@ version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -145,6 +181,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+[[package]]
+name = "constant_time_eq"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
+
[[package]]
name = "cpufeatures"
version = "0.2.12"
@@ -163,6 +205,31 @@ dependencies = [
"rustversion",
]
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+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.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
+
[[package]]
name = "crypto-common"
version = "0.1.6"
@@ -389,6 +456,7 @@ version = "1.24.0"
dependencies = [
"ansi_term",
"atty",
+ "blake3",
"camino",
"clap",
"cradle",
@@ -476,6 +544,15 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+[[package]]
+name = "memmap2"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "nix"
version = "0.27.1"
@@ -582,6 +659,26 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "rayon"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
+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_syscall"
version = "0.4.1"
diff --git a/Cargo.toml b/Cargo.toml
index 02cbbe0..7d86799 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,6 +20,7 @@ members = [".", "bin/ref-type", "bin/generate-book", "bin/update-contributors"]
[dependencies]
ansi_term = "0.12.0"
atty = "0.2.0"
+blake3 = { version = "1.5.0", features = ["rayon", "mmap"] }
camino = "1.0.4"
clap = { version = "2.33.0", features = ["wrap_help"] }
ctrlc = { version = "3.1.1", features = ["termination"] }
diff --git a/README.md b/README.md
index 8a1ddbc..46a93e6 100644
--- a/README.md
+++ b/README.md
@@ -1456,12 +1456,16 @@ which will halt execution.
#### UUID and Hash Generation
-- `sha256(string)` - Return the SHA-256 hash of `string` as a hexadecimal
+- `blake3(string)`master - Return [BLAKE3] hash of `string` as hexadecimal string.
+- `blake3_file(path)`master - Return [BLAKE3] hash of file at `path` as hexadecimal
+ string.
+- `sha256(string)` - Return the SHA-256 hash of `string` as hexadecimal string.
+- `sha256_file(path)` - Return SHA-256 hash of file at `path` as hexadecimal
string.
-- `sha256_file(path)` - Return the SHA-256 hash of the file at `path` as a
- hexadecimal string.
- `uuid()` - Generate a random version 4 UUID.
+[BLAKE3]: https://github.com/BLAKE3-team/BLAKE3/
+
#### Semantic Versions
- `semver_matches(version, requirement)`1.16.0 - Check whether a
diff --git a/src/function.rs b/src/function.rs
index 1262076..fee4bfc 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -21,6 +21,8 @@ pub(crate) fn get(name: &str) -> Option {
let function = match name {
"absolute_path" => Unary(absolute_path),
"arch" => Nullary(arch),
+ "blake3" => Unary(blake3),
+ "blake3_file" => Unary(blake3_file),
"canonicalize" => Unary(canonicalize),
"cache_directory" => Nullary(|_| dir("cache", dirs::cache_dir)),
"capitalize" => Unary(capitalize),
@@ -107,6 +109,19 @@ fn arch(_context: &FunctionContext) -> Result {
Ok(target::arch().to_owned())
}
+fn blake3(_context: &FunctionContext, s: &str) -> Result {
+ Ok(blake3::hash(s.as_bytes()).to_string())
+}
+
+fn blake3_file(context: &FunctionContext, path: &str) -> Result {
+ let path = context.search.working_directory.join(path);
+ let mut hasher = blake3::Hasher::new();
+ hasher
+ .update_mmap_rayon(&path)
+ .map_err(|err| format!("Failed to hash `{}`: {err}", path.display()))?;
+ Ok(hasher.finalize().to_string())
+}
+
fn canonicalize(_context: &FunctionContext, path: &str) -> Result {
let canonical =
std::fs::canonicalize(path).map_err(|err| format!("I/O error canonicalizing path: {err}"))?;
@@ -377,12 +392,12 @@ fn sha256(_context: &FunctionContext, s: &str) -> Result {
fn sha256_file(context: &FunctionContext, path: &str) -> Result {
use sha2::{Digest, Sha256};
- let justpath = context.search.working_directory.join(path);
+ let path = context.search.working_directory.join(path);
let mut hasher = Sha256::new();
- let mut file = fs::File::open(&justpath)
- .map_err(|err| format!("Failed to open file at `{:?}`: {err}", justpath.to_str()))?;
+ let mut file =
+ fs::File::open(&path).map_err(|err| format!("Failed to open `{}`: {err}", path.display()))?;
std::io::copy(&mut file, &mut hasher)
- .map_err(|err| format!("Failed to read file at `{:?}`: {err}", justpath.to_str()))?;
+ .map_err(|err| format!("Failed to read `{}`: {err}", path.display()))?;
let hash = hasher.finalize();
Ok(format!("{hash:x}"))
}
diff --git a/tests/functions.rs b/tests/functions.rs
index c356524..2c0e814 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -663,6 +663,30 @@ fn just_pid() {
assert_eq!(stdout.parse::().unwrap(), pid);
}
+#[test]
+fn blake3() {
+ Test::new()
+ .justfile("x := blake3('5943ee37-0000-1000-8000-010203040506')")
+ .args(["--evaluate", "x"])
+ .stdout("026c9f740a793ff536ddf05f8915ea4179421f47f0fa9545476076e9ba8f3f2b")
+ .run();
+}
+
+#[test]
+fn blake3_file() {
+ Test::new()
+ .justfile("x := blake3_file('sub/blakefile')")
+ .tree(tree! {
+ sub: {
+ blakefile: "just is great\n",
+ }
+ })
+ .current_dir("sub")
+ .args(["--evaluate", "x"])
+ .stdout("8379241877190ca4b94076a8c8f89fe5747f95c62f3e4bf41f7408a0088ae16d")
+ .run();
+}
+
#[cfg(unix)]
#[test]
fn canonicalize() {