Skip to main content

lance_core/utils/
address.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4use std::ops::Range;
5
6/// A row address encodes a fragment ID (upper 32 bits) and row offset (lower 32 bits).
7///
8/// ```
9/// use lance_core::utils::address::RowAddress;
10///
11/// let addr = RowAddress::new_from_parts(5, 100);
12/// assert_eq!(addr.fragment_id(), 5);
13/// assert_eq!(addr.row_offset(), 100);
14///
15/// // Convert to/from u64
16/// let raw: u64 = addr.into();
17/// let addr2: RowAddress = raw.into();
18/// assert_eq!(addr, addr2);
19///
20/// // Display format
21/// assert_eq!(format!("{}", addr), "(5, 100)");
22/// ```
23#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct RowAddress(u64);
25
26impl RowAddress {
27    pub const FRAGMENT_SIZE: u64 = 1 << 32;
28    /// A fragment id that will never be used.
29    pub const TOMBSTONE_FRAG: u32 = 0xffffffff;
30    /// A row id that will never be used.
31    pub const TOMBSTONE_ROW: u64 = 0xffffffffffffffff;
32
33    pub fn new_from_u64(row_addr: u64) -> Self {
34        Self(row_addr)
35    }
36
37    pub fn new_from_parts(fragment_id: u32, row_offset: u32) -> Self {
38        Self(((fragment_id as u64) << 32) | row_offset as u64)
39    }
40
41    /// Returns the address for the first row of a fragment.
42    pub fn first_row(fragment_id: u32) -> Self {
43        Self::new_from_parts(fragment_id, 0)
44    }
45
46    /// Returns the range of u64 addresses for a given fragment.
47    ///
48    /// ```
49    /// use lance_core::utils::address::RowAddress;
50    ///
51    /// let range = RowAddress::address_range(2);
52    /// assert_eq!(range.start, 2 * RowAddress::FRAGMENT_SIZE);
53    /// assert_eq!(range.end, 3 * RowAddress::FRAGMENT_SIZE);
54    /// ```
55    pub fn address_range(fragment_id: u32) -> Range<u64> {
56        u64::from(Self::first_row(fragment_id))..u64::from(Self::first_row(fragment_id + 1))
57    }
58
59    pub fn fragment_id(&self) -> u32 {
60        (self.0 >> 32) as u32
61    }
62
63    pub fn row_offset(&self) -> u32 {
64        self.0 as u32
65    }
66}
67
68impl From<RowAddress> for u64 {
69    fn from(row_addr: RowAddress) -> Self {
70        row_addr.0
71    }
72}
73
74impl From<u64> for RowAddress {
75    fn from(row_addr: u64) -> Self {
76        Self(row_addr)
77    }
78}
79
80impl std::fmt::Debug for RowAddress {
81    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
82        write!(f, "{}", self) // use Display
83    }
84}
85
86impl std::fmt::Display for RowAddress {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        write!(f, "({}, {})", self.fragment_id(), self.row_offset())
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn test_row_address() {
98        // new_from_u64 (not in doctest)
99        let addr = RowAddress::new_from_u64(0x0000_0001_0000_0002);
100        assert_eq!(addr.fragment_id(), 1);
101        assert_eq!(addr.row_offset(), 2);
102
103        // address_range uses first_row internally (coverage)
104        let range = RowAddress::address_range(3);
105        assert_eq!(range.start, 3 * RowAddress::FRAGMENT_SIZE);
106
107        // From impls with different values than doctest
108        let addr2 = RowAddress::new_from_parts(7, 8);
109        let raw: u64 = addr2.into();
110        let addr3: RowAddress = raw.into();
111        assert_eq!(addr2, addr3);
112
113        // Debug format (doctest only tests Display)
114        assert_eq!(format!("{:?}", addr), "(1, 2)");
115    }
116}