1use std::{
2 ffi::OsStr,
3 fs::{self, Metadata},
4 io::ErrorKind,
5 path::Path,
6};
7
8use log::trace;
9
10use crate::QueryError;
11
12pub struct FileQuery<'a> {
14 pub(crate) filename: Option<&'a OsStr>,
16 pub(crate) metadata: Option<Metadata>,
18}
19
20pub struct FileQueryBuilder<'name> {
22 filename: Option<&'name OsStr>,
24 metadata: Option<Metadata>,
26}
27
28impl FileQuery<'_> {
29 pub fn builder() -> FileQueryBuilder<'static> {
30 FileQueryBuilder::new()
31 }
32}
33
34impl<'name> FileQuery<'name> {
35 pub fn for_filename(name: &'name OsStr) -> FileQuery<'name> {
36 FileQuery::builder().filename(name).build()
37 }
38
39 pub fn for_path(path: &'name Path) -> Result<FileQuery, QueryError> {
40 let mut fqb = Self::builder();
41
42 if let Some(name) = path.file_name() {
43 trace!("{}: using filename {:?}", path.display(), name);
44 fqb = fqb.filename(name);
45 }
46
47 trace!("{}: looking up metadata", path.display());
48 match fs::metadata(&path) {
49 Ok(meta) => fqb = fqb.metadata(meta),
50 Err(e) if e.kind() == ErrorKind::NotFound => {
51 trace!("{}: file not found", path.display());
52 }
53 Err(e) => return Err(e.into()),
54 };
55
56 Ok(fqb.build())
57 }
58}
59
60impl FileQueryBuilder<'static> {
61 pub fn new() -> FileQueryBuilder<'static> {
62 FileQueryBuilder {
63 filename: None,
64 metadata: None,
65 }
66 }
67}
68
69impl<'name> FileQueryBuilder<'name> {
70 pub fn build(self) -> FileQuery<'name> {
72 FileQuery {
73 filename: self.filename,
74 metadata: self.metadata,
75 }
76 }
77
78 pub fn filename<'new>(self, name: &'new OsStr) -> FileQueryBuilder<'new> {
80 FileQueryBuilder {
81 filename: Some(name),
82 ..self
83 }
84 }
85
86 pub fn metadata(self, meta: fs::Metadata) -> FileQueryBuilder<'name> {
88 FileQueryBuilder {
89 metadata: Some(meta),
90 ..self
91 }
92 }
93}