1 // If no features are used, there is an "unused mut" warning in `ALL_EXTENSIONS` 2 // BUG: ? For some reason this doesn't do anything if I try and function scope this 3 #![allow(unused_mut)] 4 5 use lazy_static::lazy_static; 6 use std::collections::HashMap; 7 use std::error::Error; 8 9 use crate::map::Map; 10 use crate::{file::FileStoredFormat, value::Value, Format}; 11 12 #[cfg(feature = "toml")] 13 mod toml; 14 15 #[cfg(feature = "json")] 16 mod json; 17 18 #[cfg(feature = "yaml")] 19 mod yaml; 20 21 #[cfg(feature = "ini")] 22 mod ini; 23 24 #[cfg(feature = "ron")] 25 mod ron; 26 27 #[cfg(feature = "json5")] 28 mod json5; 29 30 /// File formats provided by the library. 31 /// 32 /// Although it is possible to define custom formats using [`Format`] trait it is recommended to use FileFormat if possible. 33 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] 34 pub enum FileFormat { 35 /// TOML (parsed with toml) 36 #[cfg(feature = "toml")] 37 Toml, 38 39 /// JSON (parsed with serde_json) 40 #[cfg(feature = "json")] 41 Json, 42 43 /// YAML (parsed with yaml_rust) 44 #[cfg(feature = "yaml")] 45 Yaml, 46 47 /// INI (parsed with rust_ini) 48 #[cfg(feature = "ini")] 49 Ini, 50 51 /// RON (parsed with ron) 52 #[cfg(feature = "ron")] 53 Ron, 54 55 /// JSON5 (parsed with json5) 56 #[cfg(feature = "json5")] 57 Json5, 58 } 59 60 lazy_static! { 61 #[doc(hidden)] 62 // #[allow(unused_mut)] ? 63 pub static ref ALL_EXTENSIONS: HashMap<FileFormat, Vec<&'static str>> = { 64 let mut formats: HashMap<FileFormat, Vec<_>> = HashMap::new(); 65 66 #[cfg(feature = "toml")] 67 formats.insert(FileFormat::Toml, vec!["toml"]); 68 69 #[cfg(feature = "json")] 70 formats.insert(FileFormat::Json, vec!["json"]); 71 72 #[cfg(feature = "yaml")] 73 formats.insert(FileFormat::Yaml, vec!["yaml", "yml"]); 74 75 #[cfg(feature = "ini")] 76 formats.insert(FileFormat::Ini, vec!["ini"]); 77 78 #[cfg(feature = "ron")] 79 formats.insert(FileFormat::Ron, vec!["ron"]); 80 81 #[cfg(feature = "json5")] 82 formats.insert(FileFormat::Json5, vec!["json5"]); 83 84 formats 85 }; 86 } 87 88 impl FileFormat { extensions(&self) -> &'static [&'static str]89 pub(crate) fn extensions(&self) -> &'static [&'static str] { 90 // It should not be possible for this to fail 91 // A FileFormat would need to be declared without being added to the 92 // ALL_EXTENSIONS map. 93 ALL_EXTENSIONS.get(self).unwrap() 94 } 95 parse( &self, uri: Option<&String>, text: &str, ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>>96 pub(crate) fn parse( 97 &self, 98 uri: Option<&String>, 99 text: &str, 100 ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> { 101 match self { 102 #[cfg(feature = "toml")] 103 FileFormat::Toml => toml::parse(uri, text), 104 105 #[cfg(feature = "json")] 106 FileFormat::Json => json::parse(uri, text), 107 108 #[cfg(feature = "yaml")] 109 FileFormat::Yaml => yaml::parse(uri, text), 110 111 #[cfg(feature = "ini")] 112 FileFormat::Ini => ini::parse(uri, text), 113 114 #[cfg(feature = "ron")] 115 FileFormat::Ron => ron::parse(uri, text), 116 117 #[cfg(feature = "json5")] 118 FileFormat::Json5 => json5::parse(uri, text), 119 120 #[cfg(all( 121 not(feature = "toml"), 122 not(feature = "json"), 123 not(feature = "yaml"), 124 not(feature = "ini"), 125 not(feature = "ron"), 126 not(feature = "json5"), 127 ))] 128 _ => unreachable!("No features are enabled, this library won't work without features"), 129 } 130 } 131 } 132 133 impl Format for FileFormat { parse( &self, uri: Option<&String>, text: &str, ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>>134 fn parse( 135 &self, 136 uri: Option<&String>, 137 text: &str, 138 ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> { 139 self.parse(uri, text) 140 } 141 } 142 143 impl FileStoredFormat for FileFormat { file_extensions(&self) -> &'static [&'static str]144 fn file_extensions(&self) -> &'static [&'static str] { 145 self.extensions() 146 } 147 } 148