1mod format;
2pub mod source;
3
4use error::*;
5use source::Source;
6use std::collections::HashMap;
7use std::path::{Path, PathBuf};
8use value::Value;
9
10pub use self::format::FileFormat;
11use self::source::FileSource;
12
13pub use self::source::file::FileSourceFile;
14pub use self::source::string::FileSourceString;
15
16#[derive(Clone, Debug)]
17pub struct File<T>
18where
19 T: FileSource,
20{
21 source: T,
22
23 format: Option<FileFormat>,
25
26 required: bool,
28}
29
30impl File<source::string::FileSourceString> {
31 pub fn from_str(s: &str, format: FileFormat) -> Self {
32 File {
33 format: Some(format),
34 required: true,
35 source: s.into(),
36 }
37 }
38}
39
40impl File<source::file::FileSourceFile> {
41 pub fn new(name: &str, format: FileFormat) -> Self {
42 File {
43 format: Some(format),
44 required: true,
45 source: source::file::FileSourceFile::new(name.into()),
46 }
47 }
48
49 pub fn with_name(name: &str) -> Self {
52 File {
53 format: None,
54 required: true,
55 source: source::file::FileSourceFile::new(name.into()),
56 }
57 }
58}
59
60impl<'a> From<&'a Path> for File<source::file::FileSourceFile> {
61 fn from(path: &'a Path) -> Self {
62 File {
63 format: None,
64 required: true,
65 source: source::file::FileSourceFile::new(path.to_path_buf()),
66 }
67 }
68}
69
70impl From<PathBuf> for File<source::file::FileSourceFile> {
71 fn from(path: PathBuf) -> Self {
72 File {
73 format: None,
74 required: true,
75 source: source::file::FileSourceFile::new(path),
76 }
77 }
78}
79
80impl<T: FileSource> File<T> {
81 pub fn format(mut self, format: FileFormat) -> Self {
82 self.format = Some(format);
83 self
84 }
85
86 pub fn required(mut self, required: bool) -> Self {
87 self.required = required;
88 self
89 }
90}
91
92impl<T: FileSource> Source for File<T>
93where
94 T: 'static,
95 T: Sync + Send,
96{
97 fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
98 Box::new((*self).clone())
99 }
100
101 fn collect(&self) -> Result<HashMap<String, Value>> {
102 let (uri, contents, format) = match self
104 .source
105 .resolve(self.format)
106 .map_err(|err| ConfigError::Foreign(err))
107 {
108 Ok((uri, contents, format)) => (uri, contents, format),
109
110 Err(error) => {
111 if !self.required {
112 return Ok(HashMap::new());
113 }
114
115 return Err(error);
116 }
117 };
118
119 format
121 .parse(uri.as_ref(), &contents)
122 .map_err(|cause| ConfigError::FileParse { uri, cause })
123 }
124}