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 super::*;

#[test]
fn phase_one_has_the_three_qwen3_embedding_models() {
  let phase1: Vec<_> = by_phase(1)
    .into_iter()
    .filter(|d| d.family == Family::Qwen3)
    .collect();
  assert_eq!(
    phase1.iter().map(|d| d.dim).collect::<Vec<_>>(),
    vec![1024, 2560, 4096]
  );
  for d in &phase1 {
    assert_eq!(d.family, Family::Qwen3, "{}", d.id);
    assert_eq!(d.pooling, Pooling::LastToken, "{}", d.id);
    assert!(
      d.mrl && d.normalize && d.passage_template.is_none(),
      "{}",
      d.id
    );
    assert_eq!(
      d.query_template.as_deref(),
      Some("Instruct: {instruction}\nQuery:{text}"),
      "{}",
      d.id
    );
    assert!(d.default_instruction.is_some(), "{}", d.id);
    assert_eq!(d.default_max_length, 8192, "{}", d.id);
    assert!(d.dense_dirs.is_empty() && !d.gated, "{}", d.id);
  }
  assert_eq!(
    lookup("Qwen/Qwen3-Embedding-0.6B").unwrap().default_dtype,
    DType::F32
  );
  assert_eq!(
    lookup("Qwen/Qwen3-Embedding-4B").unwrap().default_dtype,
    DType::BF16
  );
  assert_eq!(
    lookup("Qwen/Qwen3-Embedding-8B")
      .unwrap()
      .dtype_backends
      .f32,
    BackendSupport {
      cpu: Support::Untested,
      metal: Support::Untested,
      cuda: Support::Untested,
    },
    "the 32 GB f32 weights are untested on every device, not merely the cpu the model-wide backends field names"
  );
}

#[test]
fn phase_one_has_embeddinggemma() {
  let d = lookup("google/embeddinggemma-300m").expect("registered");
  assert_eq!(d.family, Family::Gemma3);
  assert_eq!((d.dim, d.default_max_length), (768, 2048));
  assert_eq!(d.pooling, Pooling::Mean);
  assert_eq!(
    d.dense_dirs,
    vec!["2_Dense".to_string(), "3_Dense".to_string()]
  );
  assert!(d.mrl && d.normalize && d.gated);
  assert_eq!(
    d.query_template.as_deref(),
    Some("task: {instruction} | query: {text}")
  );
  assert_eq!(d.default_instruction.as_deref(), Some("search result"));
  assert_eq!(
    d.passage_template.as_deref(),
    Some("title: none | text: {text}")
  );
  assert_eq!(d.default_dtype, DType::F32);
  assert_eq!(
    d.dtype_backends.f16,
    BackendSupport {
      cpu: Support::Unsupported,
      metal: Support::Unsupported,
      cuda: Support::Unsupported,
    },
    "f16 overflows this model's residual stream on every device, not only the ones ever run"
  );
  assert_eq!(
    (d.dtype_backends.f32, d.dtype_backends.bf16),
    (
      BackendSupport {
        cpu: Support::Verified,
        metal: Support::Verified,
        cuda: Support::Untested,
      },
      BackendSupport {
        cpu: Support::Unsupported,
        metal: Support::Verified,
        cuda: Support::Untested,
      }
    ),
    "bf16 is refused on the processor, where candle has no bf16 matmul"
  );
  assert_eq!(by_phase(1).len(), 4);
}

#[test]
fn phase_zero_is_verified_on_metal() {
  for descriptor in by_phase(0) {
    assert_eq!(
      descriptor.backends.metal,
      Support::Verified,
      "{}",
      descriptor.id
    );
  }
}

#[test]
fn backends_serialize_snake_case() {
  let json = serde_json::to_string(&lookup("BAAI/bge-small-en-v1.5").unwrap()).unwrap();
  assert!(
    json
      .contains("\"backends\":{\"cpu\":\"verified\",\"metal\":\"verified\",\"cuda\":\"verified\"}")
  );
}

/// A BF16 default loads as F32 on the processor, so F32 must run there.
#[test]
fn default_dtype_is_never_unsupported() {
  for descriptor in all() {
    let row = descriptor.dtype_backends.row(descriptor.default_dtype);
    assert_ne!(row.metal, Support::Unsupported, "{}", descriptor.id);
    let cpu_dtype = if descriptor.default_dtype == DType::BF16 {
      DType::F32
    } else {
      descriptor.default_dtype
    };
    assert_ne!(
      descriptor.dtype_backends.row(cpu_dtype).cpu,
      Support::Unsupported,
      "{}",
      descriptor.id
    );
  }
}

#[test]
fn dtype_fields_serialize_by_name() {
  let json = serde_json::to_string(&lookup("BAAI/bge-small-en-v1.5").unwrap()).unwrap();
  assert!(json.contains("\"default_dtype\":\"f32\""), "{json}");
  let verified_row = "{\"cpu\":\"verified\",\"metal\":\"verified\",\"cuda\":\"verified\"}";
  let bf16_row = "{\"cpu\":\"unsupported\",\"metal\":\"verified\",\"cuda\":\"untested\"}";
  assert!(
    json.contains(&format!(
      "\"dtype_backends\":{{\"f32\":{verified_row},\"f16\":{verified_row},\"bf16\":{bf16_row}}}"
    )),
    "{json}"
  );
  assert_eq!(
    serde_json::to_string(&Support::Unsupported).unwrap(),
    "\"unsupported\""
  );
}

#[test]
fn unknown_dtype_name_is_rejected() {
  let json = serde_json::to_string(&lookup("BAAI/bge-small-en-v1.5").unwrap())
    .unwrap()
    .replace("\"default_dtype\":\"f32\"", "\"default_dtype\":\"u8\"");
  assert!(serde_json::from_str::<ModelDescriptor>(&json).is_err());
}

#[test]
fn dense_dirs_follow_the_sentence_transformers_layout() {
  for descriptor in all() {
    for dir in &descriptor.dense_dirs {
      let number = dir.strip_suffix("_Dense").unwrap_or("");
      assert!(
        !number.is_empty() && number.chars().all(|c| c.is_ascii_digit()),
        "{}: {dir}",
        descriptor.id
      );
    }
  }
}