Skip to main content

floe_core/io/storage/
planner.rs

1use std::path::Path;
2
3use crate::FloeResult;
4
5#[derive(Debug, Clone)]
6pub struct ObjectRef {
7    pub uri: String,
8    pub key: String,
9    pub last_modified: Option<String>,
10    pub size: Option<u64>,
11}
12
13pub fn join_prefix(prefix: &str, name: &str) -> String {
14    let left = prefix.trim_matches('/');
15    let right = name.trim_matches('/');
16    if left.is_empty() {
17        right.to_string()
18    } else if right.is_empty() {
19        left.to_string()
20    } else {
21        format!("{left}/{right}")
22    }
23}
24
25pub fn normalize_separators(value: &str) -> String {
26    value.replace('\\', "/").trim_matches('/').to_string()
27}
28
29pub fn stable_sort_refs(mut refs: Vec<ObjectRef>) -> Vec<ObjectRef> {
30    refs.sort_by(|a, b| a.uri.cmp(&b.uri));
31    refs
32}
33
34pub fn filter_by_suffixes(refs: Vec<ObjectRef>, suffixes: &[String]) -> Vec<ObjectRef> {
35    let suffixes = suffixes
36        .iter()
37        .map(|suffix| suffix.to_ascii_lowercase())
38        .collect::<Vec<_>>();
39    refs.into_iter()
40        .filter(|obj| {
41            let lower = obj.uri.to_ascii_lowercase();
42            !lower.ends_with('/') && suffixes.iter().any(|suffix| lower.ends_with(suffix))
43        })
44        .collect()
45}
46
47pub fn ensure_parent_dir(path: &Path) -> FloeResult<()> {
48    if let Some(parent) = path.parent() {
49        std::fs::create_dir_all(parent)?;
50    }
51    Ok(())
52}