perf: round 21 — CalDAV/CardDAV row-mapper pre-size, dedup hash-bind & digest-key dedup, CardDAV etag/BDAY emit, NC trashbin content-type
Round 21 of the benchmark-gated perf sweep. Six behaviour-preserving, allocation-reducing changes, each with a BEFORE/AFTER counting-allocator section in examples/bench_round21_micro.rs and a byte/-value equivalence gate; all six pass their deterministic alloc gate (a non-winning AFTER exits 1 = rollback). - R1: pre-size the 16 CalDAV/CardDAV row-mapper Vecs (+1 HashMap) with Vec::with_capacity(rows.len()) — the ROUND20 §I1 file-side pattern extended to the calendar/contact repos it deferred. 7 → 1 allocs/op. - R2: settle_batch binds a borrowed Vec<&str> instead of cloning every chunk hash into a Vec<String> (sqlx encodes &[&str] as text[] identically; favorites_pg_repository.rs:271 precedent). 33 → 1 allocs/op, 39x wall. - R3: store_loose_chunks keys its intra-request dedup set on the raw [u8;32] BLAKE3 digest and moves the hex on a duplicate (the ROUND17 §D2 pattern applied to the delta-upload sibling). 401 → 209 allocs/op. - R4: CardDAV getetag emits borrowed pre-escaped " quotes via a shared write_quoted_etag helper (ROUND20 §C1 pattern, all 4 CardDAV etag sites). 3 → 0 allocs/op. - R5: BDAY stamped via the new fmt::compact_date stack renderer instead of chrono's strftime interpreter (chrono fallback out of the 4-digit-year range; byte-identical, unit-tested vs chrono). 2 → 0 allocs/op, 10.5x wall. - R6: NC trashbin folder content-type via Cow::Borrowed instead of .to_string() on the constant (ROUND16 §M1 pattern). 1 → 0 allocs/op. See benches/ROUND21.md for the full write-up and the deferred-items list (HeaderMap-clone hot handlers, Query→typed-struct, WebDAV dead-props HashSet, and others surfaced by the audit that want their own validated pass). Validated: cargo fmt, cargo clippy --features bench --all-targets -D warnings, cargo test --lib --features test_utils (529 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015gHVq5Wy2TzdWeSqtEmK6m
This commit is contained in:
@@ -241,6 +241,31 @@ pub fn compact_ical_utc(buf: &mut [u8; 16], secs: i64) -> Option<&str> {
|
||||
Some(std::str::from_utf8(&buf[..]).expect("ascii"))
|
||||
}
|
||||
|
||||
/// `chrono::NaiveDate::format("%Y-%m-%d")` for a calendar date: the vCard
|
||||
/// `BDAY` / ISO date form `2026-07-17` (10 bytes) written into `buf`.
|
||||
///
|
||||
/// The vCard emit path (`contact_to_vcard`) stamps `BDAY` per
|
||||
/// contact-with-birthday, and `write!(…, "{}", date.format("%Y-%m-%d"))` runs
|
||||
/// chrono's strftime interpreter and heap-allocates — the same interpreter cost
|
||||
/// [`compact_ical_utc`] removed for the `REV` stamp (benches/ROUND19.md §V2:
|
||||
/// 3→0 allocs). This is the date-only companion to that helper.
|
||||
///
|
||||
/// Takes the pre-split `year`/`month`/`day` (so `fmt` stays chrono-free off the
|
||||
/// test path); callers read them via `chrono::Datelike`. Returns `None` when
|
||||
/// `year` is outside the fixed-width 4-digit range — where chrono widens or
|
||||
/// sign-prefixes `%Y` — so callers keep the chrono path as fallback.
|
||||
pub fn compact_date(buf: &mut [u8; 10], year: i32, month: u32, day: u32) -> Option<&str> {
|
||||
if !(0..=9999).contains(&year) {
|
||||
return None;
|
||||
}
|
||||
push4(buf, 0, year as i64);
|
||||
buf[4] = b'-';
|
||||
push2(buf, 5, month);
|
||||
buf[7] = b'-';
|
||||
push2(buf, 8, day);
|
||||
Some(std::str::from_utf8(&buf[..]).expect("ascii"))
|
||||
}
|
||||
|
||||
/// Append the upper-cased form of `s` to `buf` without a temporary `String`.
|
||||
///
|
||||
/// Byte-identical to `buf.push_str(&s.to_uppercase())` — same
|
||||
@@ -349,14 +374,42 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_date_matches_chrono() {
|
||||
use chrono::{Datelike, NaiveDate};
|
||||
// Padding (day/month < 10), leap day, min/max in-range 4-digit year,
|
||||
// 3-digit year (chrono zero-pads %Y to 4).
|
||||
let cases = [
|
||||
(2026, 7, 17),
|
||||
(2000, 2, 29),
|
||||
(2005, 7, 1),
|
||||
(1970, 1, 1),
|
||||
(9999, 12, 31),
|
||||
(1, 1, 1),
|
||||
(876, 5, 9),
|
||||
];
|
||||
for (y, m, d) in cases {
|
||||
let date = NaiveDate::from_ymd_opt(y, m, d).unwrap();
|
||||
let mut buf = [0u8; 10];
|
||||
assert_eq!(
|
||||
compact_date(&mut buf, date.year(), date.month(), date.day()).expect("in range"),
|
||||
date.format("%Y-%m-%d").to_string(),
|
||||
"date={y}-{m}-{d}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn out_of_range_falls_back() {
|
||||
let mut b3 = [0u8; 25];
|
||||
let mut b2 = [0u8; 31];
|
||||
let mut bc = [0u8; 16];
|
||||
let mut bd = [0u8; 10];
|
||||
assert!(rfc3339_utc(&mut b3, -1).is_none());
|
||||
assert!(rfc2822_utc(&mut b2, -1).is_none());
|
||||
assert!(compact_ical_utc(&mut bc, -1).is_none());
|
||||
assert!(compact_date(&mut bd, -1, 1, 1).is_none());
|
||||
assert!(compact_date(&mut bd, 10000, 1, 1).is_none());
|
||||
assert!(rfc3339_utc(&mut b3, MAX_4DIGIT_YEAR_SECS + 1).is_none());
|
||||
assert!(compact_ical_utc(&mut bc, MAX_4DIGIT_YEAR_SECS + 1).is_none());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user