candding 0.1.0

Pure candle embeddings for Rust with no ONNX: dense, sparse, multi-vector and rerank models today, image models on the roadmap
Documentation
use crate::models::SparseHead;
use crate::registry::BackendSupport;
use crate::registry::Family;
use crate::registry::Support;
use crate::registry::WeightsFormat;
use crate::registry::sparse;
use crate::registry::sparse::SparseComputation;
use crate::registry::sparse::SparseDescriptor;

/// SPLADE's `default_max_length` is its model limit, not its published tokenizer's baked-in 128-token truncation.
#[test]
fn three_of_the_six_sparse_entries_carry_the_spec_values() {
  let splade = sparse::lookup("prithivida/Splade_PP_en_v1").expect("registered");
  assert_eq!(splade.family, Some(Family::Bert));
  assert_eq!(splade.head, SparseHead::SpladeMlm);
  assert_eq!(splade.vocab_size, 30522);
  assert_eq!(splade.default_max_length, 512);
  assert_eq!(splade.license, "Apache-2.0");
  assert_eq!(splade.size_gb, 0.44);
  assert_eq!(splade.phase, 3);
  assert_eq!(splade.weights, WeightsFormat::Pickle);
  assert!(!splade.gated);

  let bge_m3 = sparse::lookup("baai/bge-m3").expect("lookup is case-insensitive");
  assert_eq!(bge_m3.id, "BAAI/bge-m3");
  assert_eq!(bge_m3.family, Some(Family::XlmRoberta));
  assert_eq!(bge_m3.head, SparseHead::M3Linear);
  assert_eq!(bge_m3.vocab_size, 250002);
  assert_eq!(bge_m3.default_max_length, 8192);
  assert_eq!(bge_m3.license, "MIT");
  assert_eq!(bge_m3.size_gb, 2.27);
  assert_eq!(bge_m3.phase, 3);
  assert_eq!(bge_m3.weights, WeightsFormat::Pickle);
  assert!(!bge_m3.gated);

  let splade_code = sparse::lookup("naver/splade-code-06B").expect("registered");
  assert_eq!(splade_code.family, Some(Family::Qwen3));
  assert_eq!(splade_code.head, SparseHead::SpladeTied);
  assert_eq!(splade_code.vocab_size, 151936);
  assert_eq!(splade_code.default_max_length, 1024);
  assert_eq!(splade_code.license, "NAVER Non-Commercial (Splade-Code)");
  assert_eq!(splade_code.size_gb, 1.19);
  assert_eq!(splade_code.phase, 3);
  assert_eq!(splade_code.weights, WeightsFormat::Safetensors);
  assert!(!splade_code.gated);

  assert_eq!(sparse::all().len(), 6);
}

/// `vocab_size` is 19125, one more than the vocabulary file's 19124 words: id zero is reserved for an unknown word.
#[test]
fn minicoil_keeps_the_encoders_repository_id_and_names_its_own_pinned_head_source() {
  let minicoil = sparse::lookup("jinaai/jina-embeddings-v2-small-en").expect("registered");
  assert_eq!(minicoil.family, Some(Family::JinaBert));
  assert_eq!(minicoil.head, SparseHead::MiniCoil);
  assert_eq!(minicoil.vocab_size, 19125);
  assert_eq!(minicoil.default_max_length, 8192);
  assert_eq!(minicoil.license, "Apache-2.0");
  assert_eq!(minicoil.phase, 3);
  assert_eq!(minicoil.weights, WeightsFormat::Safetensors);
  assert!(!minicoil.gated);
  assert_eq!(minicoil.head_source.as_deref(), Some("Qdrant/minicoil-v1"));
  assert_eq!(
    minicoil.head_revision.as_deref(),
    Some("4a7b05822a7a246d25778508593fff58fe574dfe")
  );

  for descriptor in sparse::all() {
    if descriptor.id != minicoil.id {
      assert_eq!(descriptor.head_source, None, "{}", descriptor.id);
      assert_eq!(descriptor.head_revision, None, "{}", descriptor.id);
    }
  }
}

