diskann_tools/utils/
gen_associated_data_from_range.rs1use std::io::Write;
7
8use diskann_providers::storage::StorageWriteProvider;
9use diskann_utils::io::Metadata;
10
11use super::{CMDResult, CMDToolError};
12
13pub fn gen_associated_data_from_range<S: StorageWriteProvider>(
14 storage_provider: &S,
15 associated_data_path: &str,
16 start: u32,
17 end: u32,
18) -> CMDResult<()> {
19 if end < start {
20 return Err(CMDToolError {
21 details: format!(
22 "invalid range: end ({end}) must be greater than or equal to start ({start})"
23 ),
24 });
25 }
26
27 let num_ints = (end - start).checked_add(1).ok_or_else(|| CMDToolError {
30 details: format!("range [{start}, {end}] is too large: count overflows u32"),
31 })?;
32
33 let mut file = storage_provider.create_for_write(associated_data_path)?;
34
35 let int_length: u32 = 1;
36
37 Metadata::new(num_ints, int_length)?.write(&mut file)?;
39
40 for i in start..=end {
42 file.write_all(&i.to_le_bytes())?;
43 }
44
45 Ok(())
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use byteorder::{LittleEndian, ReadBytesExt};
52 use diskann_providers::storage::{StorageReadProvider, VirtualStorageProvider};
53
54 #[test]
55 fn test_gen_associated_data_from_range() {
56 let storage_provider = VirtualStorageProvider::new_memory();
57 let path = "/test_gen_associated_data_from_range.bin";
58
59 gen_associated_data_from_range(&storage_provider, path, 0, 9).unwrap();
61
62 let mut file = storage_provider.open_reader(path).unwrap();
64
65 let num_ints = file.read_u32::<LittleEndian>().unwrap();
67 let int_length = file.read_u32::<LittleEndian>().unwrap();
68
69 assert_eq!(num_ints, 10);
70 assert_eq!(int_length, 1);
71
72 for expected in 0u32..=9 {
74 let actual = file.read_u32::<LittleEndian>().unwrap();
75 assert_eq!(actual, expected);
76 }
77 }
78
79 #[test]
80 fn test_gen_associated_data_from_range_single_value() {
81 let storage_provider = VirtualStorageProvider::new_memory();
82 let path = "/test_gen_associated_data_single.bin";
83
84 gen_associated_data_from_range(&storage_provider, path, 42, 42).unwrap();
86
87 let mut file = storage_provider.open_reader(path).unwrap();
88
89 let num_ints = file.read_u32::<LittleEndian>().unwrap();
90 let int_length = file.read_u32::<LittleEndian>().unwrap();
91
92 assert_eq!(num_ints, 1);
93 assert_eq!(int_length, 1);
94
95 let value = file.read_u32::<LittleEndian>().unwrap();
96 assert_eq!(value, 42);
97 }
98
99 #[test]
100 fn test_gen_associated_data_from_range_large() {
101 let storage_provider = VirtualStorageProvider::new_memory();
102 let path = "/test_gen_associated_data_large.bin";
103
104 gen_associated_data_from_range(&storage_provider, path, 100, 199).unwrap();
106
107 let mut file = storage_provider.open_reader(path).unwrap();
108
109 let num_ints = file.read_u32::<LittleEndian>().unwrap();
110 let int_length = file.read_u32::<LittleEndian>().unwrap();
111
112 assert_eq!(num_ints, 100);
113 assert_eq!(int_length, 1);
114
115 for expected in 100u32..=199 {
116 let actual = file.read_u32::<LittleEndian>().unwrap();
117 assert_eq!(actual, expected);
118 }
119 }
120
121 #[test]
122 fn test_gen_associated_data_from_range_end_less_than_start() {
123 let storage_provider = VirtualStorageProvider::new_memory();
124 let path = "/test.bin";
125
126 let result = gen_associated_data_from_range(&storage_provider, path, 10, 5);
127
128 let err = result.unwrap_err();
129 assert_eq!(
130 err.details,
131 "invalid range: end (5) must be greater than or equal to start (10)"
132 );
133 assert!(
134 !storage_provider.exists(path),
135 "File should not be created when range is invalid"
136 );
137 }
138
139 #[test]
140 fn test_gen_associated_data_from_range_max_overflow() {
141 let storage_provider = VirtualStorageProvider::new_memory();
142 let path = "/test.bin";
143
144 let result = gen_associated_data_from_range(&storage_provider, path, 0, u32::MAX);
145
146 let err = result.unwrap_err();
147 assert_eq!(
148 err.details,
149 format!("range [0, {}] is too large: count overflows u32", u32::MAX)
150 );
151 assert!(
152 !storage_provider.exists(path),
153 "File should not be created when range is too large"
154 );
155 }
156}