1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
use ignore::DirEntry; use std::convert::TryFrom; use std::ffi::OsString; use std::io; use std::iter::Iterator; use std::ops::Deref; use std::path::{Path, PathBuf}; #[derive(Debug)] pub enum Error { Empty(String), Io(io::Error), } impl From<&str> for Error { fn from(s: &str) -> Self { Self::Empty(s.to_owned()) } } impl From<io::Error> for Error { fn from(err: io::Error) -> Self { Self::Io(err) } } #[derive(Clone, Debug)] pub struct Source { components: Vec<OsString>, target: PathBuf, } impl AsRef<Path> for Source { fn as_ref(&self) -> &Path { &self.target } } impl Deref for Source { type Target = PathBuf; fn deref(&self) -> &Self::Target { &self.target } } impl TryFrom<DirEntry> for Source { type Error = Error; fn try_from(entry: DirEntry) -> Result<Self, Self::Error> { let path = entry.path(); let target = path.canonicalize()?; if target.is_dir() { return Err(Error::from("entry is a directory")); } let components = path .components() .rev() .take(entry.depth()) .collect::<Vec<_>>(); if components.is_empty() { return Err(Error::from("no components in path to link target")); } let components = components .iter() .rev() .map(|c| c.as_os_str().to_owned()) .collect::<Vec<_>>(); Ok(Self { components, target }) } } impl Source { pub fn components_iter(&self) -> std::slice::Iter<'_, std::ffi::OsString> { self.components.iter() } }