669 lines
19 KiB
Rust
Raw Normal View History

2025-06-27 02:31:23 +01:00
use digest::DynDigest;
const TEST_TEXT: &str = "abcdefghijklmnopqrstuvwxyz";
struct GeneratedHasherImplMeta {
crate_name: &'static str,
hasher_type_name: &'static str,
hasher_command: &'static str,
hasher: Box<dyn DynDigest>,
}
#[cfg(any(
feature = "ascon-hash",
feature = "belt-hash",
feature = "blake2",
feature = "blake3",
feature = "fsb",
feature = "gost94",
feature = "groestl",
feature = "jh",
feature = "md2",
feature = "md4",
feature = "ripemd",
feature = "sha1",
feature = "sha2",
feature = "sha3",
feature = "shabal",
feature = "skein",
feature = "sm3",
feature = "streebog",
feature = "tiger",
feature = "whirlpool",
))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
use std::{env, io::Write, path::Path};
// MD5 and SHA256 are skipped on purpose
let hasher_impls: Vec<GeneratedHasherImplMeta> = vec![
#[cfg(feature = "ascon-hash")]
GeneratedHasherImplMeta {
crate_name: "ascon_hash",
feat: major repository modernization and tracking cleanup ## Summary Comprehensive repository cleanup focusing on plugin dependency management, documentation improvements, and git tracking optimization. ## Key Changes ### 🔧 Core Infrastructure - Synchronized all nu-* dependencies across plugins for version consistency - Enhanced upstream tracking and automation systems - Removed nushell directory from git tracking for cleaner repository management ### 📚 Documentation - Significantly expanded README.md with comprehensive development guides - Added detailed workflow documentation and command references - Improved plugin collection overview and usage examples ### 🧹 Repository Cleanup - Removed legacy bash scripts (build-all.sh, collect-install.sh, make_plugin.sh) - Streamlined automation through unified justfile and nushell script approach - Updated .gitignore with nushell directory and archive patterns - Removed nushell directory from git tracking to prevent unwanted changes ### 🔌 Plugin Updates - **nu_plugin_image**: Major refactoring with modular architecture improvements - **nu_plugin_hashes**: Enhanced functionality and build system improvements - **nu_plugin_highlight**: Updated for new plugin API compatibility - **nu_plugin_clipboard**: Dependency synchronization - **nu_plugin_desktop_notifications**: Version alignment - **nu_plugin_port_extension & nu_plugin_qr_maker**: Consistency updates - **nu_plugin_kcl & nu_plugin_tera**: Submodule synchronization ### 🏗️ Git Tracking Optimization - Removed nushell directory from version control for cleaner repository management - Added comprehensive .gitignore patterns for build artifacts and archives ## Statistics - 2,082 files changed - 2,373 insertions, 339,936 deletions - Net reduction of 337,563 lines (primarily from removing nushell directory tracking) ## Benefits - Complete version consistency across all plugins - Cleaner repository with optimized git tracking - Improved developer experience with streamlined workflows - Enhanced documentation and automation - Reduced repository size and complexity 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-20 15:18:58 +01:00
hasher_type_name: "AsconHash256",
2025-06-27 02:31:23 +01:00
hasher_command: "ascon",
feat: major repository modernization and tracking cleanup ## Summary Comprehensive repository cleanup focusing on plugin dependency management, documentation improvements, and git tracking optimization. ## Key Changes ### 🔧 Core Infrastructure - Synchronized all nu-* dependencies across plugins for version consistency - Enhanced upstream tracking and automation systems - Removed nushell directory from git tracking for cleaner repository management ### 📚 Documentation - Significantly expanded README.md with comprehensive development guides - Added detailed workflow documentation and command references - Improved plugin collection overview and usage examples ### 🧹 Repository Cleanup - Removed legacy bash scripts (build-all.sh, collect-install.sh, make_plugin.sh) - Streamlined automation through unified justfile and nushell script approach - Updated .gitignore with nushell directory and archive patterns - Removed nushell directory from git tracking to prevent unwanted changes ### 🔌 Plugin Updates - **nu_plugin_image**: Major refactoring with modular architecture improvements - **nu_plugin_hashes**: Enhanced functionality and build system improvements - **nu_plugin_highlight**: Updated for new plugin API compatibility - **nu_plugin_clipboard**: Dependency synchronization - **nu_plugin_desktop_notifications**: Version alignment - **nu_plugin_port_extension & nu_plugin_qr_maker**: Consistency updates - **nu_plugin_kcl & nu_plugin_tera**: Submodule synchronization ### 🏗️ Git Tracking Optimization - Removed nushell directory from version control for cleaner repository management - Added comprehensive .gitignore patterns for build artifacts and archives ## Statistics - 2,082 files changed - 2,373 insertions, 339,936 deletions - Net reduction of 337,563 lines (primarily from removing nushell directory tracking) ## Benefits - Complete version consistency across all plugins - Cleaner repository with optimized git tracking - Improved developer experience with streamlined workflows - Enhanced documentation and automation - Reduced repository size and complexity 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-20 15:18:58 +01:00
hasher: Box::new(ascon_hash::AsconHash256::default()),
2025-06-27 02:31:23 +01:00
},
#[cfg(feature = "belt-hash")]
GeneratedHasherImplMeta {
crate_name: "belt_hash",
hasher_type_name: "BeltHash",
hasher_command: "belt",
hasher: Box::new(belt_hash::BeltHash::default()),
},
#[cfg(feature = "blake2")]
GeneratedHasherImplMeta {
crate_name: "blake2",
hasher_type_name: "Blake2s256",
hasher_command: "blake2s-256",
hasher: Box::new(blake2::Blake2s256::default()),
},
#[cfg(feature = "blake2")]
GeneratedHasherImplMeta {
crate_name: "blake2",
hasher_type_name: "Blake2b512",
hasher_command: "blake2b-512",
hasher: Box::new(blake2::Blake2b512::default()),
},
#[cfg(feature = "blake3")]
GeneratedHasherImplMeta {
crate_name: "blake3",
hasher_type_name: "Hasher",
hasher_command: "blake3",
hasher: Box::new(blake3::Hasher::new()),
},
#[cfg(feature = "fsb")]
GeneratedHasherImplMeta {
crate_name: "fsb",
hasher_type_name: "Fsb160",
hasher_command: "fsb160",
hasher: Box::new(fsb::Fsb160::default()),
},
#[cfg(feature = "fsb")]
GeneratedHasherImplMeta {
crate_name: "fsb",
hasher_type_name: "Fsb224",
hasher_command: "fsb224",
hasher: Box::new(fsb::Fsb224::default()),
},
#[cfg(feature = "fsb")]
GeneratedHasherImplMeta {
crate_name: "fsb",
hasher_type_name: "Fsb256",
hasher_command: "fsb256",
hasher: Box::new(fsb::Fsb256::default()),
},
#[cfg(feature = "fsb")]
GeneratedHasherImplMeta {
crate_name: "fsb",
hasher_type_name: "Fsb384",
hasher_command: "fsb384",
hasher: Box::new(fsb::Fsb384::default()),
},
#[cfg(feature = "fsb")]
GeneratedHasherImplMeta {
crate_name: "fsb",
hasher_type_name: "Fsb512",
hasher_command: "fsb512",
hasher: Box::new(fsb::Fsb512::default()),
},
#[cfg(feature = "gost94")]
GeneratedHasherImplMeta {
crate_name: "gost94",
hasher_type_name: "Gost94CryptoPro",
hasher_command: "gost94-crypto-pro",
hasher: Box::new(gost94::Gost94CryptoPro::default()),
},
#[cfg(feature = "gost94")]
GeneratedHasherImplMeta {
crate_name: "gost94",
hasher_type_name: "Gost94UA",
hasher_command: "gost94-ua",
hasher: Box::new(gost94::Gost94UA::default()),
},
#[cfg(feature = "gost94")]
GeneratedHasherImplMeta {
crate_name: "gost94",
hasher_type_name: "Gost94s2015",
hasher_command: "gost94-2015",
hasher: Box::new(gost94::Gost94s2015::default()),
},
#[cfg(feature = "groestl")]
GeneratedHasherImplMeta {
crate_name: "groestl",
hasher_type_name: "Groestl224",
hasher_command: "groestl224",
hasher: Box::new(groestl::Groestl224::default()),
},
#[cfg(feature = "groestl")]
GeneratedHasherImplMeta {
crate_name: "groestl",
hasher_type_name: "Groestl256",
hasher_command: "groestl256",
hasher: Box::new(groestl::Groestl256::default()),
},
#[cfg(feature = "groestl")]
GeneratedHasherImplMeta {
crate_name: "groestl",
hasher_type_name: "Groestl384",
hasher_command: "groestl384",
hasher: Box::new(groestl::Groestl384::default()),
},
#[cfg(feature = "groestl")]
GeneratedHasherImplMeta {
crate_name: "groestl",
hasher_type_name: "Groestl512",
hasher_command: "groestl512",
hasher: Box::new(groestl::Groestl512::default()),
},
#[cfg(feature = "jh")]
GeneratedHasherImplMeta {
crate_name: "jh",
hasher_type_name: "Jh224",
hasher_command: "jh224",
hasher: Box::new(jh::Jh224::default()),
},
#[cfg(feature = "jh")]
GeneratedHasherImplMeta {
crate_name: "jh",
hasher_type_name: "Jh256",
hasher_command: "jh256",
hasher: Box::new(jh::Jh256::default()),
},
#[cfg(feature = "jh")]
GeneratedHasherImplMeta {
crate_name: "jh",
hasher_type_name: "Jh384",
hasher_command: "jh384",
hasher: Box::new(jh::Jh384::default()),
},
#[cfg(feature = "jh")]
GeneratedHasherImplMeta {
crate_name: "jh",
hasher_type_name: "Jh512",
hasher_command: "jh512",
hasher: Box::new(jh::Jh512::default()),
},
#[cfg(feature = "md2")]
GeneratedHasherImplMeta {
crate_name: "md2",
hasher_type_name: "Md2",
hasher_command: "md2",
hasher: Box::new(md2::Md2::default()),
},
#[cfg(feature = "md4")]
GeneratedHasherImplMeta {
crate_name: "md4",
hasher_type_name: "Md4",
hasher_command: "md4",
hasher: Box::new(md4::Md4::default()),
},
#[cfg(feature = "ripemd")]
GeneratedHasherImplMeta {
crate_name: "ripemd",
hasher_type_name: "Ripemd128",
hasher_command: "ripemd128",
hasher: Box::new(ripemd::Ripemd128::default()),
},
#[cfg(feature = "ripemd")]
GeneratedHasherImplMeta {
crate_name: "ripemd",
hasher_type_name: "Ripemd160",
hasher_command: "ripemd160",
hasher: Box::new(ripemd::Ripemd160::default()),
},
#[cfg(feature = "ripemd")]
GeneratedHasherImplMeta {
crate_name: "ripemd",
hasher_type_name: "Ripemd256",
hasher_command: "ripemd256",
hasher: Box::new(ripemd::Ripemd256::default()),
},
#[cfg(feature = "ripemd")]
GeneratedHasherImplMeta {
crate_name: "ripemd",
hasher_type_name: "Ripemd320",
hasher_command: "ripemd320",
hasher: Box::new(ripemd::Ripemd320::default()),
},
#[cfg(feature = "sha1")]
GeneratedHasherImplMeta {
crate_name: "sha1",
hasher_type_name: "Sha1",
hasher_command: "sha1",
hasher: Box::new(sha1::Sha1::default()),
},
#[cfg(feature = "sha2")]
GeneratedHasherImplMeta {
crate_name: "sha2",
hasher_type_name: "Sha224",
hasher_command: "sha224",
hasher: Box::new(sha2::Sha224::default()),
},
#[cfg(feature = "sha2")]
GeneratedHasherImplMeta {
crate_name: "sha2",
hasher_type_name: "Sha384",
hasher_command: "sha384",
hasher: Box::new(sha2::Sha384::default()),
},
#[cfg(feature = "sha2")]
GeneratedHasherImplMeta {
crate_name: "sha2",
hasher_type_name: "Sha512",
hasher_command: "sha512",
hasher: Box::new(sha2::Sha512::default()),
},
#[cfg(feature = "sha2")]
GeneratedHasherImplMeta {
crate_name: "sha2",
hasher_type_name: "Sha512_224",
hasher_command: "sha512-224",
hasher: Box::new(sha2::Sha512_224::default()),
},
#[cfg(feature = "sha2")]
GeneratedHasherImplMeta {
crate_name: "sha2",
hasher_type_name: "Sha512_256",
hasher_command: "sha512-256",
hasher: Box::new(sha2::Sha512_256::default()),
},
#[cfg(feature = "sha3")]
GeneratedHasherImplMeta {
crate_name: "sha3",
hasher_type_name: "Sha3_224",
hasher_command: "sha3-224",
hasher: Box::new(sha3::Sha3_224::default()),
},
#[cfg(feature = "sha3")]
GeneratedHasherImplMeta {
crate_name: "sha3",
hasher_type_name: "Sha3_256",
hasher_command: "sha3-256",
hasher: Box::new(sha3::Sha3_256::default()),
},
#[cfg(feature = "sha3")]
GeneratedHasherImplMeta {
crate_name: "sha3",
hasher_type_name: "Sha3_384",
hasher_command: "sha3-384",
hasher: Box::new(sha3::Sha3_384::default()),
},
#[cfg(feature = "sha3")]
GeneratedHasherImplMeta {
crate_name: "sha3",
hasher_type_name: "Sha3_512",
hasher_command: "sha3-512",
hasher: Box::new(sha3::Sha3_512::default()),
},
#[cfg(feature = "sha3")]
GeneratedHasherImplMeta {
crate_name: "sha3",
hasher_type_name: "Keccak224",
hasher_command: "keccak224",
hasher: Box::new(sha3::Keccak224::default()),
},
#[cfg(feature = "sha3")]
GeneratedHasherImplMeta {
crate_name: "sha3",
hasher_type_name: "Keccak256",
hasher_command: "keccak256",
hasher: Box::new(sha3::Keccak256::default()),
},
#[cfg(feature = "sha3")]
GeneratedHasherImplMeta {
crate_name: "sha3",
hasher_type_name: "Keccak384",
hasher_command: "keccak384",
hasher: Box::new(sha3::Keccak384::default()),
},
#[cfg(feature = "sha3")]
GeneratedHasherImplMeta {
crate_name: "sha3",
hasher_type_name: "Keccak512",
hasher_command: "keccak512",
hasher: Box::new(sha3::Keccak512::default()),
},
#[cfg(feature = "shabal")]
GeneratedHasherImplMeta {
crate_name: "shabal",
hasher_type_name: "Shabal192",
hasher_command: "shabal192",
hasher: Box::new(shabal::Shabal192::default()),
},
#[cfg(feature = "shabal")]
GeneratedHasherImplMeta {
crate_name: "shabal",
hasher_type_name: "Shabal224",
hasher_command: "shabal224",
hasher: Box::new(shabal::Shabal224::default()),
},
#[cfg(feature = "shabal")]
GeneratedHasherImplMeta {
crate_name: "shabal",
hasher_type_name: "Shabal256",
hasher_command: "shabal256",
hasher: Box::new(shabal::Shabal256::default()),
},
#[cfg(feature = "shabal")]
GeneratedHasherImplMeta {
crate_name: "shabal",
hasher_type_name: "Shabal384",
hasher_command: "shabal384",
hasher: Box::new(shabal::Shabal384::default()),
},
#[cfg(feature = "shabal")]
GeneratedHasherImplMeta {
crate_name: "shabal",
hasher_type_name: "Shabal512",
hasher_command: "shabal512",
hasher: Box::new(shabal::Shabal512::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein256::<skein::consts::U32>",
hasher_command: "skein256-32",
hasher: Box::new(skein::Skein256::<skein::consts::U32>::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein256::<skein::consts::U64>",
hasher_command: "skein256-64",
hasher: Box::new(skein::Skein256::<skein::consts::U64>::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein256::<skein::consts::U128>",
hasher_command: "skein256-128",
hasher: Box::new(skein::Skein256::<skein::consts::U128>::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein512::<skein::consts::U32>",
hasher_command: "skein512-32",
hasher: Box::new(skein::Skein512::<skein::consts::U32>::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein512::<skein::consts::U64>",
hasher_command: "skein512-64",
hasher: Box::new(skein::Skein512::<skein::consts::U64>::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein512::<skein::consts::U128>",
hasher_command: "skein512-128",
hasher: Box::new(skein::Skein512::<skein::consts::U128>::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein1024::<skein::consts::U32>",
hasher_command: "skein1024-32",
hasher: Box::new(skein::Skein1024::<skein::consts::U32>::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein1024::<skein::consts::U64>",
hasher_command: "skein1024-64",
hasher: Box::new(skein::Skein1024::<skein::consts::U64>::default()),
},
#[cfg(feature = "skein")]
GeneratedHasherImplMeta {
crate_name: "skein",
hasher_type_name: "Skein1024::<skein::consts::U128>",
hasher_command: "skein1024-128",
hasher: Box::new(skein::Skein1024::<skein::consts::U128>::default()),
},
#[cfg(feature = "sm3")]
GeneratedHasherImplMeta {
crate_name: "sm3",
hasher_type_name: "Sm3",
hasher_command: "sm3",
hasher: Box::new(sm3::Sm3::default()),
},
#[cfg(feature = "streebog")]
GeneratedHasherImplMeta {
crate_name: "streebog",
hasher_type_name: "Streebog256",
hasher_command: "streebog256",
hasher: Box::new(streebog::Streebog256::default()),
},
#[cfg(feature = "streebog")]
GeneratedHasherImplMeta {
crate_name: "streebog",
hasher_type_name: "Streebog512",
hasher_command: "streebog512",
hasher: Box::new(streebog::Streebog512::default()),
},
#[cfg(feature = "tiger")]
GeneratedHasherImplMeta {
crate_name: "tiger",
hasher_type_name: "Tiger",
hasher_command: "tiger",
hasher: Box::new(tiger::Tiger::default()),
},
#[cfg(feature = "tiger")]
GeneratedHasherImplMeta {
crate_name: "tiger",
hasher_type_name: "Tiger2",
hasher_command: "tiger2",
hasher: Box::new(tiger::Tiger2::default()),
},
#[cfg(feature = "whirlpool")]
GeneratedHasherImplMeta {
crate_name: "whirlpool",
hasher_type_name: "Whirlpool",
hasher_command: "whirlpool",
hasher: Box::new(whirlpool::Whirlpool::default()),
},
];
let out_dir = env::var_os("OUT_DIR").unwrap();
let hashers_generated_path = Path::new(&out_dir).join("hashers_generated.rs");
let commands_generated_path =
Path::new(&out_dir).join("commands_generated.rs");
let mut hashers_generated_file =
std::fs::File::create(hashers_generated_path).unwrap();
let mut commands_generated_file =
std::fs::File::create(commands_generated_path).unwrap();
write!(
hashers_generated_file,
"use nu_protocol::{{Example, Span, Value, ShellError}};
use nu_plugin::PluginCommand;
use crate::HashesPlugin;
use crate::hasher::{{Hasher, GenericHasher}};
"
)?;
write!(
commands_generated_file,
"use nu_plugin::PluginCommand;
use crate::{{HashesPlugin, hasher::GenericHasher}};
pub fn commands() -> Vec<Box<dyn PluginCommand<Plugin = HashesPlugin>>> {{
vec![
"
)?;
for mut hasher_impl_meta in hasher_impls {
let feature_name =
hasher_impl_meta.crate_name.replace("-", "_").to_uppercase();
if std::env::var(format!("CARGO_FEATURE_{feature_name}")).is_ok() {
hashers_generated_file
.write_all(build_impl_str(&mut hasher_impl_meta).as_bytes())?;
hashers_generated_file
.write_all(build_test_str(&hasher_impl_meta).as_bytes())?;
let crate_name = hasher_impl_meta.crate_name;
let hasher_type_name = hasher_impl_meta.hasher_type_name;
writeln!(
commands_generated_file,
" Box::new(GenericHasher::<{crate_name}::{hasher_type_name}>::default()),"
)?;
}
}
write!(
commands_generated_file,
" ]
}}"
)?;
hashers_generated_file.flush()?;
commands_generated_file.flush()?;
Ok(())
}
#[cfg(any(
feature = "ascon-hash",
feature = "belt-hash",
feature = "blake2",
feature = "blake3",
feature = "fsb",
feature = "gost94",
feature = "groestl",
feature = "jh",
feature = "md2",
feature = "md4",
feature = "ripemd",
feature = "sha1",
feature = "sha2",
feature = "sha3",
feature = "shabal",
feature = "skein",
feature = "sm3",
feature = "streebog",
feature = "tiger",
feature = "whirlpool",
))]
fn build_impl_str(meta: &mut GeneratedHasherImplMeta) -> String {
let crate_name = meta.crate_name;
let hasher_type_name = meta.hasher_type_name;
let command = meta.hasher_command;
let mut hasher = meta.hasher.clone();
hasher.update(TEST_TEXT.as_bytes());
let hash = hasher.clone().finalize();
format!(
"
impl Hasher for {crate_name}::{hasher_type_name} {{
fn name() -> &'static str {{
\"{command}\"
}}
fn examples() -> Vec<Example<'static>> {{
vec![
Example {{
description: \"Return the {command} hash of a string, hex-encoded\",
example: \"'{TEST_TEXT}' | hash {command}\",
result: Some(Value::string(
\"{}\".to_owned(),
Span::test_data(),
)),
}},
Example {{
description: \"Return the {command} hash of a string, as binary\",
example: \"'{TEST_TEXT}' | hash {command} --binary\",
result: Some(Value::binary(
vec![{}],
Span::test_data(),
)),
}},
Example {{
description: \"Return the {command} hash of a file's contents\",
example: \"open ./nu_0_24_1_windows.zip | hash {command}\",
result: None,
}},
]
}}
}}
",
hash
.iter()
.map(|b| format!("{b:02x?}"))
.collect::<Vec<_>>()
.join(""),
hash
.iter()
.map(|b| format!("0x{b:02x?}"))
.collect::<Vec<_>>()
.join(",")
)
}
#[cfg(any(
feature = "ascon-hash",
feature = "belt-hash",
feature = "blake2",
feature = "blake3",
feature = "fsb",
feature = "gost94",
feature = "groestl",
feature = "jh",
feature = "md2",
feature = "md4",
feature = "ripemd",
feature = "sha1",
feature = "sha2",
feature = "sha3",
feature = "shabal",
feature = "skein",
feature = "sm3",
feature = "streebog",
feature = "tiger",
feature = "whirlpool",
))]
fn build_test_str(meta: &GeneratedHasherImplMeta) -> String {
let crate_name = meta.crate_name;
let hasher_type_name = meta.hasher_type_name;
let command = meta.hasher_command;
let test_name = command.replace("-", "_");
format!(
"
#[test]
fn test_{test_name}_examples() -> Result<(), ShellError> {{
nu_plugin_test_support::PluginTest::new
(
\"hash {command}\",
HashesPlugin.into()
)?
.test_examples(&GenericHasher::<{crate_name}::{hasher_type_name}>::default().examples())
}}
"
)
}
#[cfg(not(any(
feature = "ascon-hash",
feature = "belt-hash",
feature = "blake2",
feature = "blake3",
feature = "fsb",
feature = "gost94",
feature = "groestl",
feature = "jh",
feature = "md2",
feature = "md4",
feature = "ripemd",
feature = "sha1",
feature = "sha2",
feature = "sha3",
feature = "shabal",
feature = "skein",
feature = "sm3",
feature = "streebog",
feature = "tiger",
feature = "whirlpool",
)))]
fn main() {
compile_error!("enable at least one feature to compile this plugin");
}