use std::fmt;
use automerge::ChangeHash;
use crate::{CompactionHash, DocumentId};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StorageKey(Vec<String>);
impl StorageKey {
pub fn storage_id_path() -> StorageKey {
StorageKey(vec!["storage-adapter-id".to_string()])
}
pub fn incremental_prefix(doc_id: &DocumentId) -> StorageKey {
StorageKey(vec![doc_id.to_string(), "incremental".to_string()])
}
pub fn incremental_path(doc_id: &DocumentId, change_hash: ChangeHash) -> StorageKey {
StorageKey(vec![
doc_id.to_string(),
"incremental".to_string(),
change_hash.to_string(),
])
}
pub fn snapshot_prefix(doc_id: &DocumentId) -> StorageKey {
StorageKey(vec![doc_id.to_string(), "snapshot".to_string()])
}
pub fn snapshot_path(doc_id: &DocumentId, compaction_hash: &CompactionHash) -> StorageKey {
StorageKey(vec![
doc_id.to_string(),
"snapshot".to_string(),
compaction_hash.to_string(),
])
}
pub fn from_parts<I: IntoIterator<Item = S>, S: AsRef<str>>(
parts: I,
) -> Result<Self, InvalidStorageKey> {
let mut components = Vec::new();
for part in parts {
if part.as_ref().is_empty() || part.as_ref().contains("/") {
return Err(InvalidStorageKey);
}
components.push(part.as_ref().to_string());
}
Ok(StorageKey(components))
}
pub fn is_prefix_of(&self, other: &StorageKey) -> bool {
if self.0.len() > other.0.len() {
return false;
}
self.0.iter().zip(other.0.iter()).all(|(a, b)| a == b)
}
pub fn onelevel_deeper(&self, prefix: &StorageKey) -> Option<StorageKey> {
if prefix.is_prefix_of(self) && self.0.len() > prefix.0.len() {
let components = self.0.iter().take(prefix.0.len() + 1).cloned();
Some(StorageKey(components.collect()))
} else {
None
}
}
pub fn with_suffix(&self, suffix: StorageKey) -> StorageKey {
let mut new_key = self.0.clone();
new_key.extend(suffix.0);
StorageKey(new_key)
}
pub fn with_component(&self, component: String) -> Result<StorageKey, InvalidStorageKey> {
if component.is_empty() || component.contains('/') {
Err(InvalidStorageKey)
} else {
let mut new_key = self.0.clone();
new_key.push(component);
Ok(StorageKey(new_key))
}
}
}
impl IntoIterator for StorageKey {
type Item = String;
type IntoIter = std::vec::IntoIter<String>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a StorageKey {
type Item = &'a String;
type IntoIter = std::slice::Iter<'a, String>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl fmt::Display for StorageKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.join("/"))
}
}
#[derive(Debug)]
pub struct InvalidStorageKey;
impl std::fmt::Display for InvalidStorageKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "InvalidStorageKey")
}
}
impl std::error::Error for InvalidStorageKey {}