Skip to main content

alien_bindings/providers/
utils.rs

1use object_store::path::Path;
2
3/// Join `base` and `location` into a new `Path` without introducing extra percent-encoding.
4///
5/// * If `base` is empty, returns `location.clone()`.
6/// * If `location` is empty, returns `base.clone()`.
7/// * Otherwise, concatenates them with a single `/` separator and constructs a `Path` from the raw string.
8///
9/// This is preferred over `base.child(location)` when `location` may already contain
10/// internal `/` segments, because `Path::child` treats the whole string as a single
11/// segment and therefore encodes embedded `/` characters as `%2F`.
12pub(crate) fn prefixed_path(base: &Path, location: &Path) -> Path {
13    if base.as_ref().is_empty() {
14        return location.clone();
15    }
16    if location.as_ref().is_empty() {
17        return base.clone();
18    }
19    let joined = format!("{}/{}", base.as_ref(), location.as_ref());
20    Path::from(joined)
21}
22
23/// Takes a `full_path` and attempts to make it relative to `base_dir`.
24///
25/// If `base_dir` is empty, `full_path` is returned as is.
26/// If `base_dir` is not a prefix of `full_path` (which implies a logic error
27/// if this function is used correctly), an `ObjectStoreError::Generic` is returned.
28pub(crate) fn relativize_path(
29    base_dir: &Path,
30    full_path: Path, // Takes ownership
31    store_name_for_error: &'static str,
32) -> object_store::Result<Path> {
33    if base_dir.as_ref().is_empty() {
34        return Ok(full_path);
35    }
36
37    // Path::prefix_match consumes `full_path` if it's not found in the `match` arms,
38    // so we clone it here if we need to use it in the error message later.
39    // However, it's better to avoid clone if possible.
40    // `prefix_match` takes `&self`, so `full_path` is not consumed by `prefix_match`.
41    // It is consumed when Path::from_iter is called, or when Ok(full_path) is returned if base_dir is empty.
42    match full_path.prefix_match(base_dir) {
43        Some(iter) => Ok(Path::from_iter(iter)),
44        None => Err(object_store::Error::Generic {
45            store: store_name_for_error,
46            source: format!(
47                "Internal logic error: expected base_dir '{}' to be a prefix of '{}', but it was not. Cannot relativize path.",
48                base_dir, full_path
49            ).into(),
50        }),
51    }
52}