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)]
29#[serde(into = "String", try_from = "String")]
30pub enum FileUrl {
31 Url(Url),
32 Path(Utf8PathBuf),
33}
34
35impl FileUrl {
36 pub fn try_from_url(s: &str) -> Result<Self> {
47 let url = Url::parse(s)?;
48 Ok(Self::Url(url))
49 }
50}
51
52impl Display for FileUrl {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 match self {
55 FileUrl::Url(url) => write!(f, "{url}"),
56 FileUrl::Path(path) => write!(f, "file://{path}"),
57 }
58 }
59}
60
61impl From<FileUrl> for String {
62 fn from(source: FileUrl) -> Self {
63 source.to_string()
64 }
65}
66
67impl FromStr for FileUrl {
68 type Err = Error;
69
70 fn from_str(s: &str) -> Result<Self> {
71 if let Some(path) = s.strip_prefix("file://") {
72 Ok(FileUrl::Path(Utf8PathBuf::from(path)))
73 } else {
74 FileUrl::try_from_url(s)
75 }
76 }
77}
78
79impl TryFrom<String> for FileUrl {
80 type Error = Error;
81
82 fn try_from(s: String) -> Result<Self> {
83 s.parse()
84 }
85}
86
87impl From<Url> for FileUrl {
88 fn from(url: Url) -> Self {
89 Self::Url(url)
90 }
91}
92
93impl From<Utf8PathBuf> for FileUrl {
94 fn from(path: Utf8PathBuf) -> Self {
95 Self::Path(path)
96 }
97}