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 std::sync::Mutex;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::time::Instant;

use tempfile::tempdir;

use super::ID;
use super::SHA;
use super::config;
use super::hub;
use super::server::Server;
use crate::hub::download::fetch;
use crate::registry::WeightsFormat;

#[test]
fn a_second_fetch_waits_for_the_first_and_downloads_nothing() {
  let (open, gate) = mpsc::channel::<()>();
  let gate = Mutex::new(gate);
  let weights = format!("GET /{ID}/resolve/{SHA}/model.safetensors");
  let held = weights.clone();
  let server = Server::start(move |method, path| {
    if format!("{method} {path}") == held {
      let _ = gate.lock().unwrap().recv();
    }
    hub(method, path)
  });
  let cache = tempdir().unwrap();
  let config = config(cache.path(), &server.url);
  let fetch = || fetch(&config, ID, "main", WeightsFormat::Safetensors).unwrap();
  thread::scope(|scope| {
    let first = scope.spawn(fetch);
    let deadline = Instant::now() + Duration::from_secs(20);
    while !server.requests().contains(&weights) {
      assert!(Instant::now() < deadline, "{:?}", server.requests());
      thread::sleep(Duration::from_millis(10));
    }
    let seen = server.requests().len();
    let second = scope.spawn(fetch);
    thread::sleep(Duration::from_millis(500));
    assert_eq!(server.requests().len(), seen, "the second fetch went ahead");
    drop(open);
    assert_eq!(first.join().unwrap(), second.join().unwrap());
  });
  let gets = server.requests().iter().filter(|r| **r == weights).count();
  assert_eq!(gets, 1, "{:?}", server.requests());
}