1use std::{fmt::Display, str::FromStr};
2
3use camino::Utf8PathBuf;
4use serde::{Deserialize, Serialize};
5use url::Url;
6
7use crate::{Error, Result};
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(into = "String", try_from = "String")]
11pub enum FileUrl {
12 Url(Url),
13 Path(Utf8PathBuf),
14}
15
16impl FileUrl {
17 pub fn try_from_url(s: &str) -> Result<Self> {
18 let url = Url::parse(s)?;
19 Ok(Self::Url(url))
20 }
21}
22
23impl Display for FileUrl {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 FileUrl::Url(url) => write!(f, "{url}"),
27 FileUrl::Path(path) => write!(f, "file://{path}"),
28 }
29 }
30}
31
32impl From<FileUrl> for String {
33 fn from(source: FileUrl) -> Self {
34 source.to_string()
35 }
36}
37
38impl FromStr for FileUrl {
39 type Err = Error;
40
41 fn from_str(s: &str) -> Result<Self> {
42 if let Some(path) = s.strip_prefix("file://") {
43 Ok(FileUrl::Path(Utf8PathBuf::from(path)))
44 } else {
45 FileUrl::try_from_url(s)
46 }
47 }
48}
49
50impl TryFrom<String> for FileUrl {
51 type Error = Error;
52
53 fn try_from(s: String) -> Result<Self> {
54 s.parse()
55 }
56}
57
58impl From<Url> for FileUrl {
59 fn from(url: Url) -> Self {
60 Self::Url(url)
61 }
62}
63
64impl From<Utf8PathBuf> for FileUrl {
65 fn from(path: Utf8PathBuf) -> Self {
66 Self::Path(path)
67 }
68}