helpers/system_files.rs
1//! Deserialization of the `system` argument from a config file.
2//!
3//! Accepts either a single file path — the legacy form,
4//! `system = "foo.md"` — or a list of file paths,
5//! `system = ["foo.md", "bar.md"]`. Both deserialize into a
6//! `Vec<PathBuf>`; on the command line, `--system` is repeatable.
7
8use serde::de::{self, Deserializer, SeqAccess, Visitor};
9use std::fmt;
10use std::path::PathBuf;
11
12/// Deserialize a single file path or a list of file paths into a
13/// `Vec<PathBuf>`.
14///
15/// The single-path form exists for backwards compatibility with config files
16/// written before `--system` became repeatable.
17pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<PathBuf>, D::Error>
18where
19 D: Deserializer<'de>,
20{
21 /// Visitor for a single path or a list of paths.
22 struct SystemFiles;
23
24 impl<'de> Visitor<'de> for SystemFiles {
25 type Value = Vec<PathBuf>;
26
27 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 f.write_str("a file path or a list of file paths")
29 }
30
31 /// The legacy form: a single path, e.g. `system = "foo.md"`.
32 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
33 Ok(vec![PathBuf::from(v)])
34 }
35
36 /// The new form: a list of paths, e.g. `system = ["foo.md", "bar.md"]`.
37 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
38 let mut files = Vec::new();
39 while let Some(file) = seq.next_element()? {
40 files.push(file);
41 }
42 Ok(files)
43 }
44 }
45
46 deserializer.deserialize_any(SystemFiles)
47}