Skip to main content

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}