spacetimedb_paths/
utils.rs1use std::borrow::BorrowMut;
2use std::path::{Path, PathBuf};
3
4pub(crate) trait PathBufExt: BorrowMut<PathBuf> + Sized {
5 fn joined<P: AsRef<Path>>(mut self, path: P) -> Self {
6 self.borrow_mut().push(path);
7 self
8 }
9 fn with_exe_ext(mut self) -> Self {
10 self.borrow_mut().set_extension(std::env::consts::EXE_EXTENSION);
11 self
12 }
13 fn joined_int<I: itoa::Integer>(self, path_seg: I) -> Self {
14 self.joined(itoa::Buffer::new().format(path_seg))
15 }
16}
17
18impl PathBufExt for PathBuf {}
19
20#[macro_export]
33macro_rules! path_type {
34 ($(#[doc = $doc:literal])* $(#[non_exhaustive($($non_exhaustive:tt)+)])? $name:ident) => {
35 $(#[doc = $doc])*
36 #[derive(Clone, Debug, $crate::__serde::Serialize, $crate::__serde::Deserialize)]
37 #[serde(transparent)]
38 #[cfg_attr(all($($($non_exhaustive)+)?), non_exhaustive)]
39 pub struct $name(pub std::path::PathBuf);
40
41 impl AsRef<std::path::Path> for $name {
42 #[inline]
43 fn as_ref(&self) -> &std::path::Path {
44 &self.0
45 }
46 }
47 impl AsRef<std::ffi::OsStr> for $name {
48 #[inline]
49 fn as_ref(&self) -> &std::ffi::OsStr {
50 self.0.as_ref()
51 }
52 }
53
54 impl From<std::ffi::OsString> for $name {
55 fn from(s: std::ffi::OsString) -> Self {
56 Self(s.into())
57 }
58 }
59
60 impl $crate::FromPathUnchecked for $name {
61 fn from_path_unchecked(path: impl Into<std::path::PathBuf>) -> Self {
62 Self(path.into())
63 }
64 }
65
66 impl $name {
67 #[inline]
68 pub fn display(&self) -> std::path::Display<'_> {
69 self.0.display()
70 }
71
72 #[inline]
73 pub fn metadata(&self) -> std::io::Result<std::fs::Metadata> {
74 self.0.metadata()
75 }
76 }
77 };
78 ($(#[$($attr:tt)+])* $name:ident: dir) => {
79 path_type!($(#[$($attr)+])* $name);
80 impl $name {
81 #[inline]
82 pub fn create(&self) -> std::io::Result<()> {
83 std::fs::create_dir_all(self)
84 }
85 #[inline]
86 pub fn read_dir(&self) -> std::io::Result<std::fs::ReadDir> {
87 self.0.read_dir()
88 }
89 #[inline]
90 pub fn is_dir(&self) -> bool {
91 self.0.is_dir()
92 }
93 }
94 };
95 ($(#[$($attr:tt)+])* $name:ident: file) => {
96 path_type!($(#[$($attr)+])* $name);
97 impl $name {
98 pub fn read(&self) -> std::io::Result<Vec<u8>> {
99 std::fs::read(self)
100 }
101
102 pub fn read_to_string(&self) -> std::io::Result<String> {
103 std::fs::read_to_string(self)
104 }
105
106 pub fn write(&self, contents: impl AsRef<[u8]>) -> std::io::Result<()> {
107 self.create_parent()?;
108 std::fs::write(self, contents)
109 }
110
111 #[inline]
113 pub fn open_file(&self, options: &std::fs::OpenOptions) -> std::io::Result<std::fs::File> {
114 self.create_parent()?;
115 options.open(self)
116 }
117
118 #[inline]
120 pub fn create_parent(&self) -> std::io::Result<()> {
121 if let Some(parent) = self.0.parent() {
122 if parent != std::path::Path::new("") {
123 std::fs::create_dir_all(parent)?;
124 }
125 }
126 Ok(())
127 }
128 }
129 };
130}
131pub(crate) use path_type;