jamhash 0.1.3

Fast non-cryptographic hashing for canonical packed DNA kmers
Documentation
use jamhash::{JamHasher, jamhash_bytes, jamhash_u64};
use std::hash::Hasher;

fn main() {
    println!("=== jamhash Examples ===\n");

    // Example 1: Hash a single u64 (optimized path)
    println!("1. Hashing single u64 values:");
    let kmer = 0x1234567890abcdef;
    let hash = jamhash_u64(kmer);
    println!("   jamhash_u64(0x{:016x}) = 0x{:016x}", kmer, hash);
    println!(
        "   jamhash_u64(0) = 0x{:016x} (predictable zero)",
        jamhash_u64(0)
    );
    println!();

    // Example 2: Hash bytes (one-shot)
    println!("2. Hashing byte slices:");
    let data = b"hello world";
    let hash = jamhash_bytes(data);
    println!(
        "   jamhash_bytes({:?}) = 0x{:016x}",
        std::str::from_utf8(data).unwrap(),
        hash
    );
    println!();

    // Example 3: Hasher write calls are separate frames, not stream chunks.
    println!("3. Call-sequence hasher:");
    let mut one_frame = JamHasher::new();
    one_frame.write(b"hello world");
    let mut two_frames = JamHasher::new();
    two_frames.write(b"hello ");
    two_frames.write(b"world");
    println!("   One frame: 0x{:016x}", one_frame.finish());
    println!("   Two frames: 0x{:016x}", two_frames.finish());
    println!("   Write boundaries are part of the input");
    println!();

    // Example 4: Different input lengths produce different hashes
    println!("4. Length sensitivity:");
    for len in 0..=8 {
        let data = vec![0u8; len];
        let hash = jamhash_bytes(&data);
        println!("   {} zero bytes: 0x{:016x}", len, hash);
    }
    println!();

    // Example 5: Hash caller-canonicalized packed kmers directly.
    println!("5. Hashing packed canonical kmers:");
    let canonical_kmers = [0x0000_006f_93b4_b1bc, 0x0000_001b_e4ed_2c6f];
    for kmer in canonical_kmers {
        println!("   0x{kmer:016x} -> 0x{:016x}", jamhash_u64(kmer));
    }
    println!();

    // Example 6: Avalanche demonstration
    println!("6. Avalanche effect (bit difference):");
    let pairs = [
        (b"test" as &[u8], b"Test" as &[u8]),
        (b"hello", b"Hello"),
        (b"abc", b"abd"),
    ];

    for (a, b) in &pairs {
        let hash_a = jamhash_bytes(a);
        let hash_b = jamhash_bytes(b);
        let diff_bits = (hash_a ^ hash_b).count_ones();
        println!(
            "   {:?} vs {:?}: {} bits differ",
            std::str::from_utf8(a).unwrap(),
            std::str::from_utf8(b).unwrap(),
            diff_bits
        );
    }
}