diskann_disk/data_model/
graph_layout_version.rs1use std::{cmp::Ordering, fmt, io::Cursor};
7
8use byteorder::{LittleEndian, ReadBytesExt};
9use diskann::{ANNError, ANNResult};
10
11#[derive(Debug, PartialEq, Eq, Clone)]
13pub struct GraphLayoutVersion {
14 pub major: u32,
15 pub minor: u32,
16}
17
18impl GraphLayoutVersion {
19 pub const fn new(major: u32, minor: u32) -> Self {
20 Self { major, minor }
21 }
22
23 pub fn major_version(&self) -> u32 {
24 self.major
25 }
26
27 pub fn minor_version(&self) -> u32 {
28 self.minor
29 }
30
31 pub fn to_bytes(&self) -> Vec<u8> {
37 let mut buffer = Vec::with_capacity(8);
38 buffer.extend_from_slice(self.major.to_le_bytes().as_ref());
39 buffer.extend_from_slice(self.minor.to_le_bytes().as_ref());
40 buffer
41 }
42}
43
44impl PartialOrd for GraphLayoutVersion {
45 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
46 Some(self.cmp(other))
47 }
48}
49
50impl Ord for GraphLayoutVersion {
51 fn cmp(&self, other: &Self) -> Ordering {
52 match self.major.cmp(&other.major) {
53 Ordering::Equal => self.minor.cmp(&other.minor),
54 major_ordering => major_ordering,
55 }
56 }
57}
58
59impl fmt::Display for GraphLayoutVersion {
60 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61 write!(formatter, "{}.{}", self.major, self.minor)
62 }
63}
64
65impl<'a> TryFrom<&'a [u8]> for GraphLayoutVersion {
66 type Error = ANNError;
67 fn try_from(value: &'a [u8]) -> ANNResult<Self> {
71 if value.len() < std::mem::size_of::<GraphLayoutVersion>() {
72 Err(ANNError::log_parse_slice_error(
73 "&[u8]".to_string(),
74 "GraphLayoutVersion".to_string(),
75 "The given bytes are not long enough to create a valid graph layout version."
76 .to_string(),
77 ))
78 } else {
79 let mut cursor = Cursor::new(&value);
80 let major = cursor.read_u32::<LittleEndian>()?;
81 let minor = cursor.read_u32::<LittleEndian>()?;
82
83 Ok(Self::new(major, minor))
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use std::cmp::Ordering;
91
92 use super::GraphLayoutVersion;
93
94 #[test]
95 fn test_graph_layout_version_creation() {
96 let version = GraphLayoutVersion::new(1, 0);
97 assert_eq!(version.major_version(), 1);
98 assert_eq!(version.minor_version(), 0);
99 }
100
101 #[test]
102 fn test_graph_layout_version_comparison() {
103 let v1 = GraphLayoutVersion::new(1, 0);
104 let v2 = GraphLayoutVersion::new(1, 1);
105 let v3 = GraphLayoutVersion::new(2, 0);
106 let v4 = GraphLayoutVersion::new(2, 1);
107 let v5 = GraphLayoutVersion::new(2, 1);
108
109 assert_eq!(v1.partial_cmp(&v2), Some(Ordering::Less));
110 assert_eq!(v2.partial_cmp(&v3), Some(Ordering::Less));
111 assert_eq!(v3.partial_cmp(&v4), Some(Ordering::Less));
112 assert_eq!(v4.partial_cmp(&v5), Some(Ordering::Equal));
113 }
114
115 #[test]
116 fn test_graph_layout_version_ordering() {
117 let v1 = GraphLayoutVersion::new(1, 0);
118 let v2 = GraphLayoutVersion::new(1, 1);
119 let v3 = GraphLayoutVersion::new(2, 0);
120 let v4 = GraphLayoutVersion::new(2, 1);
121
122 assert_eq!(v1.cmp(&v2), Ordering::Less);
123 assert_eq!(v2.cmp(&v3), Ordering::Less);
124 assert_eq!(v3.cmp(&v4), Ordering::Less);
125 assert_eq!(v4.cmp(&v4), Ordering::Equal);
126 }
127
128 #[test]
129 fn test_graph_layout_version() {
130 let version_bytes = [0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00];
132 let version = GraphLayoutVersion::try_from(&version_bytes[..]).unwrap();
133 assert_eq!(version.major_version(), 1);
134 assert_eq!(version.minor_version(), 2);
135
136 let bytes = vec![3; std::mem::size_of::<GraphLayoutVersion>() - 1]; let result = GraphLayoutVersion::try_from(&bytes[..]);
138 assert!(result.is_err());
139 }
140}