From d01a3841d967ffd272000f201d13495ec3963829 Mon Sep 17 00:00:00 2001 From: Breadway Date: Fri, 17 Jul 2026 08:16:25 +0800 Subject: [PATCH 1/3] breadmill/breadsearch: narrow embedder lock scope, recover from poisoned mutexes, atomic index save + corrupt rebuild, fix GUI busy-poll, bump theme pin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - indexer.rs: embedder mutex is now locked only around each chunk's embed_document() call instead of the whole file's chunk loop, so a slow MIGraphX JIT compile on one file no longer blocks every query for minutes - sync_ext.rs (new)/indexer.rs/main.rs/serve.rs: added MutexExt::lock_recover(), replacing every .lock().unwrap() so a panic on one thread (poisoning the mutex) logs a warning and recovers instead of cascading into every future lock().unwrap() call - store.rs: save_index now writes to a .tmp sibling and renames atomically into place; Store::open recovers from an index that fails to load by wiping it and the SQLite files/chunks tables so the next scan rebuilds from scratch, instead of refusing to start at all. Note: this recovery only catches corruption usearch's loader reports as Err — verified experimentally that sufficiently garbled input segfaults the process instead, which no Rust-side handling can catch; the atomic save is what actually prevents the realistic mid-crash corruption case from arising - breadsearch/src/main.rs: GUI query-result wait switched from glib::idle_add_local (re-invoked every main-loop tick, pegging a core for the whole wait) to a 15ms glib::timeout_add_local poll - breadsearch/Cargo.toml: bread-theme pin bumped v0.2.8 -> v0.2.10 to match the rest of the family --- Cargo.lock | 2 +- breadmill/src/indexer.rs | 45 +++++++++++++-------- breadmill/src/main.rs | 4 +- breadmill/src/serve.rs | 5 ++- breadmill/src/store.rs | 82 ++++++++++++++++++++++++++++++++++++--- breadmill/src/sync_ext.rs | 41 ++++++++++++++++++++ breadsearch/Cargo.toml | 2 +- breadsearch/src/main.rs | 13 +++++-- 8 files changed, 164 insertions(+), 30 deletions(-) create mode 100644 breadmill/src/sync_ext.rs diff --git a/Cargo.lock b/Cargo.lock index 768ecb2..a5395bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,7 +123,7 @@ dependencies = [ [[package]] name = "bread-theme" version = "0.2.3" -source = "git+https://github.com/Breadway/bread-ecosystem?tag=v0.2.8#5e58558dd36031433d4a8d8e70c71206c3f1f8f4" +source = "git+https://github.com/Breadway/bread-ecosystem?tag=v0.2.10#17d1bb85801b9a8c195b64c02d288cd662c9c780" dependencies = [ "dirs", "gtk4", diff --git a/breadmill/src/indexer.rs b/breadmill/src/indexer.rs index 3ad20b5..539b58c 100644 --- a/breadmill/src/indexer.rs +++ b/breadmill/src/indexer.rs @@ -10,7 +10,7 @@ use ignore::WalkBuilder; use notify::{RecommendedWatcher, RecursiveMode, Watcher, EventKind}; use sha2::{Digest, Sha256}; -use crate::{embed::OrtEmbedder, extract, chunk, power, store::Store}; +use crate::{embed::OrtEmbedder, extract, chunk, power, store::Store, sync_ext::MutexExt}; pub struct SharedState { pub store: Mutex, @@ -64,7 +64,7 @@ impl Indexer { pub fn full_reindex(&self) { eprintln!("breadmill: full reindex triggered"); { - let mut store = self.state.store.lock().unwrap(); + let mut store = self.state.store.lock_recover(); // Clear all state let _ = store.conn.execute_batch("DELETE FROM chunks; DELETE FROM files;"); let _ = store.index.reserve(4096); @@ -87,7 +87,7 @@ impl Indexer { // Snapshot existing indexed files let known: HashMap = { - let store = self.state.store.lock().unwrap(); + let store = self.state.store.lock_recover(); store.all_files() .unwrap_or_default() .into_iter() @@ -155,7 +155,7 @@ impl Indexer { .collect(); if !to_delete.is_empty() { - let mut store = self.state.store.lock().unwrap(); + let mut store = self.state.store.lock_recover(); for path in to_delete { eprintln!("breadmill: removing deleted file: {}", path); let _ = store.delete_file(&path); @@ -163,7 +163,7 @@ impl Indexer { } let count = { - let store = self.state.store.lock().unwrap(); + let store = self.state.store.lock_recover(); let n = store.chunk_count(); let _ = store.save_index(&self.state_dir); n @@ -238,7 +238,7 @@ impl Indexer { self.handle_fs_event(&path); } let count = { - let store = self.state.store.lock().unwrap(); + let store = self.state.store.lock_recover(); let n = store.chunk_count(); let _ = store.save_index(&self.state_dir); n @@ -261,7 +261,7 @@ impl Indexer { if !path.is_file() { let path_str = path.to_string_lossy().into_owned(); // File deleted — remove from index - let mut store = self.state.store.lock().unwrap(); + let mut store = self.state.store.lock_recover(); let _ = store.delete_file(&path_str); return; } @@ -309,7 +309,7 @@ impl Indexer { // Check if hash changed (catches content changes without mtime change) { - let store = self.state.store.lock().unwrap(); + let store = self.state.store.lock_recover(); if let Ok(files) = store.all_files() { if files.iter().any(|f| f.path == path_str && f.hash == hash) { return; @@ -322,20 +322,22 @@ impl Indexer { // for natural-language files. let chunks = chunk::chunk_text(&text, 400, 80, 2_000); eprintln!("breadmill: embedding {} ({} chars, {} chunks)", path_str, text.len(), chunks.len()); - let mut embedder_guard = self.state.embedder.lock().unwrap(); if !self.state.model_ready.load(Ordering::Relaxed) { eprintln!("breadmill: model not ready, skipping embed for {}", path_str); return; } - let embedder = match embedder_guard.as_mut() { - Some(e) => e, - None => return, - }; + // Confirm the embedder is actually present before committing to + // clearing this file's old chunks below — same check as before, + // just without holding the embedder lock past this one glance (see + // the per-chunk locking in the loop for why). + if self.state.embedder.lock_recover().is_none() { + return; + } { - let mut store = self.state.store.lock().unwrap(); + let mut store = self.state.store.lock_recover(); let _ = store.delete_file(path_str); // remove old chunks/vectors first } @@ -344,9 +346,18 @@ impl Indexer { for (i, chunk) in chunks.iter().enumerate() { eprintln!("breadmill: embed chunk {}/{} ({} chars) for {}", i + 1, chunks.len(), chunk.text.len(), path_str); - match embedder.embed_document(&chunk.text) { + // Lock the embedder only around this single chunk's embed call — + // this used to be held for the whole file's chunk loop, so one + // large file needing a fresh MIGraphX JIT compile (60-120s for a + // new sequence length) could block every query (serve.rs locks + // this same mutex) for the entire file, not just one chunk. + let embed_result = match self.state.embedder.lock_recover().as_mut() { + Some(embedder) => embedder.embed_document(&chunk.text), + None => break, // model was unloaded mid-scan; stop here + }; + match embed_result { Ok(embedding) => { - let mut store = self.state.store.lock().unwrap(); + let mut store = self.state.store.lock_recover(); // Ensure file row exists before inserting chunks (FK constraint) let _ = store.upsert_file(path_str, mtime, &hash); let _ = store.insert_chunk( @@ -367,7 +378,7 @@ impl Indexer { eprintln!("breadmill: no chunks embedded for {}", path_str); // Record the file so the mtime+hash check skips it on the next startup // rather than re-entering the same embed-fail loop. - let store = self.state.store.lock().unwrap(); + let store = self.state.store.lock_recover(); let _ = store.upsert_file(path_str, mtime, &hash); } else { // Increment live so `status` reflects progress before the full scan ends. diff --git a/breadmill/src/main.rs b/breadmill/src/main.rs index da5814d..08452e8 100644 --- a/breadmill/src/main.rs +++ b/breadmill/src/main.rs @@ -13,10 +13,12 @@ mod indexer; mod power; mod serve; mod store; +mod sync_ext; use embed::{Backend, OrtEmbedder}; use indexer::{Indexer, SharedState}; use store::Store; +use sync_ext::MutexExt; const MODEL_URL: &str = "https://huggingface.co/nomic-ai/nomic-embed-text-v1.5/resolve/main/onnx/model.onnx"; @@ -170,7 +172,7 @@ fn run_daemon( eprintln!("breadmill: loading model..."); match OrtEmbedder::load(&model_path, &tokenizer_path, dim, backend) { Ok(embedder) => { - *state_clone.embedder.lock().unwrap() = Some(embedder); + *state_clone.embedder.lock_recover() = Some(embedder); state_clone.model_ready.store(true, Ordering::Relaxed); eprintln!("breadmill: model loaded"); } diff --git a/breadmill/src/serve.rs b/breadmill/src/serve.rs index cd67e67..a147235 100644 --- a/breadmill/src/serve.rs +++ b/breadmill/src/serve.rs @@ -8,6 +8,7 @@ use std::{ use breadsearch_shared::{Request, Response, StatusInfo}; use crate::indexer::SharedState; +use crate::sync_ext::MutexExt; pub fn run(socket_path: &Path, state: Arc, snippet_len: usize, search_limit: usize) { let _ = std::fs::remove_file(socket_path); @@ -86,7 +87,7 @@ fn dispatch( } let embedding = { - let mut embedder = state.embedder.lock().unwrap(); + let mut embedder = state.embedder.lock_recover(); match embedder.as_mut() { Some(e) => match e.embed_query(&query) { Ok(v) => v, @@ -101,7 +102,7 @@ fn dispatch( }; let limit = limit.min(search_limit).max(1); - let store = state.store.lock().unwrap(); + let store = state.store.lock_recover(); match store.search(&embedding, limit, snippet_len) { Ok(hits) => Response::Hits { hits }, diff --git a/breadmill/src/store.rs b/breadmill/src/store.rs index 077736d..ed1392a 100644 --- a/breadmill/src/store.rs +++ b/breadmill/src/store.rs @@ -57,9 +57,32 @@ impl Store { let index = new_index(&options).map_err(|e| e.to_string())?; if idx_path.exists() { - index - .load(idx_path.to_str().unwrap()) - .map_err(|e| e.to_string())?; + // NOTE: this only catches corruption that usearch's loader + // itself detects and reports as an `Err` (e.g. a recognizable + // but wrong/incompatible header). Verified experimentally: a + // file that doesn't even look like a usearch index at all (pure + // garbage bytes) crashes the *process* with a SIGSEGV inside the + // native loader rather than returning an `Err` — no amount of + // Rust-side `Result`/`catch_unwind` handling can intercept that, + // it's a native-code robustness gap in the usearch library + // itself. This recovery path is still worth having (it's the + // difference between "won't start" and "rebuilds and starts" + // for the errors it *does* catch), but it is not a complete + // guarantee against every possible corrupt file. The atomic + // save below is the real fix for the common case this was + // written for (a crash mid-save) — it now can't produce a + // half-written `vectors.usearch` in the first place. + if let Err(e) = index.load(idx_path.to_str().unwrap()) { + eprintln!( + "breadmill: WARNING: {} failed to load ({}) — treating it as corrupt, \ + discarding it, and rebuilding the index from scratch on the next scan", + idx_path.display(), + e + ); + conn.execute_batch("DELETE FROM chunks; DELETE FROM files;") + .map_err(|e| e.to_string())?; + index.reserve(4096).map_err(|e| e.to_string())?; + } } else { index.reserve(4096).map_err(|e| e.to_string())?; } @@ -218,11 +241,18 @@ impl Store { // ---- persistence -------------------------------------------------------- + /// Saves to a `.tmp` sibling and renames it into place — a same- + /// filesystem rename is atomic, so a crash mid-save leaves only an + /// orphaned `.tmp` file rather than a truncated/corrupt + /// `vectors.usearch` that would otherwise fail to load on next start + /// (see the recovery path in `open`). pub fn save_index(&self, state_dir: &Path) -> Result<(), String> { let idx_path = state_dir.join("vectors.usearch"); + let tmp_path = state_dir.join("vectors.usearch.tmp"); self.index - .save(idx_path.to_str().unwrap()) - .map_err(|e| e.to_string()) + .save(tmp_path.to_str().unwrap()) + .map_err(|e| e.to_string())?; + std::fs::rename(&tmp_path, &idx_path).map_err(|e| e.to_string()) } } @@ -233,3 +263,45 @@ fn truncate_to_chars(s: &str, max_chars: usize) -> String { let truncated: String = s.chars().take(max_chars).collect(); format!("{}…", truncated.trim_end()) } + +#[cfg(test)] +mod tests { + use super::*; + + fn test_dir(name: &str) -> std::path::PathBuf { + let dir = std::env::temp_dir().join(format!("breadmill-store-test-{name}-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + dir + } + + #[test] + fn save_index_leaves_no_tmp_file_behind_and_is_loadable() { + let dir = test_dir("save-atomic"); + let store = Store::open(&dir, 4).unwrap(); + store.save_index(&dir).unwrap(); + + assert!(dir.join("vectors.usearch").exists()); + assert!( + !dir.join("vectors.usearch.tmp").exists(), + "the .tmp staging file should be renamed away, not left behind" + ); + + // A fresh `open` can load what was just saved without error. + Store::open(&dir, 4).unwrap(); + + std::fs::remove_dir_all(&dir).unwrap(); + } + + // No automated test for the corrupt-index recovery branch in `open`: + // the natural way to construct a "corrupt" fixture (writing arbitrary + // garbage to vectors.usearch) was tried and crashes the *test process* + // with a SIGSEGV inside usearch's native loader before our `Result` + // handling ever gets a chance to run — see the comment on that branch + // in `open`. A real usearch file with a deliberately-broken-but-still- + // parseable header could plausibly hit the `Err` path exercised there + // instead, but reverse-engineering that format precisely enough to + // build a safe fixture wasn't worth the risk of another flaky/crashing + // test. The atomic-save test above covers the actual mechanism that + // prevents this scenario from arising in the first place. +} diff --git a/breadmill/src/sync_ext.rs b/breadmill/src/sync_ext.rs new file mode 100644 index 0000000..a891cd7 --- /dev/null +++ b/breadmill/src/sync_ext.rs @@ -0,0 +1,41 @@ +//! Poison-tolerant `Mutex` locking. +//! +//! A panic on any thread while holding `SharedState::store` or +//! `SharedState::embedder` (e.g. an untrapped ONNX Runtime panic — only PDF +//! extraction is `catch_unwind`-guarded, see `extract.rs`) poisons the +//! `Mutex`. Every subsequent plain `.lock().unwrap()` — in the indexer *and* +//! in every query handler in `serve.rs` — would then immediately panic too, +//! silently bricking indexing and search until the daemon is restarted by +//! hand. +//! +//! `Mutex` poisoning exists to flag "the data guarded by this lock might be +//! in an inconsistent state," but every lock scope in this crate is a short, +//! single-step SQLite call or usearch operation — nothing here spans a +//! multi-step invariant across a single `lock()` call — so recovering the +//! guard and logging loudly is a reasonable trade here: continuing to serve +//! (and re-attempting the operation that panicked, on the next file/query) +//! beats a daemon that silently stops answering everything after one panic. + +use std::sync::{Mutex, MutexGuard}; + +pub trait MutexExt { + /// Like `.lock().unwrap()`, but recovers from a poisoned mutex instead + /// of panicking again — logs once per recovery so it's visible in the + /// daemon's own output, not just silently swallowed. + fn lock_recover(&self) -> MutexGuard<'_, T>; +} + +impl MutexExt for Mutex { + fn lock_recover(&self) -> MutexGuard<'_, T> { + match self.lock() { + Ok(guard) => guard, + Err(poisoned) => { + eprintln!( + "breadmill: WARNING: a mutex was poisoned by a panic on another thread; \ + recovering it and continuing instead of cascading the panic" + ); + poisoned.into_inner() + } + } + } +} diff --git a/breadsearch/Cargo.toml b/breadsearch/Cargo.toml index 5569deb..ca78b7a 100644 --- a/breadsearch/Cargo.toml +++ b/breadsearch/Cargo.toml @@ -10,7 +10,7 @@ path = "src/main.rs" [dependencies] breadsearch-shared = { path = "../breadsearch-shared" } -bread-theme = { git = "https://github.com/Breadway/bread-ecosystem", tag = "v0.2.8", features = ["gtk"] } +bread-theme = { git = "https://github.com/Breadway/bread-ecosystem", tag = "v0.2.10", features = ["gtk"] } gtk4 = { version = "0.11", features = ["v4_12"] } gtk4-layer-shell = "0.8" serde_json = "1" diff --git a/breadsearch/src/main.rs b/breadsearch/src/main.rs index 58f4b47..a9812fe 100644 --- a/breadsearch/src/main.rs +++ b/breadsearch/src/main.rs @@ -298,12 +298,19 @@ fn run_ui() { let _ = tx.send(breadsearch_shared::send_request(&req)); }); - // Poll via idle_add_local until the thread delivers its result. - // Unix socket round-trips are sub-millisecond so this fires once. + // Wait for the thread's result on a bounded timer rather than + // an `idle_add_local` — an idle source has no wait condition + // of its own, so GLib re-invokes it on every single main-loop + // iteration, i.e. a busy-spin pinning a full CPU core for as + // long as the daemon takes to answer (normally sub-ms, but + // the daemon's socket has no read timeout of its own, so a + // wedged/slow daemon previously meant an indefinite spin). + // 15ms is imperceptible added latency for a search box and + // caps this at a couple dozen checks per second instead. let rx = Rc::new(rx); let list_t = list_clone.clone(); - glib::idle_add_local(move || { + glib::timeout_add_local(std::time::Duration::from_millis(15), move || { match rx.try_recv() { Ok(result) => { populate_list(&list_t, result); From 099096972246a4ba072d120629d2791c1776a727 Mon Sep 17 00:00:00 2001 From: Breadway Date: Fri, 17 Jul 2026 09:41:58 +0800 Subject: [PATCH 2/3] Migrate embedding pipeline, EP session building, and model download to bread-onnx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit embed.rs's OrtEmbedder now delegates its tokenize -> tensor build -> mean-pool -> L2-normalize pipeline to bread_onnx::embedding::EmbeddingSession (near-byte-identical to breadarrd's own OrtEmbedder — same duplication, now shared, path dependency for now, see the TODO in breadmill/Cargo.toml), and its per-EP session builders (npu_session/rocm_session/cuda_session/ openvino_session) collapse into a single to_provider() mapping onto bread_onnx::Provider, which this crate's own breadmill/src/session.rs counterpart now handles generically. This crate's Backend enum, cargo feature gates (npu/rocm/cuda/openvino/full - unchanged, still control which onnxruntime EPs actually link/load), and NPU vaip_config.json discovery all stay local since they're genuinely breadsearch-specific. main.rs's Backend construction and CLI flag handling are untouched. This is also the reference implementation the MIGraphX-not-ROCm default in bread-onnx's provider module was promoted from (see this machine's own breadsearch-gpu-backends operator notes) — breadpad's ONNX migration, which had the actual silent-fallback bug, follows in a later commit. download_if_missing is replaced with bread_onnx::download::ensure_file (same sync/ureq approach, now shared with breadarrd's downloader). Builds clean with default features AND --features full (npu+rocm+cuda+ openvino all compiling together, matching how this crate already combined them). All existing tests pass across the whole workspace. --- Cargo.lock | 44 ++++++++ breadmill/Cargo.toml | 2 + breadmill/src/embed.rs | 245 +++++++---------------------------------- breadmill/src/main.rs | 28 +---- 4 files changed, 88 insertions(+), 231 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5395bb..9b54221 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +[[package]] +name = "anyhow" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + [[package]] name = "arbitrary" version = "1.4.2" @@ -120,6 +126,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bread-onnx" +version = "0.2.3" +dependencies = [ + "anyhow", + "bread-utils", + "hex", + "ort", + "sha2", + "tokenizers", + "tracing", + "ureq 2.12.1", +] + [[package]] name = "bread-theme" version = "0.2.3" @@ -131,10 +151,20 @@ dependencies = [ "serde_json", ] +[[package]] +name = "bread-utils" +version = "0.2.3" +dependencies = [ + "dirs", + "serde", + "serde_json", +] + [[package]] name = "breadmill" version = "0.2.4" dependencies = [ + "bread-onnx", "breadsearch-shared", "hex", "ignore", @@ -2966,9 +2996,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.36" @@ -3107,6 +3149,8 @@ dependencies = [ "once_cell", "rustls", "rustls-pki-types", + "serde", + "serde_json", "url", "webpki-roots 0.26.11", ] diff --git a/breadmill/Cargo.toml b/breadmill/Cargo.toml index 768735d..929fd8d 100644 --- a/breadmill/Cargo.toml +++ b/breadmill/Cargo.toml @@ -42,6 +42,8 @@ breadsearch-shared = { path = "../breadsearch-shared" } # needed for the plain CPU path even in the npu build. ort = { version = "2.0.0-rc.12", default-features = false, features = ["std", "tracing", "download-binaries", "tls-native", "copy-dylibs", "api-23"] } tokenizers = "0" +# TODO(owner): switch to tag-pinned git dependency once bread-onnx is merged and tagged, matching the bread-theme pattern +bread-onnx = { path = "../../bread-ecosystem-fix-worktree/bread-onnx" } # Surfaces ort's own EP-registration tracing (e.g. a GPU EP silently failing to # register and falling back to CPU) as visible log output instead of nowhere. diff --git a/breadmill/src/embed.rs b/breadmill/src/embed.rs index 3020e58..d507951 100644 --- a/breadmill/src/embed.rs +++ b/breadmill/src/embed.rs @@ -1,10 +1,7 @@ use std::path::{Path, PathBuf}; -use ort::{ - session::{Session, builder::{GraphOptimizationLevel, SessionBuilder}}, - value::Tensor, -}; -use tokenizers::Tokenizer; +use bread_onnx::embedding::EmbeddingSession; +use bread_onnx::Provider; const DOCUMENT_PREFIX: &str = "search_document: "; const QUERY_PREFIX: &str = "search_query: "; @@ -35,23 +32,15 @@ pub enum Backend { } pub struct OrtEmbedder { - session: Session, - tokenizer: Tokenizer, - dim: usize, + inner: EmbeddingSession, } impl OrtEmbedder { pub fn load(model_path: &Path, tokenizer_path: &Path, dim: usize, backend: Backend) -> Result { - let builder = Session::builder() - .map_err(|e| e.to_string())? - .with_optimization_level(GraphOptimizationLevel::All) + let provider = to_provider(backend)?; + let inner = EmbeddingSession::load(model_path, tokenizer_path, dim, MAX_SEQ_LEN, &[provider]) .map_err(|e| e.to_string())?; - - let mut builder = configure_eps(builder, &backend)?; - let session = builder.commit_from_file(model_path).map_err(|e| e.to_string())?; - let tokenizer = Tokenizer::from_file(tokenizer_path).map_err(|e| e.to_string())?; - - Ok(Self { session, tokenizer, dim }) + Ok(Self { inner }) } pub fn embed_document(&mut self, text: &str) -> Result, String> { @@ -64,229 +53,71 @@ impl OrtEmbedder { fn embed_with_prefix(&mut self, text: &str, prefix: &str) -> Result, String> { let input = format!("{}{}", prefix, text); - - let encoding = self - .tokenizer - .encode(input, true) - .map_err(|e| e.to_string())?; - - let mut ids: Vec = encoding.get_ids().iter().map(|&x| x as i64).collect(); - let mut mask: Vec = encoding - .get_attention_mask() - .iter() - .map(|&x| x as i64) - .collect(); - let mut type_ids: Vec = encoding - .get_type_ids() - .iter() - .map(|&x| x as i64) - .collect(); - - if ids.len() > MAX_SEQ_LEN { - eprintln!( - "breadmill: truncating {} tokens to {} (chunk too large)", - ids.len(), - MAX_SEQ_LEN - ); - ids.truncate(MAX_SEQ_LEN); - mask.truncate(MAX_SEQ_LEN); - type_ids.truncate(MAX_SEQ_LEN); - } - - let seq_len = ids.len() as i64; - - let id_tensor = - Tensor::::from_array((vec![1i64, seq_len], ids.clone())).map_err(|e| e.to_string())?; - let mask_tensor = - Tensor::::from_array((vec![1i64, seq_len], mask.clone())).map_err(|e| e.to_string())?; - let type_tensor = - Tensor::::from_array((vec![1i64, seq_len], type_ids)).map_err(|e| e.to_string())?; - - let outputs = self - .session - .run(ort::inputs! { - "input_ids" => id_tensor, - "attention_mask" => mask_tensor, - "token_type_ids" => type_tensor, - }) - .map_err(|e| e.to_string())?; - - // last_hidden_state: shape [1, seq_len, dim] - let (shape, data) = outputs["last_hidden_state"] - .try_extract_tensor::() - .map_err(|e| e.to_string())?; - - let actual_seq = shape[1] as usize; - let actual_dim = shape[2] as usize; - - // Mean-pool over non-padding positions. Some execution providers (e.g. - // MIGraphX) pad the output sequence dimension for kernel efficiency, so - // actual_seq can exceed mask.len() — only positions covered by our own - // attention mask are meaningful, so cap the loop at whichever is shorter. - let mut result = vec![0.0f32; actual_dim]; - let mut count = 0usize; - - for t in 0..actual_seq.min(mask.len()) { - if mask[t] > 0 { - for d in 0..actual_dim { - result[d] += data[t * actual_dim + d]; - } - count += 1; - } - } - - if count > 0 { - for x in &mut result { - *x /= count as f32; - } - } - - l2_normalize(&mut result); - - // Clamp/pad to configured dim - result.truncate(self.dim); - while result.len() < self.dim { - result.push(0.0); - } - - Ok(result) + self.inner.embed(&input).map_err(|e| e.to_string()) } } -fn l2_normalize(v: &mut Vec) { - let norm: f32 = v.iter().map(|x| x * x).sum::().sqrt(); - if norm > 1e-10 { - for x in v.iter_mut() { - *x /= norm; - } - } -} +// ---- Backend -> bread_onnx::Provider ---------------------------------------- +// +// `bread_onnx::session::build_session` (via `EmbeddingSession::load`) is the +// shared session-builder + EP-fallback + loud-logging code every EP branch +// below used to hand-roll separately (`configure_eps`/`npu_session`/ +// `rocm_session`/`cuda_session`/`openvino_session`). What's genuinely +// specific to this crate — its cargo feature gates (npu/rocm/cuda/openvino), +// and NPU's `vaip_config.json` discovery — stays here. -// ---- Execution provider selection ------------------------------------------- - -fn configure_eps(builder: SessionBuilder, backend: &Backend) -> Result { +fn to_provider(backend: Backend) -> Result { match backend { - Backend::Cpu => Ok(builder), - Backend::Npu { cache_dir } => npu_session(builder, cache_dir), - Backend::Rocm => rocm_session(builder), - Backend::Cuda => cuda_session(builder), - Backend::OpenVino { cache_dir } => openvino_session(builder, cache_dir), + Backend::Cpu => Ok(Provider::Cpu), + Backend::Npu { cache_dir } => npu_provider(cache_dir), + Backend::Rocm => rocm_provider(), + Backend::Cuda => cuda_provider(), + Backend::OpenVino { cache_dir } => Ok(Provider::OpenVino { device_type: "GPU".to_string(), cache_dir }), } } #[cfg(feature = "npu")] -fn npu_session(builder: SessionBuilder, cache_dir: &Path) -> Result { - let vitis_ep = build_vitis_ep(cache_dir)?; - eprintln!("breadmill: using NPU (VitisAI) execution provider"); +fn npu_provider(cache_dir: PathBuf) -> Result { + let vaip_config = find_vaip_config()?; if std::env::var("ORT_DYLIB_PATH").is_err() { eprintln!( "breadmill: hint — set ORT_DYLIB_PATH to the Ryzen AI SDK ORT, e.g.:\n \ ORT_DYLIB_PATH=~/.local/share/ryzen-ai-1.7.1/lib/libonnxruntime.so" ); } - builder - .with_execution_providers([vitis_ep, ort::ep::CPU::default().build()]) - .map_err(|e| e.to_string()) + Ok(Provider::Vitis { + config_file: vaip_config, + cache_dir: cache_dir.join("npu"), + cache_key: "nomic-embed-text-v1.5".to_string(), + }) } #[cfg(not(feature = "npu"))] -fn npu_session(builder: SessionBuilder, _cache_dir: &Path) -> Result { +fn npu_provider(_cache_dir: PathBuf) -> Result { eprintln!("breadmill: NPU backend requested but not compiled in (rebuild with --features npu); using CPU"); - Ok(builder) + Ok(Provider::Cpu) } -// ---- VitisAI EP (NPU) ------------------------------------------------------- - -#[cfg(feature = "npu")] -fn build_vitis_ep(cache_dir: &Path) -> Result { - let vaip_config = find_vaip_config()?; - let npu_cache = cache_dir.join("npu"); - std::fs::create_dir_all(&npu_cache).map_err(|e| e.to_string())?; - eprintln!("breadmill: vaip_config: {}", vaip_config.display()); - eprintln!("breadmill: NPU model cache: {}", npu_cache.display()); - Ok(ort::ep::Vitis::default() - .with_config_file(vaip_config.to_string_lossy()) - .with_cache_dir(npu_cache.to_string_lossy()) - .with_cache_key("nomic-embed-text-v1.5") - .build()) -} - -// ---- MIGraphX EP (AMD iGPU, ROCm-backed) ------------------------------------- - #[cfg(feature = "rocm")] -fn rocm_session(builder: SessionBuilder) -> Result { - eprintln!("breadmill: using MIGraphX execution provider (device 0)"); - eprintln!( - "breadmill: note — check the log line above/below for \"Successfully registered \ - `MIGraphXExecutionProvider`\"; if it's missing, the ONNX Runtime in use wasn't built \ - with MIGraphX support and inference silently fell back to CPU" - ); - builder - .with_execution_providers([ - ort::ep::MIGraphX::default().with_device_id(0).build(), - ort::ep::CPU::default().build(), - ]) - .map_err(|e| e.to_string()) +fn rocm_provider() -> Result { + Ok(Provider::MiGraphX { device_id: 0 }) } #[cfg(not(feature = "rocm"))] -fn rocm_session(builder: SessionBuilder) -> Result { +fn rocm_provider() -> Result { eprintln!("breadmill: ROCm backend requested but not compiled in (rebuild with --features rocm); using CPU"); - Ok(builder) + Ok(Provider::Cpu) } -// ---- CUDA EP (NVIDIA GPU) ---------------------------------------------------- - #[cfg(feature = "cuda")] -fn cuda_session(builder: SessionBuilder) -> Result { - eprintln!("breadmill: using CUDA execution provider (device 0)"); - eprintln!( - "breadmill: note — check the log line above/below for \"Successfully registered \ - `CUDAExecutionProvider`\"; if it's missing, the ONNX Runtime in use wasn't built \ - with CUDA support and inference silently fell back to CPU" - ); - builder - .with_execution_providers([ - ort::ep::CUDA::default().with_device_id(0).build(), - ort::ep::CPU::default().build(), - ]) - .map_err(|e| e.to_string()) +fn cuda_provider() -> Result { + Ok(Provider::Cuda { device_id: 0 }) } #[cfg(not(feature = "cuda"))] -fn cuda_session(builder: SessionBuilder) -> Result { +fn cuda_provider() -> Result { eprintln!("breadmill: CUDA backend requested but not compiled in (rebuild with --features cuda); using CPU"); - Ok(builder) -} - -// ---- OpenVINO EP (Intel iGPU/dGPU) ------------------------------------------- - -#[cfg(feature = "openvino")] -fn openvino_session(builder: SessionBuilder, cache_dir: &Path) -> Result { - let ov_cache = cache_dir.join("openvino"); - std::fs::create_dir_all(&ov_cache).map_err(|e| e.to_string())?; - eprintln!("breadmill: using OpenVINO execution provider (device_type GPU)"); - eprintln!("breadmill: OpenVINO model cache: {}", ov_cache.display()); - eprintln!( - "breadmill: note — check the log line above/below for \"Successfully registered \ - `OpenVINOExecutionProvider`\"; if it's missing, the ONNX Runtime in use wasn't built \ - with OpenVINO support and inference silently fell back to CPU" - ); - builder - .with_execution_providers([ - ort::ep::OpenVINO::default() - .with_device_type("GPU") - .with_cache_dir(ov_cache.to_string_lossy()) - .build(), - ort::ep::CPU::default().build(), - ]) - .map_err(|e| e.to_string()) -} - -#[cfg(not(feature = "openvino"))] -fn openvino_session(builder: SessionBuilder, _cache_dir: &Path) -> Result { - eprintln!("breadmill: OpenVINO backend requested but not compiled in (rebuild with --features openvino); using CPU"); - Ok(builder) + Ok(Provider::Cpu) } /// Locate the VitisAI EP config file required by the AMD Ryzen AI SDK. diff --git a/breadmill/src/main.rs b/breadmill/src/main.rs index 08452e8..0b79eef 100644 --- a/breadmill/src/main.rs +++ b/breadmill/src/main.rs @@ -1,5 +1,4 @@ use std::{ - io::Read, path::{Path, PathBuf}, sync::{Arc, atomic::Ordering}, }; @@ -226,29 +225,10 @@ fn download_if_missing(url: &str, dest: &Path) -> Result<(), String> { eprintln!(" already present: {}", dest.display()); return Ok(()); } - - eprintln!(" downloading {} ...", url); - let agent = ureq::AgentBuilder::new() - .timeout(std::time::Duration::from_secs(300)) - .build(); - - let response = agent.get(url).call().map_err(|e| e.to_string())?; - let mut bytes = Vec::new(); - response - .into_reader() - .read_to_end(&mut bytes) - .map_err(|e| e.to_string())?; - - if bytes.is_empty() { - return Err(format!("empty download from {}", url)); - } - - // Write atomically via temp file - let tmp = dest.with_extension("tmp"); - std::fs::write(&tmp, &bytes).map_err(|e| e.to_string())?; - std::fs::rename(&tmp, dest).map_err(|e| e.to_string())?; - - eprintln!(" saved {} ({:.1} MB)", dest.display(), bytes.len() as f64 / 1_048_576.0); + // Shared with breadarrd's own (previously reqwest/async, now also this + // same sync/ureq implementation) model downloader — see + // bread_onnx::download's doc comment. + bread_onnx::download::ensure_file(url, dest, None).map_err(|e| e.to_string())?; Ok(()) } From 99724853a0ef173a8f008b52a0c948dcc2a0d1f6 Mon Sep 17 00:00:00 2001 From: Breadway Date: Sun, 19 Jul 2026 03:53:04 +0800 Subject: [PATCH 3/3] Switch to tag-pinned bread-ecosystem deps; bump version to v0.3.0 --- Cargo.lock | 547 ++++++++++++++++++++-------------- breadmill/Cargo.toml | 5 +- breadsearch-shared/Cargo.toml | 2 +- breadsearch/Cargo.toml | 2 +- packaging/breadmill.service | 2 +- 5 files changed, 325 insertions(+), 233 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9b54221..49e20a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -104,9 +104,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" [[package]] name = "block-buffer" @@ -117,6 +117,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block-padding" version = "0.3.3" @@ -128,13 +137,14 @@ dependencies = [ [[package]] name = "bread-onnx" -version = "0.2.3" +version = "0.3.0" +source = "git+https://git.breadway.dev/Breadway/bread-ecosystem?tag=v0.3.0#8e82d2d833e992ce939a5b836f910ee109f2e939" dependencies = [ "anyhow", "bread-utils", "hex", "ort", - "sha2", + "sha2 0.10.9", "tokenizers", "tracing", "ureq 2.12.1", @@ -153,7 +163,8 @@ dependencies = [ [[package]] name = "bread-utils" -version = "0.2.3" +version = "0.3.0" +source = "git+https://git.breadway.dev/Breadway/bread-ecosystem?tag=v0.3.0#8e82d2d833e992ce939a5b836f910ee109f2e939" dependencies = [ "dirs", "serde", @@ -162,7 +173,7 @@ dependencies = [ [[package]] name = "breadmill" -version = "0.2.4" +version = "0.3.0" dependencies = [ "bread-onnx", "breadsearch-shared", @@ -175,7 +186,7 @@ dependencies = [ "rusqlite", "serde", "serde_json", - "sha2", + "sha2 0.11.0", "tokenizers", "tracing-subscriber", "ureq 2.12.1", @@ -185,7 +196,7 @@ dependencies = [ [[package]] name = "breadsearch" -version = "0.2.0" +version = "0.3.0" dependencies = [ "bread-theme", "breadsearch-shared", @@ -196,7 +207,7 @@ dependencies = [ [[package]] name = "breadsearch-shared" -version = "0.2.0" +version = "0.3.0" dependencies = [ "serde", "serde_json", @@ -205,12 +216,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530" dependencies = [ "memchr", - "serde", + "serde_core", ] [[package]] @@ -219,12 +230,6 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" -[[package]] -name = "bytecount" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" - [[package]] name = "byteorder" version = "1.5.0" @@ -233,9 +238,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "bzip2" @@ -262,7 +267,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cc8d9aa793480744cd9a0524fef1a2e197d9eaa0f739cde19d16aba530dcb95" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cairo-sys-rs", "glib", "libc", @@ -299,9 +304,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.65" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "c89588d05638b5b4594a3348a2d6c20277e43a7f5c5202b05cc56888475a47b8" dependencies = [ "find-msvc-tools", "jobserver", @@ -311,9 +316,9 @@ dependencies = [ [[package]] name = "cff-parser" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f5b6e9141c036f3ff4ce7b2f7e432b0f00dee416ddcd4f17741d189ddc2e9d" +checksum = "c5810ca1a2b5870df2aab1c03e11c40c361ba51d6e3e361e56310f1cb3b4e087" [[package]] name = "cfg-expr" @@ -331,30 +336,41 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "inout", ] [[package]] name = "clap" -version = "4.6.1" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "dd059f9da4f5c36b3787f65d38ccaab1cc315f07b01f89abc8359ee6a8205011" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b" dependencies = [ "anstyle", "clap_lex", @@ -395,9 +411,9 @@ dependencies = [ [[package]] name = "console" -version = "0.16.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" dependencies = [ "encode_unicode", "libc", @@ -405,6 +421,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "constant_time_eq" version = "0.3.1" @@ -436,6 +458,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -462,18 +493,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -481,18 +512,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crypto-common" @@ -505,10 +536,19 @@ dependencies = [ ] [[package]] -name = "cxx" -version = "1.0.194" +name = "crypto-common" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747d8437319e3a2f43d93b341c137927ca70c0f5dabeea7a005a73665e247c7e" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "cxx" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00424da159cc5adcb4eeea7e7b5cb1d96df41f5fa695ec596922181bdc36232a" dependencies = [ "cc", "cxx-build", @@ -521,9 +561,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.194" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f4697d190a142477b16aef7da8a99bfdc41e7e8b1687583c0d23a79c7afc1e" +checksum = "43e05269dbed4dab7072ae0f04ef31799ad189d52ce2ac12710c2997b754f86a" dependencies = [ "cc", "codespan-reporting", @@ -536,9 +576,9 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" -version = "1.0.194" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0956799fa8678d4c50eed028f2de1c0552ae183c76e976cf7ca8c4e36a7c328" +checksum = "e2f017b07e0da7f425642339faff0edc9f0de6459a18180183d086d1f3381e89" dependencies = [ "clap", "codespan-reporting", @@ -550,15 +590,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.194" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23384a836ab4f0ad98ace7e3955ad2de39de42378ab487dc28d3990392cb283a" +checksum = "293d267f43a5778bf3b89fff2a658f081166e7f152d9640e2ee3d917d065a5fc" [[package]] name = "cxxbridge-macro" -version = "1.0.194" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6acc6b5822b9526adfb4fc377b67128fdd60aac757cc4a741a6278603f763cf" +checksum = "72dd233dc128223fe85d2afa5c617c79743c0f47fb495b69234b5da680d4986a" dependencies = [ "indexmap", "proc-macro2", @@ -624,9 +664,9 @@ checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" [[package]] name = "der" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" dependencies = [ "pem-rfc7468", "zeroize", @@ -686,11 +726,22 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", +] + [[package]] name = "dirs" version = "5.0.1" @@ -888,24 +939,24 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" dependencies = [ "futures-core", "futures-task", @@ -914,15 +965,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" dependencies = [ "proc-macro2", "quote", @@ -931,15 +982,15 @@ dependencies = [ [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" dependencies = [ "futures-core", "futures-macro", @@ -975,9 +1026,9 @@ dependencies = [ [[package]] name = "gdk4" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd42fdbbf48612c6e8f47c65fb92d2e8f39c25aecd6af047e83897c1a22d2a4e" +checksum = "d81e2a6c6ecba2aab60633a98df1868b03fa0bfdce8105edc27c1bccf71f0e39" dependencies = [ "cairo-rs", "gdk-pixbuf", @@ -991,9 +1042,9 @@ dependencies = [ [[package]] name = "gdk4-sys" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d974ac4f15e67472c3a9728daf612590b4a5762a4b33f0edd298df0b80d043c" +checksum = "3d8f608d8d7d229975c4d0d026f5d3071598c4ddab3c5262b0a31840fec78d13" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1036,16 +1087,30 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] [[package]] -name = "gio" -version = "0.22.6" +name = "getrandom" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3848bcba3a35cc0a71df8ba8ecfd799d6bfb862342a53a4a915fb62213aa4e6" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "gio" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3e1f669909c326b9413bde5a742097b8c90a7d78f45326db13668984769ded" dependencies = [ "futures-channel", "futures-core", @@ -1060,9 +1125,9 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.22.0" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64729ba2772c080448f9f966dba8f4456beeb100d8c28a865ef8a0f2ef4987e1" +checksum = "353fdc7da7cd16da916104b1e0e4e7de380ec9c8aaa20d4d742d66310ab4b0d5" dependencies = [ "glib-sys", "gobject-sys", @@ -1093,11 +1158,11 @@ dependencies = [ [[package]] name = "glib" -version = "0.22.7" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c207e04e51605dcf7b2924c41591b3a10e1438eaac5bcf448fb91f325381104a" +checksum = "ddbcf514bd1881fc1b960e4e52b4e82873f4da3bceddbd58d42827b508888100" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "futures-channel", "futures-core", "futures-executor", @@ -1126,9 +1191,9 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.22.6" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7fbac234ed5bc2a28359b7bde8e1b9cdf1441cc2d7f068e4824672d7db9445" +checksum = "030967459f9f676851872c6304adea7825c6d462ec9b72554c733cf0c5952233" dependencies = [ "libc", "system-deps", @@ -1136,9 +1201,9 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +checksum = "e47d37d2ae4464254884b60ab7071be2b876a9c35b696bd018ddcc76847309cd" dependencies = [ "aho-corasick", "bstr", @@ -1160,32 +1225,30 @@ dependencies = [ [[package]] name = "graphene-rs" -version = "0.22.0" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d1b7881f96869f49808b6adfe906a93a57a34204952253444d68c3208d71f1" +checksum = "eb856b9c558971c3f13ab692358926da710b046932a4e087aedcc35b040d7dff" dependencies = [ "glib", "graphene-sys", - "libc", ] [[package]] name = "graphene-sys" -version = "0.22.0" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "517f062f3fd6b7fd3e57a3f038a74b3c23ca32f51199ff028aa704609943f79c" +checksum = "5c7ffdfde88f3570d3705e0d8a2433e036d387a1f2930bbf47eafcb5f569fd04" dependencies = [ "glib-sys", "libc", - "pkg-config", "system-deps", ] [[package]] name = "gsk4" -version = "0.11.1" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c912dfcbd28acace5fc99c40bb9f25e1dcb73efb1f2608327f66a99acdcb62" +checksum = "b867be1c5f14dcb8f552c0eff6e9a9b1da5f8b43943e8efc3a63c889d84952ff" dependencies = [ "cairo-rs", "gdk4", @@ -1198,9 +1261,9 @@ dependencies = [ [[package]] name = "gsk4-sys" -version = "0.11.1" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d54bbc7a9d8b6ffe4f0c95eede15ccfb365c8bf521275abe6bcfb57b18fb8a" +checksum = "5b7c7eb2e681ee896646cfb8872b431f24d09f53ba9283289d9b10caa6707088" dependencies = [ "cairo-sys-rs", "gdk4-sys", @@ -1214,9 +1277,9 @@ dependencies = [ [[package]] name = "gtk4" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7181b837f04cbe93f79441475f7a00560a92cba7a72e38cc1a68b6f8b78eaae2" +checksum = "98a0a0466484f64b07b5b8184d43fa46be78eb0b8e04ae4e179af31d770b76d9" dependencies = [ "cairo-rs", "field-offset", @@ -1239,7 +1302,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4069987ff4793699511a251028cc336b438e46565b463f111250148d574752a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "gdk4", "glib", "glib-sys", @@ -1263,9 +1326,9 @@ dependencies = [ [[package]] name = "gtk4-macros" -version = "0.11.0" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3581b242ba62fdff122ebb626ea641582ec326031622bd19d60f85029c804a87" +checksum = "5ac7179400a36a04de039c24206bb841c5596992b907b43b23ee8d5bdc40d00e" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1275,9 +1338,9 @@ dependencies = [ [[package]] name = "gtk4-sys" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ba8e695e2640455561274e65e45f0a151619e450746007667f4b23ceae4e1b" +checksum = "82b8f954786af0b1984425c4446b77f5ff6594346181316be3f850caab1c6f01" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1312,9 +1375,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5081f264ed7adee96ea4b4778b6bb9da0a7228b084587aa3bd3ff05da7c5a3b" +checksum = "32069d97bb81e38fa67eab65e3393bf804bb85969f2bc06bf13f64aef5aba248" dependencies = [ "hashbrown 0.17.1", ] @@ -1337,7 +1400,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -1362,6 +1425,15 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + [[package]] name = "icu_collections" version = "2.2.0" @@ -1473,9 +1545,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.26" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" +checksum = "7b009b6744c1445efd7244084e25e498636412effb6760b55067553baa925cc7" dependencies = [ "crossbeam-deque", "globset", @@ -1499,9 +1571,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.18.4" +version = "0.18.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +checksum = "9433806cd6b4ec1aba79c021c7e4c58fb4c3b9977c085062e611ac929998fb0c" dependencies = [ "console", "portable-atomic", @@ -1523,9 +1595,9 @@ dependencies = [ [[package]] name = "inotify-sys" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" dependencies = [ "libc", ] @@ -1557,19 +1629,19 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.102" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", @@ -1598,7 +1670,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", ] @@ -1626,9 +1698,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ "libc", ] @@ -1673,26 +1745,25 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lopdf" -version = "0.38.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7184fdea2bc3cd272a1acec4030c321a8f9875e877b3f92a53f2f6033fdc289" +checksum = "25aab26d99567469098e64a02f42679f8965c6401263eefa31d8f2dcc37a221c" dependencies = [ "aes", - "bitflags 2.13.0", + "bitflags 2.13.1", "cbc", "ecb", "encoding_rs", "flate2", - "getrandom 0.3.4", + "getrandom 0.4.3", "indexmap", "itoa", "log", "md-5", "nom 8.0.0", - "nom_locate", - "rand", + "rand 0.10.2", "rangemap", - "sha2", + "sha2 0.10.9", "stringprep", "thiserror 2.0.18", "ttf-parser", @@ -1753,9 +1824,9 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" dependencies = [ "autocfg", "rawpointer", @@ -1768,14 +1839,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memoffset" @@ -1887,24 +1958,13 @@ dependencies = [ "memchr", ] -[[package]] -name = "nom_locate" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b577e2d69827c4740cba2b52efaad1c4cc7c73042860b199710b3575c68438d" -dependencies = [ - "bytecount", - "memchr", - "nom 8.0.0", -] - [[package]] name = "notify" version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crossbeam-channel", "filetime", "fsevent-sys", @@ -1980,7 +2040,7 @@ version = "6.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc3cbf698f9438986c11a880c90a6d04b9de27575afd28bbf45b154b6c709e2" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "once_cell", "onig_sys", @@ -2002,7 +2062,7 @@ version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "foreign-types", "libc", @@ -2072,13 +2132,12 @@ dependencies = [ [[package]] name = "pango" -version = "0.22.6" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251bdc6e6487b811be0e406a21e301e07e45c0aa8fa39e00c0c8e12a91752438" +checksum = "5d800d8d0de2ad5d0fb046f5344dbaba14a003cf3dd27cc21d85893d35ea316c" dependencies = [ "gio", "glib", - "libc", "pango-sys", ] @@ -2106,15 +2165,15 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest", + "digest 0.10.7", "hmac", ] [[package]] name = "pdf-extract" -version = "0.10.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28ba1758a3d3f361459645780e09570b573fc3c82637449e9963174c813a98" +checksum = "417e8fdc940f1d5bc62c5f89864c3a2255f74f69aa353c98509213d67df61e73" dependencies = [ "adobe-cmap-parser", "cff-parser", @@ -2162,9 +2221,9 @@ checksum = "60f6ce597ecdcc9a098e7fddacb1065093a3d66446fa16c675e7e71d1b5c28e6" [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" [[package]] name = "portable-atomic-util" @@ -2211,7 +2270,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.12+spec-1.1.0", + "toml_edit 0.25.13+spec-1.1.0", ] [[package]] @@ -2225,9 +2284,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.40.1" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", "serde", @@ -2249,13 +2308,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "rand" -version = "0.9.4" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha", - "rand_core", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", ] [[package]] @@ -2265,7 +2341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.5", ] [[package]] @@ -2277,6 +2353,12 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rangemap" version = "1.7.1" @@ -2333,9 +2415,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.4" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -2345,9 +2427,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" dependencies = [ "aho-corasick", "memchr", @@ -2390,7 +2472,7 @@ version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11438310b19e3109b6446c33d1ed5e889428cf2e278407bc7896bc4aaea43323" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -2414,7 +2496,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys", @@ -2423,9 +2505,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.41" +version = "0.23.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" dependencies = [ "log", "once_cell", @@ -2438,9 +2520,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "zeroize", ] @@ -2458,9 +2540,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "ryu" @@ -2498,7 +2580,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation", "core-foundation-sys", "libc", @@ -2584,13 +2666,13 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", ] [[package]] @@ -2600,8 +2682,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -2621,9 +2714,9 @@ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "slab" @@ -2709,9 +2802,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.118" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" dependencies = [ "proc-macro2", "quote", @@ -2738,7 +2831,7 @@ dependencies = [ "cfg-expr", "heck", "pkg-config", - "toml 1.1.2+spec-1.1.0", + "toml 1.1.3+spec-1.1.0", "version-compare", ] @@ -2755,7 +2848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", @@ -2812,18 +2905,18 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ "cfg-if", ] [[package]] name = "time" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", "num-conv", @@ -2850,9 +2943,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" dependencies = [ "tinyvec_macros", ] @@ -2883,7 +2976,7 @@ dependencies = [ "monostate", "onig", "paste", - "rand", + "rand 0.9.5", "rayon", "rayon-cond", "regex", @@ -2911,9 +3004,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c" dependencies = [ "indexmap", "serde_core", @@ -2921,7 +3014,7 @@ dependencies = [ "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -2958,14 +3051,14 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.12+spec-1.1.0" +version = "0.25.13+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ "indexmap", "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -2974,7 +3067,7 @@ version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -2985,9 +3078,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tracing" @@ -3199,9 +3292,9 @@ dependencies = [ [[package]] name = "usearch" -version = "2.25.3" +version = "2.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c08f764417012cf6aea6d1380ef9ea8712c5795a938b726fc67b9bf7ea8824b" +checksum = "1cd7f672d20412962c457b11c858c6c5aecb949808a5345a95e1d671112bcf72" dependencies = [ "cxx", "cxx-build", @@ -3271,9 +3364,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -3284,9 +3377,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3294,9 +3387,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", @@ -3307,9 +3400,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] @@ -3326,9 +3419,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" dependencies = [ "rustls-pki-types", ] @@ -3339,14 +3432,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.8", + "webpki-roots 1.0.9", ] [[package]] name = "webpki-roots" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" dependencies = [ "rustls-pki-types", ] @@ -3553,9 +3646,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] @@ -3612,18 +3705,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" dependencies = [ "proc-macro2", "quote", @@ -3736,9 +3829,9 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zopfli" diff --git a/breadmill/Cargo.toml b/breadmill/Cargo.toml index 929fd8d..9faeae0 100644 --- a/breadmill/Cargo.toml +++ b/breadmill/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "breadmill" -version = "0.2.4" +version = "0.3.0" edition = "2021" license = "MIT" @@ -42,8 +42,7 @@ breadsearch-shared = { path = "../breadsearch-shared" } # needed for the plain CPU path even in the npu build. ort = { version = "2.0.0-rc.12", default-features = false, features = ["std", "tracing", "download-binaries", "tls-native", "copy-dylibs", "api-23"] } tokenizers = "0" -# TODO(owner): switch to tag-pinned git dependency once bread-onnx is merged and tagged, matching the bread-theme pattern -bread-onnx = { path = "../../bread-ecosystem-fix-worktree/bread-onnx" } +bread-onnx = { git = "https://git.breadway.dev/Breadway/bread-ecosystem", tag = "v0.3.0" } # Surfaces ort's own EP-registration tracing (e.g. a GPU EP silently failing to # register and falling back to CPU) as visible log output instead of nowhere. diff --git a/breadsearch-shared/Cargo.toml b/breadsearch-shared/Cargo.toml index c557db6..3ebc491 100644 --- a/breadsearch-shared/Cargo.toml +++ b/breadsearch-shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "breadsearch-shared" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "MIT" diff --git a/breadsearch/Cargo.toml b/breadsearch/Cargo.toml index ca78b7a..241457f 100644 --- a/breadsearch/Cargo.toml +++ b/breadsearch/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "breadsearch" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "MIT" diff --git a/packaging/breadmill.service b/packaging/breadmill.service index 69c928f..e6ade17 100644 --- a/packaging/breadmill.service +++ b/packaging/breadmill.service @@ -1,6 +1,6 @@ [Unit] Description=Breadmill semantic search indexer -Documentation=https://github.com/breadway/breadsearch +Documentation=https://git.breadway.dev/Breadway/breadsearch After=default.target [Service]