use std::fs::File;
use std::io::{self, BufReader, BufWriter, Read, Seek, Write};
use std::path::Path;
const TVR_MAGIC: &[u8; 4] = b"TVR1";
const TVRQ_MAGIC: &[u8; 4] = b"TVRQ";
const TVBM_MAGIC: &[u8; 4] = b"TVBM";
const TVSB_MAGIC: &[u8; 4] = b"TVSB";
const VERSION: u8 = 1;
pub const MAX_DIM: usize = u16::MAX as usize;
pub const MAX_SIGN_BITMAP_DIM: usize = 1 << 24;
pub const MAX_VECTORS: usize = 64 * 1024 * 1024;
fn invalid<S: Into<String>>(msg: S) -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, msg.into())
}
fn try_alloc_zeroed(n: usize) -> io::Result<Vec<u8>> {
let mut buf: Vec<u8> = Vec::new();
buf.try_reserve_exact(n)
.map_err(|_| invalid("payload allocation too large"))?;
buf.resize(n, 0);
Ok(buf)
}
fn read_le_vec<R: Read, T, const W: usize>(
r: &mut R,
n: usize,
parse: impl Fn([u8; W]) -> T,
) -> io::Result<Vec<T>> {
let mut v: Vec<T> = Vec::new();
v.try_reserve_exact(n)
.map_err(|_| invalid("payload allocation too large"))?;
let mut buf = [0u8; W];
for _ in 0..n {
r.read_exact(&mut buf)?;
v.push(parse(buf));
}
Ok(v)
}
fn check_payload_matches_file<R: Seek>(
reader: &mut R,
file_len: u64,
payload_bytes: usize,
) -> io::Result<()> {
let pos = reader.stream_position()?;
let remaining = file_len.saturating_sub(pos);
if payload_bytes as u64 != remaining {
return Err(invalid(format!(
"declared payload ({payload_bytes} B) does not match remaining \
file size ({remaining} B): truncated, forged, or trailing bytes"
)));
}
Ok(())
}
fn check_dim(dim: usize) -> io::Result<()> {
if !(2..=MAX_DIM).contains(&dim) {
return Err(invalid(format!("dim {dim} out of range [2, {MAX_DIM}]")));
}
Ok(())
}
fn check_sign_bitmap_dim(dim: usize) -> io::Result<()> {
if !(64..=MAX_SIGN_BITMAP_DIM).contains(&dim) {
return Err(invalid(format!(
"TVSB dim {dim} out of range [64, {MAX_SIGN_BITMAP_DIM}]"
)));
}
if !dim.is_multiple_of(64) {
return Err(invalid(format!("TVSB dim {dim} is not a multiple of 64")));
}
Ok(())
}
fn check_n_vectors(n_vectors: usize) -> io::Result<()> {
if n_vectors > MAX_VECTORS {
return Err(invalid(format!(
"n_vectors {n_vectors} exceeds MAX_VECTORS={MAX_VECTORS}"
)));
}
Ok(())
}
fn check_payload_bytes(payload_bytes: usize) -> io::Result<()> {
const MAX_PAYLOAD: u64 = 128 * 1024 * 1024 * 1024;
if payload_bytes as u64 > MAX_PAYLOAD {
return Err(invalid(format!(
"payload {payload_bytes} B exceeds MAX_PAYLOAD={MAX_PAYLOAD}"
)));
}
Ok(())
}
pub(crate) fn write_rank(
path: impl AsRef<Path>,
dim: usize,
n_vectors: usize,
ranks: &[u16],
) -> io::Result<()> {
let payload_bytes = n_vectors
.checked_mul(dim)
.and_then(|x| x.checked_mul(2))
.ok_or_else(|| invalid("payload size overflows usize"))?;
check_payload_bytes(payload_bytes)?;
assert_eq!(ranks.len(), payload_bytes / 2);
let mut f = BufWriter::new(File::create(path)?);
f.write_all(TVR_MAGIC)?;
f.write_all(&[VERSION])?;
f.write_all(&(dim as u32).to_le_bytes())?;
f.write_all(&(n_vectors as u32).to_le_bytes())?;
for &r in ranks {
f.write_all(&r.to_le_bytes())?;
}
f.flush()?;
Ok(())
}
pub(crate) fn load_rank(path: impl AsRef<Path>) -> io::Result<(usize, usize, Vec<u16>)> {
let file = File::open(path)?;
let file_len = file.metadata()?.len();
let mut f = BufReader::new(file);
let mut magic = [0u8; 4];
f.read_exact(&mut magic)?;
if &magic != TVR_MAGIC {
return Err(invalid("not a TVR1 file: wrong magic"));
}
let mut ver = [0u8; 1];
f.read_exact(&mut ver)?;
if ver[0] != VERSION {
return Err(invalid(format!("unsupported TVR1 version: {}", ver[0])));
}
let mut dim_buf = [0u8; 4];
f.read_exact(&mut dim_buf)?;
let dim = u32::from_le_bytes(dim_buf) as usize;
check_dim(dim)?;
let mut n_buf = [0u8; 4];
f.read_exact(&mut n_buf)?;
let n_vectors = u32::from_le_bytes(n_buf) as usize;
check_n_vectors(n_vectors)?;
let payload_bytes = n_vectors
.checked_mul(dim)
.and_then(|x| x.checked_mul(2))
.ok_or_else(|| invalid("payload size overflows usize"))?;
check_payload_bytes(payload_bytes)?;
check_payload_matches_file(&mut f, file_len, payload_bytes)?;
let ranks = read_le_vec(&mut f, payload_bytes / 2, u16::from_le_bytes)?;
let mut seen = vec![0u32; dim];
for (row_idx, row) in ranks.chunks_exact(dim).enumerate() {
let stamp = row_idx as u32 + 1;
for &r in row {
let ri = r as usize;
if ri >= dim {
return Err(invalid(format!(
"TVR1 rank value {r} >= dim ({dim}); ranks must be a permutation of [0, dim)"
)));
}
if seen[ri] == stamp {
return Err(invalid(format!(
"TVR1 row {row_idx} is not a permutation of [0, dim): value {r} repeats"
)));
}
seen[ri] = stamp;
}
}
Ok((dim, n_vectors, ranks))
}
pub(crate) fn write_rankquant(
path: impl AsRef<Path>,
bits: u8,
dim: usize,
n_vectors: usize,
packed: &[u8],
) -> io::Result<()> {
let payload_bytes = n_vectors
.checked_mul(dim)
.and_then(|x| x.checked_mul(bits as usize))
.map(|x| x / 8)
.ok_or_else(|| invalid("payload size overflows usize"))?;
check_payload_bytes(payload_bytes)?;
assert_eq!(packed.len(), payload_bytes);
let mut f = BufWriter::new(File::create(path)?);
f.write_all(TVRQ_MAGIC)?;
f.write_all(&[VERSION])?;
f.write_all(&[bits])?;
f.write_all(&(dim as u32).to_le_bytes())?;
f.write_all(&(n_vectors as u32).to_le_bytes())?;
f.write_all(packed)?;
f.flush()?;
Ok(())
}
pub(crate) fn load_rankquant(path: impl AsRef<Path>) -> io::Result<(u8, usize, usize, Vec<u8>)> {
let file = File::open(path)?;
let file_len = file.metadata()?.len();
let mut f = BufReader::new(file);
let mut magic = [0u8; 4];
f.read_exact(&mut magic)?;
if &magic != TVRQ_MAGIC {
return Err(invalid("not a TVRQ file: wrong magic"));
}
let mut ver = [0u8; 1];
f.read_exact(&mut ver)?;
if ver[0] != VERSION {
return Err(invalid(format!("unsupported TVRQ version: {}", ver[0])));
}
let mut bits_buf = [0u8; 1];
f.read_exact(&mut bits_buf)?;
let bits = bits_buf[0];
if !matches!(bits, 1 | 2 | 4) {
return Err(invalid(format!(
"unsupported TVRQ bits: {bits} (expected 1, 2, or 4)"
)));
}
let mut dim_buf = [0u8; 4];
f.read_exact(&mut dim_buf)?;
let dim = u32::from_le_bytes(dim_buf) as usize;
check_dim(dim)?;
let n_buckets = 1usize << bits;
if !dim.is_multiple_of(n_buckets) {
return Err(invalid(format!(
"TVRQ dim {dim} is not a multiple of 2^bits = {n_buckets}; \
constant-composition invariant violated"
)));
}
let codes_per_byte = (8 / bits) as usize;
if !dim.is_multiple_of(codes_per_byte) {
return Err(invalid(format!(
"TVRQ dim {dim} is not a multiple of codes_per_byte = {codes_per_byte}"
)));
}
let mut n_buf = [0u8; 4];
f.read_exact(&mut n_buf)?;
let n_vectors = u32::from_le_bytes(n_buf) as usize;
check_n_vectors(n_vectors)?;
let payload_bytes = n_vectors
.checked_mul(dim)
.and_then(|x| x.checked_mul(bits as usize))
.map(|x| x / 8)
.ok_or_else(|| invalid("payload size overflows usize"))?;
check_payload_bytes(payload_bytes)?;
check_payload_matches_file(&mut f, file_len, payload_bytes)?;
let mut packed = try_alloc_zeroed(payload_bytes)?;
f.read_exact(&mut packed)?;
let bytes_per_row = dim / codes_per_byte;
let expected_per_bucket = dim / n_buckets;
let mask = (1u8 << bits) - 1;
let bits_u = bits as usize;
for (row_idx, row) in packed.chunks_exact(bytes_per_row).enumerate() {
let mut hist = [0usize; 16]; for &byte in row {
for slot in 0..codes_per_byte {
let shift = (codes_per_byte - 1 - slot) * bits_u;
hist[((byte >> shift) & mask) as usize] += 1;
}
}
for (bucket, &count) in hist[..n_buckets].iter().enumerate() {
if count != expected_per_bucket {
return Err(invalid(format!(
"TVRQ row {row_idx} violates constant composition: bucket {bucket} \
has {count} codes, expected {expected_per_bucket} (= dim / 2^bits)"
)));
}
}
}
Ok((bits, dim, n_vectors, packed))
}
pub(crate) fn write_bitmap(
path: impl AsRef<Path>,
dim: usize,
n_top: usize,
n_vectors: usize,
bitmaps: &[u64],
) -> io::Result<()> {
let qpv = dim / 64;
let payload_bytes = n_vectors
.checked_mul(qpv)
.and_then(|x| x.checked_mul(8))
.ok_or_else(|| invalid("payload size overflows usize"))?;
check_payload_bytes(payload_bytes)?;
assert_eq!(bitmaps.len(), payload_bytes / 8);
let mut f = BufWriter::new(File::create(path)?);
f.write_all(TVBM_MAGIC)?;
f.write_all(&[VERSION])?;
f.write_all(&(dim as u32).to_le_bytes())?;
f.write_all(&(n_top as u32).to_le_bytes())?;
f.write_all(&(n_vectors as u32).to_le_bytes())?;
for &w in bitmaps {
f.write_all(&w.to_le_bytes())?;
}
f.flush()?;
Ok(())
}
pub(crate) fn load_bitmap(path: impl AsRef<Path>) -> io::Result<(usize, usize, usize, Vec<u64>)> {
let file = File::open(path)?;
let file_len = file.metadata()?.len();
let mut f = BufReader::new(file);
let mut magic = [0u8; 4];
f.read_exact(&mut magic)?;
if &magic != TVBM_MAGIC {
return Err(invalid("not a TVBM file: wrong magic"));
}
let mut ver = [0u8; 1];
f.read_exact(&mut ver)?;
if ver[0] != VERSION {
return Err(invalid(format!("unsupported TVBM version: {}", ver[0])));
}
let mut dim_buf = [0u8; 4];
f.read_exact(&mut dim_buf)?;
let dim = u32::from_le_bytes(dim_buf) as usize;
check_dim(dim)?;
if !dim.is_multiple_of(64) {
return Err(invalid(format!("TVBM dim {dim} is not a multiple of 64")));
}
let mut top_buf = [0u8; 4];
f.read_exact(&mut top_buf)?;
let n_top = u32::from_le_bytes(top_buf) as usize;
if n_top == 0 || n_top >= dim {
return Err(invalid(format!(
"TVBM n_top {n_top} must satisfy 0 < n_top < dim ({dim})"
)));
}
let mut n_buf = [0u8; 4];
f.read_exact(&mut n_buf)?;
let n_vectors = u32::from_le_bytes(n_buf) as usize;
check_n_vectors(n_vectors)?;
let qpv = dim / 64;
let payload_bytes = n_vectors
.checked_mul(qpv)
.and_then(|x| x.checked_mul(8))
.ok_or_else(|| invalid("payload size overflows usize"))?;
check_payload_bytes(payload_bytes)?;
check_payload_matches_file(&mut f, file_len, payload_bytes)?;
let bitmaps = read_le_vec(&mut f, payload_bytes / 8, u64::from_le_bytes)?;
for (row_idx, row) in bitmaps.chunks_exact(qpv).enumerate() {
let pop: u32 = row.iter().map(|w| w.count_ones()).sum();
if pop as usize != n_top {
return Err(invalid(format!(
"TVBM row {row_idx} has {pop} bits set, expected n_top = {n_top}"
)));
}
}
Ok((dim, n_top, n_vectors, bitmaps))
}
pub(crate) fn write_sign_bitmap(
path: impl AsRef<Path>,
dim: usize,
n_vectors: usize,
bitmaps: &[u64],
) -> io::Result<()> {
let qpv = dim / 64;
let payload_bytes = n_vectors
.checked_mul(qpv)
.and_then(|x| x.checked_mul(8))
.ok_or_else(|| invalid("payload size overflows usize"))?;
check_payload_bytes(payload_bytes)?;
assert_eq!(bitmaps.len(), payload_bytes / 8);
let mut f = BufWriter::new(File::create(path)?);
f.write_all(TVSB_MAGIC)?;
f.write_all(&[VERSION])?;
f.write_all(&(dim as u32).to_le_bytes())?;
f.write_all(&(n_vectors as u32).to_le_bytes())?;
for &w in bitmaps {
f.write_all(&w.to_le_bytes())?;
}
f.flush()?;
Ok(())
}
pub(crate) fn load_sign_bitmap(path: impl AsRef<Path>) -> io::Result<(usize, usize, Vec<u64>)> {
let file = File::open(path)?;
let file_len = file.metadata()?.len();
let mut f = BufReader::new(file);
let mut magic = [0u8; 4];
f.read_exact(&mut magic)?;
if &magic != TVSB_MAGIC {
return Err(invalid("not a TVSB file: wrong magic"));
}
let mut ver = [0u8; 1];
f.read_exact(&mut ver)?;
if ver[0] != VERSION {
return Err(invalid(format!("unsupported TVSB version: {}", ver[0])));
}
let mut dim_buf = [0u8; 4];
f.read_exact(&mut dim_buf)?;
let dim = u32::from_le_bytes(dim_buf) as usize;
check_sign_bitmap_dim(dim)?;
let mut n_buf = [0u8; 4];
f.read_exact(&mut n_buf)?;
let n_vectors = u32::from_le_bytes(n_buf) as usize;
check_n_vectors(n_vectors)?;
let qpv = dim / 64;
let payload_bytes = n_vectors
.checked_mul(qpv)
.and_then(|x| x.checked_mul(8))
.ok_or_else(|| invalid("payload size overflows usize"))?;
check_payload_bytes(payload_bytes)?;
check_payload_matches_file(&mut f, file_len, payload_bytes)?;
let bitmaps = read_le_vec(&mut f, payload_bytes / 8, u64::from_le_bytes)?;
Ok((dim, n_vectors, bitmaps))
}
#[cfg(test)]
mod tests {
use super::{
load_rank, load_rankquant, write_bitmap, write_rank, write_rankquant, write_sign_bitmap,
};
use crate::Rank;
use std::io::Write;
use std::path::PathBuf;
fn forge(suffix: &str, bytes: &[u8]) -> PathBuf {
let mut p = std::env::temp_dir();
let nonce = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
p.push(format!(
"rank_io_test_{}_{}_{}",
std::process::id(),
nonce,
suffix
));
std::fs::File::create(&p).unwrap().write_all(bytes).unwrap();
p
}
#[test]
fn tvdeser004_load_rankquant_rejects_dim_not_multiple_of_2pow_bits() {
let mut v = Vec::new();
v.extend_from_slice(b"TVRQ");
v.push(1); v.push(2); v.extend_from_slice(&6u32.to_le_bytes()); v.extend_from_slice(&0u32.to_le_bytes()); let path = forge("tvrq_dim6_bits2.tvrq", &v);
let result = std::panic::catch_unwind(|| load_rankquant(&path));
std::fs::remove_file(&path).ok();
let result = result.expect("load_rankquant panicked on bits=2 dim=6");
assert!(
result.is_err(),
"load_rankquant accepted bits=2 dim=6 (dim % 4 != 0); expected Err"
);
}
#[test]
fn tvdeser004_load_rankquant_rejects_dim_smaller_than_buckets() {
let mut v = Vec::new();
v.extend_from_slice(b"TVRQ");
v.push(1);
v.push(4); v.extend_from_slice(&4u32.to_le_bytes()); v.extend_from_slice(&0u32.to_le_bytes());
let path = forge("tvrq_dim4_bits4.tvrq", &v);
let result = std::panic::catch_unwind(|| load_rankquant(&path));
std::fs::remove_file(&path).ok();
let result = result.expect("load_rankquant panicked on bits=4 dim=4");
assert!(
result.is_err(),
"load_rankquant accepted bits=4 dim=4 (dim % 16 != 0); expected Err"
);
}
#[test]
fn tvdeser004_load_rankquant_accepts_valid_dim() {
let mut v = Vec::new();
v.extend_from_slice(b"TVRQ");
v.push(1);
v.push(2);
v.extend_from_slice(&8u32.to_le_bytes()); v.extend_from_slice(&0u32.to_le_bytes());
let path = forge("tvrq_dim8_bits2.tvrq", &v);
let result = load_rankquant(&path);
std::fs::remove_file(&path).ok();
let (bits, dim, n, packed) = result.expect("valid TVRQ should load");
assert_eq!(bits, 2);
assert_eq!(dim, 8);
assert_eq!(n, 0);
assert!(packed.is_empty());
}
#[test]
fn tvdeser005_load_rank_rejects_rank_value_ge_dim() {
let ranks: [u16; 4] = [60000, 1, 2, 3];
let mut v = Vec::new();
v.extend_from_slice(b"TVR1");
v.push(1);
v.extend_from_slice(&4u32.to_le_bytes()); v.extend_from_slice(&1u32.to_le_bytes()); for &r in &ranks {
v.extend_from_slice(&r.to_le_bytes());
}
let path = forge("tvr_rank_ge_dim.tvr", &v);
let result = std::panic::catch_unwind(|| load_rank(&path));
std::fs::remove_file(&path).ok();
let result = result.expect("load_rank panicked on rank >= dim");
assert!(
result.is_err(),
"load_rank accepted ranks=[60000,1,2,3] with dim=4 (60000 >= dim); expected Err"
);
}
#[test]
fn tvdeser005_load_rank_accepts_valid_permutation() {
let ranks: [u16; 8] = [0, 1, 2, 3, 3, 2, 1, 0];
let mut v = Vec::new();
v.extend_from_slice(b"TVR1");
v.push(1);
v.extend_from_slice(&4u32.to_le_bytes());
v.extend_from_slice(&2u32.to_le_bytes());
for &r in &ranks {
v.extend_from_slice(&r.to_le_bytes());
}
let path = forge("tvr_valid_perm.tvr", &v);
let result = load_rank(&path);
std::fs::remove_file(&path).ok();
let (d, n, loaded) = result.expect("valid TVR1 should load");
assert_eq!(d, 4);
assert_eq!(n, 2);
assert_eq!(loaded, ranks.to_vec());
}
#[test]
fn writers_reject_oversized_payload_without_truncating() {
use std::io::ErrorKind;
let tmp_dir = std::env::temp_dir();
let nonce = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let path = |s: &str| {
tmp_dir.join(format!(
"rank_io_write_guard_{}_{}_{}.bin",
std::process::id(),
nonce,
s
))
};
let big_dim = u16::MAX as usize; let big_n = 64 * 1024 * 1024;
let pr = path("rank");
let e = write_rank(&pr, big_dim, big_n, &[]).unwrap_err();
assert_eq!(e.kind(), ErrorKind::InvalidData);
assert!(
!pr.exists(),
"write_rank created a file despite rejecting the payload"
);
let prq = path("rankquant");
let e = write_rankquant(&prq, 4, big_dim, big_n, &[]).unwrap_err();
assert_eq!(e.kind(), ErrorKind::InvalidData);
assert!(
!prq.exists(),
"write_rankquant created a file despite rejecting the payload"
);
let bm_dim = 32768;
let pbm = path("bitmap");
let e = write_bitmap(&pbm, bm_dim, 1, big_n, &[]).unwrap_err();
assert_eq!(e.kind(), ErrorKind::InvalidData);
assert!(
!pbm.exists(),
"write_bitmap created a file despite rejecting the payload"
);
let psb = path("sign_bitmap");
let e = write_sign_bitmap(&psb, bm_dim, big_n, &[]).unwrap_err();
assert_eq!(e.kind(), ErrorKind::InvalidData);
assert!(
!psb.exists(),
"write_sign_bitmap created a file despite rejecting the payload"
);
let keep = path("rank_existing");
{
let mut idx = Rank::new(8);
idx.add(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
idx.write(&keep).unwrap();
}
let before = std::fs::read(&keep).unwrap();
let e = write_rank(&keep, big_dim, big_n, &[]).unwrap_err();
assert_eq!(e.kind(), ErrorKind::InvalidData);
let after = std::fs::read(&keep).unwrap();
assert_eq!(
before, after,
"rejected oversized write altered an existing file"
);
let (_dim, n, _ranks) = load_rank(&keep).unwrap();
assert_eq!(
n, 1,
"existing index no longer loads after a rejected write"
);
for p in [pr, prq, pbm, psb, keep] {
let _ = std::fs::remove_file(p);
}
}
}