lance_encoding/
version.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4use std::str::FromStr;
5
6use lance_core::{Error, Result};
7use snafu::location;
8
9pub const LEGACY_FORMAT_VERSION: &str = "0.1";
10pub const V2_FORMAT_2_0: &str = "2.0";
11pub const V2_FORMAT_2_1: &str = "2.1";
12pub const V2_FORMAT_2_2: &str = "2.2";
13
14/// Lance file version
15#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, strum::EnumIter)]
16pub enum LanceFileVersion {
17    // Note that Stable must come AFTER the stable version and Next must come AFTER the next version
18    // this way comparisons like x >= V2_0 will work the same if x is Stable or V2_0
19    /// The legacy (0.1) format
20    Legacy,
21    #[default]
22    V2_0,
23    /// The latest stable release
24    Stable,
25    V2_1,
26    /// The latest unstable release
27    Next,
28    V2_2,
29}
30
31impl LanceFileVersion {
32    /// Convert Stable or Next to the actual version
33    pub fn resolve(&self) -> Self {
34        match self {
35            Self::Stable => Self::V2_0,
36            Self::Next => Self::V2_1,
37            _ => *self,
38        }
39    }
40
41    pub fn try_from_major_minor(major: u32, minor: u32) -> Result<Self> {
42        match (major, minor) {
43            (0, 0) => Ok(Self::Legacy),
44            (0, 1) => Ok(Self::Legacy),
45            (0, 2) => Ok(Self::Legacy),
46            (0, 3) => Ok(Self::V2_0),
47            (2, 0) => Ok(Self::V2_0),
48            (2, 1) => Ok(Self::V2_1),
49            (2, 2) => Ok(Self::V2_2),
50            _ => Err(Error::InvalidInput {
51                source: format!("Unknown Lance storage version: {}.{}", major, minor).into(),
52                location: location!(),
53            }),
54        }
55    }
56
57    pub fn to_numbers(&self) -> (u32, u32) {
58        match self {
59            Self::Legacy => (0, 2),
60            Self::V2_0 => (2, 0),
61            Self::V2_1 => (2, 1),
62            Self::V2_2 => (2, 2),
63            Self::Stable => self.resolve().to_numbers(),
64            Self::Next => self.resolve().to_numbers(),
65        }
66    }
67
68    pub fn iter_non_legacy() -> impl Iterator<Item = Self> {
69        use strum::IntoEnumIterator;
70
71        Self::iter().filter(|&v| v != Self::Stable && v != Self::Next && v != Self::Legacy)
72    }
73}
74
75impl std::fmt::Display for LanceFileVersion {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        write!(
78            f,
79            "{}",
80            match self {
81                Self::Legacy => LEGACY_FORMAT_VERSION,
82                Self::V2_0 => V2_FORMAT_2_0,
83                Self::V2_1 => V2_FORMAT_2_1,
84                Self::V2_2 => V2_FORMAT_2_2,
85                Self::Stable => "stable",
86                Self::Next => "next",
87            }
88        )
89    }
90}
91
92impl FromStr for LanceFileVersion {
93    type Err = Error;
94
95    fn from_str(value: &str) -> Result<Self> {
96        match value.to_lowercase().as_str() {
97            LEGACY_FORMAT_VERSION => Ok(Self::Legacy),
98            V2_FORMAT_2_0 => Ok(Self::V2_0),
99            V2_FORMAT_2_1 => Ok(Self::V2_1),
100            V2_FORMAT_2_2 => Ok(Self::V2_2),
101            "stable" => Ok(Self::Stable),
102            "legacy" => Ok(Self::Legacy),
103            "next" => Ok(Self::Next),
104            // Version 0.3 is an alias of 2.0
105            "0.3" => Ok(Self::V2_0),
106            _ => Err(Error::InvalidInput {
107                source: format!("Unknown Lance storage version: {}", value).into(),
108                location: location!(),
109            }),
110        }
111    }
112}