mail_template/
base_dir.rs1use std::{
2 path::{Path, PathBuf},
3 ops::{Deref, DerefMut},
4 env, io
5};
6
7use serde::{
8 ser::{Serialize, Serializer},
9 de::{Deserialize, Deserializer}
10};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
13pub struct CwdBaseDir(PathBuf);
14
15impl CwdBaseDir {
16
17 pub fn new_unchanged(path: PathBuf) -> Self {
19 CwdBaseDir(path)
20 }
21
22 pub fn from_path<P>(path: P) -> Result<Self, io::Error>
36 where P: AsRef<Path> + Into<PathBuf>
37 {
38 let path =
39 if path.as_ref().is_absolute() {
40 path.into()
41 } else {
42 let mut cwd = env::current_dir()?;
43 cwd.push(path.as_ref());
44 cwd
45 };
46
47 Ok(CwdBaseDir(path))
48 }
49
50 pub fn to_base_path(&self) -> Result<&Path, io::Error> {
65 let cwd = env::current_dir()?;
66 self.strip_prefix(&cwd)
67 .or_else(|_err_does_not_has_that_prefix| {
68 Ok(&self)
69 })
70 }
71
72 pub fn into_inner_with_prefix(self) -> PathBuf {
74 let CwdBaseDir(path) = self;
75 path
76 }
77}
78
79impl Deref for CwdBaseDir {
80 type Target = PathBuf;
81
82 fn deref(&self) -> &Self::Target {
83 &self.0
84 }
85}
86
87impl DerefMut for CwdBaseDir {
88 fn deref_mut(&mut self) -> &mut Self::Target {
89 &mut self.0
90 }
91}
92
93impl AsRef<Path> for CwdBaseDir {
94 fn as_ref(&self) -> &Path {
95 &self.0
96 }
97}
98
99
100
101impl<'de> Deserialize<'de> for CwdBaseDir {
102 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
103 where D: Deserializer<'de>
104 {
105 use serde::de::Error;
106 let path_buf = PathBuf::deserialize(deserializer)?;
107 Self::from_path(path_buf)
108 .map_err(|err| D::Error::custom(err))
109 }
110}
111
112impl Serialize for CwdBaseDir {
113 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
114 where S: Serializer,
115 {
116 use serde::ser::Error;
117 let path = self.to_base_path()
118 .map_err(|err| S::Error::custom(err))?;
119
120 path.serialize(serializer)
121 }
122}
123
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn from_path_does_not_affect_absolute_paths() {
131 let path = Path::new("/the/dog");
132 let base_dir = CwdBaseDir::from_path(path).unwrap();
133 assert_eq!(&*base_dir, Path::new("/the/dog"))
134 }
135
136 #[test]
137 fn from_path_prefixes_with_cwd() {
138 let cwd = env::current_dir().unwrap();
139 let expected = cwd.join("./the/dog");
140
141 let base_dir = CwdBaseDir::from_path("./the/dog").unwrap();
142 assert_eq!(&*base_dir, &expected);
143 }
144
145 #[test]
146 fn to_base_path_removes_cwd_prefix() {
147 let cwd = env::current_dir().unwrap();
148 let dir = cwd.join("hy/there");
149 let base_dir = CwdBaseDir::new_unchanged(dir);
150 let path = base_dir.to_base_path().unwrap();
151 assert_eq!(path, Path::new("hy/there"));
152 }
153}