1use std::{fmt, path::Path};
2
3use super::{File, FileResolver};
4use crate::Error;
5
6#[derive(Default)]
10pub struct ChainFileResolver {
11 resolvers: Vec<Box<dyn FileResolver>>,
12}
13
14impl ChainFileResolver {
15 pub fn new() -> Self {
17 Default::default()
18 }
19
20 pub fn add<F>(&mut self, resolver: F)
24 where
25 F: FileResolver + 'static,
26 {
27 self.resolvers.push(Box::new(resolver))
28 }
29}
30
31impl FileResolver for ChainFileResolver {
32 fn resolve_path(&self, path: &Path) -> Option<String> {
33 for resolver in &self.resolvers {
34 if let Some(name) = resolver.resolve_path(path) {
35 return Some(name);
36 }
37 }
38
39 None
40 }
41
42 fn open_file(&self, name: &str) -> Result<File, Error> {
43 for resolver in &self.resolvers {
44 match resolver.open_file(name) {
45 Ok(file) => return Ok(file),
46 Err(err) if err.is_file_not_found() => continue,
47 Err(err) => return Err(err),
48 }
49 }
50
51 Err(Error::file_not_found(name))
52 }
53}
54
55impl fmt::Debug for ChainFileResolver {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 f.debug_struct("ChainFileResolver").finish_non_exhaustive()
58 }
59}