1use crate::helpers::extract_ext;
2use miette::Diagnostic;
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
8#[serde(rename_all = "lowercase")]
9pub enum Format {
10 #[doc(hidden)]
13 #[default]
14 None,
15
16 #[cfg(feature = "json")]
17 Json,
18
19 #[cfg(feature = "pkl")]
20 Pkl,
21
22 #[cfg(feature = "ron")]
23 Ron,
24
25 #[cfg(feature = "toml")]
26 Toml,
27
28 #[cfg(any(feature = "yaml", feature = "yml"))]
29 Yaml,
30}
31
32impl Format {
33 pub fn detect(value: &str) -> Result<Format, UnsupportedFormatError> {
36 let mut available: Vec<&str> = vec![];
37 let ext = extract_ext(value).unwrap_or_default();
38
39 #[cfg(feature = "json")]
40 {
41 available.push("JSON");
42
43 if ext == ".json" {
44 return Ok(Format::Json);
45 }
46 }
47
48 #[cfg(feature = "pkl")]
49 {
50 available.push("Pkl");
51
52 if ext == ".pkl" {
53 return Ok(Format::Pkl);
54 }
55 }
56
57 #[cfg(feature = "ron")]
58 {
59 available.push("RON");
60
61 if ext == ".ron" {
62 return Ok(Format::Ron);
63 }
64 }
65
66 #[cfg(feature = "toml")]
67 {
68 available.push("TOML");
69
70 if ext == ".toml" {
71 return Ok(Format::Toml);
72 }
73 }
74
75 #[cfg(any(feature = "yaml", feature = "yml"))]
76 {
77 available.push("YAML");
78
79 if ext == ".yaml" || ext == ".yml" {
80 return Ok(Format::Yaml);
81 }
82 }
83
84 Err(UnsupportedFormatError(
85 value.to_owned(),
86 available.join(", "),
87 ))
88 }
89
90 pub fn is_json(&self) -> bool {
91 #[cfg(feature = "json")]
92 {
93 matches!(self, Format::Json)
94 }
95 #[cfg(not(feature = "json"))]
96 {
97 false
98 }
99 }
100
101 pub fn is_pkl(&self) -> bool {
102 #[cfg(feature = "pkl")]
103 {
104 matches!(self, Format::Pkl)
105 }
106 #[cfg(not(feature = "pkl"))]
107 {
108 false
109 }
110 }
111
112 pub fn is_ron(&self) -> bool {
113 #[cfg(feature = "ron")]
114 {
115 matches!(self, Format::Ron)
116 }
117 #[cfg(not(feature = "ron"))]
118 {
119 false
120 }
121 }
122
123 pub fn is_toml(&self) -> bool {
124 #[cfg(feature = "toml")]
125 {
126 matches!(self, Format::Toml)
127 }
128 #[cfg(not(feature = "toml"))]
129 {
130 false
131 }
132 }
133
134 pub fn is_yaml(&self) -> bool {
135 #[cfg(any(feature = "yaml", feature = "yml"))]
136 {
137 matches!(self, Format::Yaml)
138 }
139 #[cfg(not(any(feature = "yaml", feature = "yml")))]
140 {
141 false
142 }
143 }
144}
145
146#[derive(Clone, Debug, Diagnostic, Error)]
147#[diagnostic(code(config::format::unsupported))]
148#[error("Unsupported format for {0}, expected {1}.")]
149pub struct UnsupportedFormatError(String, String);