1#![warn(missing_docs)]
36
37use std::{io, path::Path};
38
39pub use de::Deserializer;
40use serde::Deserialize;
41
42mod de;
43
44pub fn deserialize<'de, D, F, T>(deserializer: D, mut listener: F) -> Result<T, D::Error>
50where
51 D: serde::Deserializer<'de>,
52 F: FnMut(&Path, &io::Result<Vec<u8>>),
53 T: Deserialize<'de>,
54{
55 T::deserialize(Deserializer::new(deserializer, &mut listener))
56}
57
58#[cfg(test)]
59mod test {
60 use std::{fs, io, path::Path};
61
62 use serde::Deserialize;
63 use tempfile::NamedTempFile;
64
65 use super::*;
66
67 #[derive(Deserialize, PartialEq, Debug)]
68 struct Config {
69 sub: Subconfig,
70 }
71
72 #[derive(Deserialize, PartialEq, Debug)]
73 struct Subconfig {
74 file: Vec<String>,
75 inline: String,
76 }
77
78 #[test]
79 fn smoke() {
80 let file = NamedTempFile::new().unwrap();
81 fs::write(file.path(), "hunter2").unwrap();
82
83 let config = format!(
84 r#"
85{{
86 "sub": {{
87 "file": [
88 "${{file:{}}}"
89 ],
90 "inline": "${{foobar}}"
91 }}
92}}
93 "#,
94 file.path().display(),
95 );
96
97 let mut deserializer = serde_json::Deserializer::from_str(&config);
98 let mut files = vec![];
99 let mut cb = |path: &Path, r: &io::Result<Vec<u8>>| {
100 files.push((path.to_owned(), r.as_ref().ok().cloned()))
101 };
102 let deserializer = Deserializer::new(&mut deserializer, &mut cb);
103
104 let config = Config::deserialize(deserializer).unwrap();
105
106 let expected = Config {
107 sub: Subconfig {
108 file: vec!["hunter2".to_string()],
109 inline: "${foobar}".to_string(),
110 },
111 };
112
113 assert_eq!(config, expected);
114
115 let expected = vec![(file.path().to_owned(), Some("hunter2".as_bytes().to_vec()))];
116 assert_eq!(files, expected);
117 }
118
119 #[test]
120 fn io_error() {
121 let dir = tempfile::tempdir().unwrap();
122 let file = dir.path().join("bogus");
123
124 let config = format!("\"${{file:{}}}\"", file.display());
125
126 let mut deserializer = serde_json::Deserializer::from_str(&config);
127 let mut files = vec![];
128 let mut cb = |path: &Path, r: &io::Result<Vec<u8>>| {
129 files.push((path.to_owned(), r.as_ref().ok().cloned()))
130 };
131 let deserializer = Deserializer::new(&mut deserializer, &mut cb);
132
133 String::deserialize(deserializer).unwrap_err();
134
135 let expected = vec![(file.to_path_buf(), None)];
136 assert_eq!(files, expected);
137 }
138}