use std::{path::PathBuf, time::Duration};
use serde::{Deserialize, Serialize};
use crate::StateStoreError;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum LanceStateStoreLocation {
Memory,
Directory(PathBuf),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct LanceStateStoreConfig {
location: LanceStateStoreLocation,
operation_timeout_ms: u64,
}
impl LanceStateStoreConfig {
#[must_use]
pub fn memory() -> Self {
Self {
location: LanceStateStoreLocation::Memory,
operation_timeout_ms: 30_000,
}
}
#[must_use]
pub fn directory(path: impl Into<PathBuf>) -> Self {
Self {
location: LanceStateStoreLocation::Directory(path.into()),
operation_timeout_ms: 30_000,
}
}
pub fn with_operation_timeout(mut self, timeout: Duration) -> Result<Self, StateStoreError> {
self.operation_timeout_ms = u64::try_from(timeout.as_millis()).map_err(|_| {
StateStoreError::invalid_config("Lance state operation timeout exceeds milliseconds")
})?;
self.validate()?;
Ok(self)
}
#[must_use]
pub fn location(&self) -> &LanceStateStoreLocation {
&self.location
}
#[must_use]
pub fn operation_timeout(&self) -> Duration {
Duration::from_millis(self.operation_timeout_ms)
}
pub fn validate(&self) -> Result<(), StateStoreError> {
if self.operation_timeout_ms == 0
|| std::time::Instant::now()
.checked_add(self.operation_timeout())
.is_none()
{
return Err(StateStoreError::invalid_config(
"Lance state operation timeout must be positive and fit the clock range",
));
}
if let LanceStateStoreLocation::Directory(path) = &self.location {
let value = path.to_str().ok_or_else(|| {
StateStoreError::invalid_config("Lance state directory must be valid UTF-8")
})?;
if value.is_empty() || value.contains('\0') || value.contains("://") {
return Err(StateStoreError::invalid_config(
"Lance state directory must be a nonempty local filesystem path without NUL",
));
}
}
Ok(())
}
}