#[test]
fn bge_m3_sparse_is_a_second_row_beside_the_untouched_dense_entry() {
  let dense = crate::registry::dense::lookup("BAAI/bge-m3").expect("the dense entry still exists");
  assert_eq!(dense.dim, 1024);
  assert!(sparse::lookup("BAAI/bge-m3").is_some());
}

#[test]
fn bm42_is_a_second_row_beside_the_untouched_dense_bert_entry_and_names_no_second_repository() {
  let dense = crate::registry::dense::lookup("sentence-transformers/all-MiniLM-L6-v2")
    .expect("the dense entry still exists");
  assert_eq!(dense.dim, 384);

  let bm42 = sparse::lookup("sentence-transformers/all-MiniLM-L6-v2").expect("registered");
  assert_eq!(bm42.family, Some(Family::Bert));
  assert_eq!(bm42.head, SparseHead::Bm42);
  assert_eq!(bm42.vocab_size, 30522);
  assert_eq!(bm42.default_max_length, 256);
  assert_eq!(bm42.license, "Apache-2.0");
  assert_eq!(bm42.size_gb, 0.09);
  assert_eq!(bm42.phase, 3);
  assert_eq!(bm42.weights, WeightsFormat::Safetensors);
  assert!(!bm42.gated);
  assert_eq!(bm42.head_source, None);
  assert_eq!(bm42.head_revision, None);
}

#[test]
fn bm25_is_a_computed_entry_with_no_encoder_weights_or_device_or_dtype_status() {
  let bm25 = sparse::lookup("Qdrant/bm25").expect("registered");
  assert_eq!(bm25.family, None);
  assert_eq!(bm25.head, SparseHead::Bm25);
  assert_eq!(bm25.vocab_size, 0);
  assert_eq!(bm25.license, "Apache-2.0");
  assert_eq!(bm25.phase, 3);
  assert_eq!(bm25.weights, WeightsFormat::NoWeights);
  assert!(!bm25.gated);
  assert_eq!(bm25.head_source, None);
  assert_eq!(bm25.head_revision, None);
  assert_eq!(bm25.computation, SparseComputation::Computed);
  for status in [bm25.backends.cpu, bm25.backends.metal, bm25.backends.cuda] {
    assert_eq!(status, Support::NotApplicable);
  }
  for row in [
    bm25.dtype_backends.f32,
    bm25.dtype_backends.f16,
    bm25.dtype_backends.bf16,
  ] {
    assert_eq!(row, BackendSupport::not_applicable(), "all nine cells");
  }
}

#[test]
fn by_phase_returns_all_six_entries_for_phase_three_and_none_for_an_unused_phase() {
  assert_eq!(
    sparse::by_phase(3)
      .iter()
      .map(|d| d.id.as_str())
      .collect::<Vec<_>>(),
    vec![
      "prithivida/Splade_PP_en_v1",
      "BAAI/bge-m3",
      "naver/splade-code-06B",
      "jinaai/jina-embeddings-v2-small-en",
      "sentence-transformers/all-MiniLM-L6-v2",
      "Qdrant/bm25",
    ]
  );
  assert!(sparse::by_phase(9).is_empty());
}

#[test]
fn weights_format_finds_a_head_source_id_that_is_no_entrys_own() {
  assert_eq!(
    crate::registry::weights_format("Qdrant/minicoil-v1"),
    WeightsFormat::Npy
  );
  assert_eq!(
    crate::registry::weights_format("qdrant/minicoil-v1"),
    WeightsFormat::Npy
  );
  assert_eq!(
    crate::registry::weights_format("an-id-nothing-names-at-all"),
    WeightsFormat::Safetensors
  );
}

#[test]
fn sparse_descriptor_round_trips_through_json() {
  let descriptor = sparse::lookup("BAAI/bge-m3").unwrap();
  let json = serde_json::to_string(&descriptor).unwrap();
  assert!(json.contains("\"head\":\"m3_linear\""));
  assert!(json.contains("\"weights\":\"pickle\""));
  let back: SparseDescriptor = serde_json::from_str(&json).unwrap();
  assert_eq!(back, descriptor);
}

mod dtype_backends;
mod invariants;