diff --git a/Cargo.lock b/Cargo.lock index 6e49b88..034a25b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,6 +59,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -196,6 +205,7 @@ dependencies = [ "objc2", "objc2-foundation", "objc2-natural-language", + "postcard", "regex", "reqwest", "serde", @@ -217,6 +227,15 @@ dependencies = [ "tokenizers", ] +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.17", +] + [[package]] name = "colored" version = "2.2.0" @@ -292,6 +311,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -441,6 +466,18 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encode_unicode" version = "1.0.0" @@ -693,12 +730,35 @@ dependencies = [ "tracing", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "hex" version = "0.4.3" @@ -1391,6 +1451,19 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -1597,6 +1670,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "1.1.3" @@ -1693,6 +1775,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -1809,6 +1897,15 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "spm_precompiled" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index ae9e283..4ee5a9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,8 @@ path = "src/lib.rs" [features] default = ["cache", "tokenizer", "colored-output"] -# Translation cache with sled DB -cache = ["dep:sled", "dep:sha2", "dep:hex"] +# Translation cache with sled DB + postcard binary serialization +cache = ["dep:sled", "dep:sha2", "dep:hex", "dep:postcard"] # Claude tokenizer for precise token counting tokenizer = ["dep:claude-tokenizer"] # Colored terminal output @@ -46,6 +46,7 @@ fastrand = "2" # Lightweight RNG for retry jitter sled = { version = "0.34", optional = true } sha2 = { version = "0.10", optional = true } hex = { version = "0.4", optional = true } +postcard = { version = "1", features = ["alloc"], optional = true } # Optional: Colored output colored = { version = "2", optional = true } diff --git a/src/cache.rs b/src/cache.rs index 4f56fa2..8825a28 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -176,7 +176,7 @@ mod cache_impl { /// Get cached translation if available and not expired pub fn get(&self, key: &str) -> Option { match self.db.get(key) { - Ok(Some(bytes)) => match serde_json::from_slice::(&bytes) { + Ok(Some(bytes)) => match postcard::from_bytes::(&bytes) { Ok(entry) => { let now = Utc::now().timestamp(); let ttl_secs = self.config.ttl_days as i64 * 24 * 60 * 60; @@ -190,6 +190,7 @@ mod cache_impl { } } Err(_) => { + let _ = self.db.remove(key); CACHE_MISSES.fetch_add(1, Ordering::Relaxed); None } @@ -203,7 +204,7 @@ mod cache_impl { /// Store translation in cache pub fn put(&self, key: &str, entry: &CacheEntry) { - if let Ok(bytes) = serde_json::to_vec(entry) { + if let Ok(bytes) = postcard::to_allocvec(entry) { let entry_size = bytes.len(); let _ = self.db.insert(key, bytes);