1use crate::error::{Error, Result};
6use std::path::{Path, PathBuf};
7use url::Url;
8
9pub fn slice_up_to(s: &str, max_len: usize) -> &str {
12 if max_len >= s.len() {
13 return s;
14 }
15 let mut idx = max_len;
16 while !s.is_char_boundary(idx) {
17 idx -= 1;
18 }
19 &s[..idx]
20}
21
22fn unurl_path(p: impl AsRef<Path>) -> PathBuf {
29 p.as_ref()
30 .to_str()
31 .and_then(|s| Url::parse(s).ok())
32 .and_then(|u| {
33 if u.scheme() == "file" {
34 u.to_file_path().ok()
35 } else {
36 None
37 }
38 })
39 .unwrap_or_else(|| p.as_ref().to_owned())
40}
41
42pub fn ensure_url_path(p: impl AsRef<Path>) -> Result<Url> {
47 if let Some(u) = p.as_ref().to_str().and_then(|s| Url::parse(s).ok()) {
48 if u.scheme() == "file" {
49 Ok(u)
50 } else {
51 Err(Error::IllegalDatabasePath(p.as_ref().to_owned()))
52 }
53 } else {
54 let p = p.as_ref();
55 let u = Url::from_file_path(p).map_err(|_| Error::IllegalDatabasePath(p.to_owned()))?;
56 Ok(u)
57 }
58}
59
60pub fn normalize_path(p: impl AsRef<Path>) -> Result<PathBuf> {
65 let path = unurl_path(p);
66 if let Ok(canonical) = path.canonicalize() {
67 return Ok(canonical);
68 }
69 let file_name = path
79 .file_name()
80 .ok_or_else(|| Error::IllegalDatabasePath(path.clone()))?;
81
82 let parent = path
83 .parent()
84 .ok_or_else(|| Error::IllegalDatabasePath(path.clone()))?;
85
86 let mut canonical = parent.canonicalize()?;
87 canonical.push(file_name);
88 Ok(canonical)
89}
90
91#[cfg(test)]
92mod test {
93 use super::*;
94 #[test]
95 fn test_slice_up_to() {
96 assert_eq!(slice_up_to("abcde", 4), "abcd");
97 assert_eq!(slice_up_to("abcde", 5), "abcde");
98 assert_eq!(slice_up_to("abcde", 6), "abcde");
99 let s = "abcd😀";
100 assert_eq!(s.len(), 8);
101 assert_eq!(slice_up_to(s, 4), "abcd");
102 assert_eq!(slice_up_to(s, 5), "abcd");
103 assert_eq!(slice_up_to(s, 6), "abcd");
104 assert_eq!(slice_up_to(s, 7), "abcd");
105 assert_eq!(slice_up_to(s, 8), s);
106 }
107 #[test]
108 fn test_unurl_path() {
109 assert_eq!(
110 unurl_path("file:///foo%20bar/baz").to_string_lossy(),
111 "/foo bar/baz"
112 );
113 assert_eq!(unurl_path("/foo bar/baz").to_string_lossy(), "/foo bar/baz");
114 assert_eq!(unurl_path("../baz").to_string_lossy(), "../baz");
115 }
116
117 #[test]
118 fn test_ensure_url() {
119 assert_eq!(
120 ensure_url_path("file:///foo%20bar/baz").unwrap().as_str(),
121 "file:///foo%20bar/baz"
122 );
123
124 assert_eq!(
125 ensure_url_path("/foo bar/baz").unwrap().as_str(),
126 "file:///foo%20bar/baz"
127 );
128
129 assert!(ensure_url_path("bar").is_err());
130
131 assert!(ensure_url_path("http://www.not-a-file.com").is_err());
132 }
133}