1use std::ffi::{OsStr, OsString};
95use std::fmt::Display;
96use std::fs::File;
97use std::ops::{Deref, DerefMut};
98use std::path::{Path, PathBuf};
99use std::str::FromStr;
100
101#[derive(Debug, thiserror::Error)]
102pub enum Error {
103 #[error("IO error at {0:?}: {1}")]
104 Io(PathBuf, #[source] std::io::Error),
105 #[error("Parse error at {0:?}: {1}")]
106 Parse(PathBuf, #[source] Box<dyn std::error::Error + Send + Sync>),
107}
108
109trait WrapIoError: Sized {
110 type Output;
111
112 fn wrap_io_error(self, get_path: impl FnOnce() -> PathBuf) -> Result<Self::Output>;
113
114 fn wrap_io_error_with(self, path: &Path) -> Result<Self::Output> {
115 self.wrap_io_error(|| path.to_path_buf())
116 }
117}
118
119impl<T> WrapIoError for std::io::Result<T> {
120 type Output = T;
121
122 fn wrap_io_error(self, get_path: impl FnOnce() -> PathBuf) -> Result<Self::Output> {
123 self.map_err(|e| Error::Io(get_path(), e))
124 }
125}
126
127pub type Result<T> = std::result::Result<T, Error>;
128
129pub trait DirStructure: DirStructureItem {}
135
136pub trait DirStructureItem: ReadFrom + WriteTo {
139 fn read(path: impl AsRef<Path>) -> Result<Self>
142 where
143 Self: Sized,
144 {
145 Self::read_from(path.as_ref())
146 }
147
148 fn write(&self, path: impl AsRef<Path>) -> Result<()> {
151 self.write_to(path.as_ref())
152 }
153}
154
155impl<T> DirStructureItem for T where T: ReadFrom + WriteTo {}
157
158pub trait ReadFrom {
161 fn read_from(path: &Path) -> Result<Self>
164 where
165 Self: Sized;
166}
167
168pub trait WriteTo {
177 fn write_to(&self, path: &Path) -> Result<()>;
179}
180
181pub trait FromRefForWriter<'a> {
192 type Inner: ?Sized;
194 type Wr: WriteTo + 'a;
196
197 fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr;
200}
201
202pub trait NewtypeToInner {
208 type Inner;
210
211 fn into_inner(self) -> Self::Inner;
213}
214
215pub struct DirChildren<T>
228where
229 T: DirStructureItem,
230{
231 pub self_path: PathBuf,
236 pub children: Vec<DirChild<T>>,
238}
239
240impl<T> DirChildren<T>
241where
242 T: DirStructureItem,
243{
244 pub fn new() -> Self {
246 Self {
247 self_path: PathBuf::new(),
248 children: Vec::new(),
249 }
250 }
251
252 pub fn with_children_from_iter(
254 self_path: impl Into<PathBuf>,
255 children: impl IntoIterator<Item = DirChild<T>>,
256 ) -> Self {
257 Self {
258 self_path: self_path.into(),
259 children: children.into_iter().collect(),
260 }
261 }
262
263 pub fn len(&self) -> usize {
265 self.children.len()
266 }
267
268 pub fn get(&self, index: usize) -> Option<&DirChild<T>> {
270 self.children.get(index)
271 }
272
273 pub fn get_name(&self, name: impl AsRef<OsStr>) -> Option<&DirChild<T>> {
275 self.children
276 .iter()
277 .find(|child| child.file_name == name.as_ref())
278 }
279
280 pub fn iter(&self) -> DirChildrenIter<'_, T> {
282 DirChildrenIter(self.children.iter())
283 }
284}
285
286impl<T> ReadFrom for DirChildren<T>
287where
288 T: DirStructureItem,
289{
290 fn read_from(path: &Path) -> Result<Self>
291 where
292 Self: Sized,
293 {
294 let mut children = Vec::new();
295 for child in path.read_dir().wrap_io_error_with(path)? {
296 let child = child.wrap_io_error_with(path)?;
297 let file_name = child.file_name();
298 let value = T::read_from(&child.path())?;
299 children.push(DirChild { file_name, value });
300 }
301
302 Ok(DirChildren {
303 self_path: path.to_path_buf(),
304 children,
305 })
306 }
307}
308
309impl<T> WriteTo for DirChildren<T>
310where
311 T: DirStructureItem,
312{
313 fn write_to(&self, path: &Path) -> Result<()> {
314 for child in &self.children {
315 let child_path = path.join(&child.file_name);
316 child.value.write_to(&child_path)?;
317 }
318
319 Ok(())
320 }
321}
322
323pub struct DirChild<T>
325where
326 T: DirStructureItem,
327{
328 file_name: OsString,
330 value: T,
332}
333
334impl<T> DirChild<T>
335where
336 T: DirStructureItem,
337{
338 pub fn new(file_name: impl Into<OsString>, value: T) -> Self {
340 Self {
341 file_name: file_name.into(),
342 value,
343 }
344 }
345
346 pub fn file_name(&self) -> &OsString {
348 &self.file_name
349 }
350
351 pub fn file_name_mut(&mut self) -> &mut OsString {
355 &mut self.file_name
356 }
357
358 pub fn value(&self) -> &T {
362 &self.value
363 }
364
365 pub fn value_mut(&mut self) -> &mut T {
371 &mut self.value
372 }
373}
374
375impl<T> IntoIterator for DirChildren<T>
376where
377 T: DirStructureItem,
378{
379 type Item = DirChild<T>;
380 type IntoIter = std::vec::IntoIter<Self::Item>;
381
382 fn into_iter(self) -> Self::IntoIter {
383 self.children.into_iter()
384 }
385}
386
387pub struct DirChildrenIter<'a, T: DirStructureItem>(std::slice::Iter<'a, DirChild<T>>);
390
391impl<'a, T> Iterator for DirChildrenIter<'a, T>
392where
393 T: DirStructureItem,
394{
395 type Item = &'a DirChild<T>;
396
397 fn next(&mut self) -> Option<Self::Item> {
398 self.0.next()
399 }
400
401 fn size_hint(&self) -> (usize, Option<usize>) {
402 self.0.size_hint()
403 }
404}
405
406impl<'a, T> ExactSizeIterator for DirChildrenIter<'a, T>
407where
408 T: DirStructureItem,
409{
410 fn len(&self) -> usize {
411 self.0.len()
412 }
413}
414
415#[macro_export]
418macro_rules! dir_children_wrapper {
419 ($vis:vis $name:ident $ty:ty) => {
420 $vis struct $name(pub $crate::DirChildren<$ty>);
421
422 impl $crate::ReadFrom for $name {
423 fn read_from(path: &::std::path::Path) -> $crate::Result<Self>
424 where
425 Self: Sized,
426 {
427 Ok(Self(<$crate::DirChildren<$ty>>::read_from(path)?))
428 }
429 }
430
431 impl $crate::WriteTo for $name {
432 fn write_to(&self, path: &::std::path::Path) -> $crate::Result<()> {
433 self.0.write_to(path)
434 }
435 }
436
437 impl std::ops::Deref for $name {
438 type Target = $crate::DirChildren<$ty>;
439
440 fn deref(&self) -> &Self::Target {
441 &self.0
442 }
443 }
444
445 impl std::ops::DerefMut for $name {
446 fn deref_mut(&mut self) -> &mut Self::Target {
447 &mut self.0
448 }
449 }
450
451 impl std::iter::IntoIterator for $name {
452 type Item = $crate::DirChild<$ty>;
453 type IntoIter = std::vec::IntoIter<Self::Item>;
454
455 fn into_iter(self) -> Self::IntoIter {
456 self.0.into_iter()
457 }
458 }
459 };
460}
461
462pub use dir_structure_macros::DirStructure;
463
464#[cfg(feature = "json")]
465pub mod json {
466 use std::fmt;
471 use std::fmt::Formatter;
472 use std::path::Path;
473 use std::str::FromStr;
474
475 use crate::{FromRefForWriter, NewtypeToInner, ReadFrom, WriteTo};
476
477 #[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash)]
481 #[serde(transparent)]
482 pub struct Json<T>(#[serde(bound = "")] pub T)
483 where
484 T: 'static + serde::Serialize + for<'d> serde::Deserialize<'d>;
485
486 impl<T> FromStr for Json<T>
487 where
488 T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
489 {
490 type Err = serde_json::Error;
491
492 fn from_str(s: &str) -> Result<Self, Self::Err> {
493 serde_json::from_str(s).map(Self)
494 }
495 }
496
497 struct JsonToStr<'a, T>(&'a T)
498 where
499 T: serde::Serialize + 'a;
500
501 impl<'a, T> fmt::Display for JsonToStr<'a, T>
502 where
503 T: serde::Serialize + 'a,
504 {
505 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
506 let s = serde_json::to_string(&self.0).map_err(|_| fmt::Error)?;
507 write!(f, "{}", s)
508 }
509 }
510
511 impl<T> fmt::Display for Json<T>
512 where
513 T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
514 {
515 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
516 JsonToStr(&self.0).fmt(f)
517 }
518 }
519
520 impl<T> ReadFrom for Json<T>
521 where
522 T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
523 {
524 fn read_from(path: &Path) -> crate::Result<Self> {
525 let contents = crate::FileString::read_from(path)?.0;
526 let v = serde_json::from_str::<Self>(&contents)
527 .map_err(|e| crate::Error::Parse(path.to_path_buf(), e.into()))?;
528 Ok(v)
529 }
530 }
531
532 impl<T> WriteTo for Json<T>
533 where
534 T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
535 {
536 fn write_to(&self, path: &Path) -> crate::Result<()> {
537 Self::from_ref_for_writer(&self.0).write_to(path)
538 }
539 }
540
541 impl<T> NewtypeToInner for Json<T>
542 where
543 T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
544 {
545 type Inner = T;
546
547 fn into_inner(self) -> Self::Inner {
548 self.0
549 }
550 }
551
552 impl<'a, T> FromRefForWriter<'a> for Json<T>
553 where
554 T: serde::Serialize + for<'d> serde::Deserialize<'d> + 'static,
555 {
556 type Inner = T;
557 type Wr = JsonWr<'a, T>;
558
559 fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
560 JsonWr(value)
561 }
562 }
563
564 pub struct JsonWr<'a, T>(&'a T)
566 where
567 T: serde::Serialize + 'a;
568
569 impl<'a, T> WriteTo for JsonWr<'a, T>
570 where
571 T: serde::Serialize + 'a,
572 {
573 fn write_to(&self, path: &Path) -> crate::Result<()> {
574 crate::FileString::from_ref_for_writer(&format!("{}", JsonToStr(self.0))).write_to(path)
575 }
576 }
577}
578
579pub struct FmtWrapper<T>(pub T);
584
585impl<T> NewtypeToInner for FmtWrapper<T> {
586 type Inner = T;
587
588 fn into_inner(self) -> Self::Inner {
589 self.0
590 }
591}
592
593impl<T> ReadFrom for FmtWrapper<T>
594where
595 T: FromStr,
596 T::Err: Into<Box<dyn std::error::Error + Send + Sync>>,
597{
598 fn read_from(path: &Path) -> Result<Self>
599 where
600 Self: Sized,
601 {
602 let contents = FileString::read_from(path)?.0;
603 match contents.parse::<T>() {
604 Ok(v) => Ok(Self(v)),
605 Err(e) => Err(Error::Parse(path.to_path_buf(), e.into())),
606 }
607 }
608}
609
610impl<T> WriteTo for FmtWrapper<T>
611where
612 T: Display,
613{
614 fn write_to(&self, path: &Path) -> Result<()> {
615 Self::from_ref_for_writer(&self.0).write_to(path)
616 }
617}
618
619impl<'a, T> FromRefForWriter<'a> for FmtWrapper<T>
620where
621 T: Display + 'a,
622{
623 type Inner = T;
624 type Wr = FmtWrapperRefWr<'a, T>;
625
626 fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
627 FmtWrapperRefWr(value)
628 }
629}
630
631pub struct FmtWrapperRefWr<'a, T: ?Sized>(pub &'a T);
634
635impl<'a, T> WriteTo for FmtWrapperRefWr<'a, T>
636where
637 T: Display + ?Sized,
638{
639 fn write_to(&self, path: &Path) -> Result<()> {
640 use std::io::Write;
641 utils::create_parent_dir(path)?;
642 let mut f = File::create(path).wrap_io_error_with(path)?;
643 write!(f, "{}", self.0).wrap_io_error_with(path)?;
644 Ok(())
645 }
646}
647
648#[derive(Debug, Clone, PartialEq, Eq, Hash)]
650pub struct FileBytes(pub Vec<u8>);
651
652impl FileBytes {
653 pub fn new(v: impl Into<Vec<u8>>) -> Self {
655 Self(v.into())
656 }
657}
658
659impl ReadFrom for FileBytes {
660 fn read_from(path: &Path) -> Result<Self>
661 where
662 Self: Sized,
663 {
664 std::fs::read(path).wrap_io_error_with(path).map(Self)
665 }
666}
667
668impl WriteTo for FileBytes {
669 fn write_to(&self, path: &Path) -> Result<()> {
670 Self::from_ref_for_writer(&self.0).write_to(path)
671 }
672}
673
674impl From<FileBytes> for Vec<u8> {
675 fn from(value: FileBytes) -> Self {
676 value.0
677 }
678}
679
680impl NewtypeToInner for FileBytes {
681 type Inner = Vec<u8>;
682
683 fn into_inner(self) -> Self::Inner {
684 self.0
685 }
686}
687
688impl<'a> FromRefForWriter<'a> for FileBytes {
689 type Inner = [u8];
690 type Wr = FileBytesRefWr<'a>;
691
692 fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
693 FileBytesRefWr(value)
694 }
695}
696
697pub struct FileBytesRefWr<'a>(&'a [u8]);
699
700impl<'a> WriteTo for FileBytesRefWr<'a> {
701 fn write_to(&self, path: &Path) -> Result<()> {
702 utils::create_parent_dir(path)?;
703 std::fs::write(path, self.0).wrap_io_error_with(path)?;
704 Ok(())
705 }
706}
707
708#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
710pub struct FileString(pub String);
711
712impl FileString {
713 pub fn new(s: impl Into<String>) -> Self {
715 Self(s.into())
716 }
717}
718
719impl From<FileString> for String {
720 fn from(value: FileString) -> Self {
721 value.0
722 }
723}
724
725impl NewtypeToInner for FileString {
726 type Inner = String;
727
728 fn into_inner(self) -> Self::Inner {
729 self.0
730 }
731}
732
733impl ReadFrom for FileString {
734 fn read_from(path: &Path) -> Result<Self>
735 where
736 Self: Sized,
737 {
738 std::fs::read_to_string(path)
739 .wrap_io_error_with(path)
740 .map(Self)
741 }
742}
743
744impl WriteTo for FileString {
745 fn write_to(&self, path: &Path) -> Result<()> {
746 Self::from_ref_for_writer(&self.0).write_to(path)
747 }
748}
749
750impl<'a> FromRefForWriter<'a> for FileString {
751 type Inner = str;
752 type Wr = FileStrWr<'a>;
753
754 fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
755 FileStrWr(value)
756 }
757}
758
759pub struct FileStrWr<'a>(&'a str);
761
762impl WriteTo for FileStrWr<'_> {
763 fn write_to(&self, path: &Path) -> Result<()> {
764 FileBytes::from_ref_for_writer(self.0.as_bytes()).write_to(path)
765 }
766}
767
768impl<T> ReadFrom for Option<T>
769where
770 T: ReadFrom,
771{
772 fn read_from(path: &Path) -> Result<Self>
773 where
774 Self: Sized,
775 {
776 if path.exists() {
777 T::read_from(path).map(Some)
778 } else {
779 Ok(None)
780 }
781 }
782}
783
784impl<T> WriteTo for Option<T>
785where
786 T: WriteTo,
787{
788 fn write_to(&self, path: &Path) -> Result<()> {
789 if let Some(v) = self {
790 v.write_to(path)
791 } else {
792 Ok(())
793 }
794 }
795}
796
797#[derive(Debug, Clone, Hash)]
799pub struct DeferredRead<T>(pub PathBuf, std::marker::PhantomData<T>)
800where
801 T: ReadFrom;
802
803impl<T> ReadFrom for DeferredRead<T>
804where
805 T: ReadFrom,
806{
807 fn read_from(path: &Path) -> Result<Self>
808 where
809 Self: Sized,
810 {
811 Ok(Self(path.to_path_buf(), std::marker::PhantomData))
812 }
813}
814
815impl<T> DeferredRead<T>
816where
817 T: ReadFrom,
818{
819 pub fn perform_read(&self) -> Result<T> {
821 T::read_from(&self.0)
822 }
823}
824
825impl<T> WriteTo for DeferredRead<T>
826where
827 T: ReadFrom + WriteTo,
828{
829 fn write_to(&self, path: &Path) -> Result<()> {
830 if path == self.0 {
831 return Ok(());
839 }
840
841 let r = self.perform_read()?;
842 r.write_to(path)
843 }
844}
845
846#[derive(Debug, Clone, Hash)]
850pub enum DeferredReadOrOwn<T>
851where
852 T: ReadFrom,
853{
854 Own(T),
855 Deferred(DeferredRead<T>),
856}
857
858impl<T> DeferredReadOrOwn<T>
859where
860 T: ReadFrom,
861{
862 pub fn get(&self) -> Result<T>
864 where
865 T: Clone,
866 {
867 match self {
868 DeferredReadOrOwn::Own(own) => Ok(own.clone()),
869 DeferredReadOrOwn::Deferred(d) => Ok(d.perform_read()?),
870 }
871 }
872
873 pub fn perform_and_store_read(&mut self) -> Result<&T> {
876 match self {
877 DeferredReadOrOwn::Own(own) => Ok(own),
878 DeferredReadOrOwn::Deferred(d) => {
879 let value = d.perform_read()?;
880 *self = DeferredReadOrOwn::Own(value);
881 let DeferredReadOrOwn::Own(own) = self else {
882 unreachable!()
883 };
884 Ok(own)
885 }
886 }
887 }
888}
889
890impl<T> ReadFrom for DeferredReadOrOwn<T>
891where
892 T: ReadFrom,
893{
894 fn read_from(path: &Path) -> Result<Self>
895 where
896 Self: Sized,
897 {
898 ReadFrom::read_from(path).map(Self::Deferred)
899 }
900}
901
902impl<T> WriteTo for DeferredReadOrOwn<T>
903where
904 T: ReadFrom + WriteTo,
905{
906 fn write_to(&self, path: &Path) -> Result<()> {
907 match self {
908 DeferredReadOrOwn::Own(own) => own.write_to(path),
909 DeferredReadOrOwn::Deferred(d) => d.write_to(path),
910 }
911 }
912}
913
914pub struct CleanDir<T: DirStructureItem>(pub T);
921
922impl<T> ReadFrom for CleanDir<T>
923where
924 T: DirStructureItem,
925{
926 fn read_from(path: &Path) -> Result<Self>
927 where
928 Self: Sized,
929 {
930 Ok(Self(T::read_from(path)?))
931 }
932}
933
934impl<T> WriteTo for CleanDir<T>
935where
936 T: DirStructureItem,
937{
938 fn write_to(&self, path: &Path) -> Result<()> {
939 Self::from_ref_for_writer(&self.0).write_to(path)
940 }
941}
942
943impl<'a, T> FromRefForWriter<'a> for CleanDir<T>
944where
945 T: DirStructureItem + 'a,
946{
947 type Inner = T;
948 type Wr = CleanDirRefWr<'a, T>;
949
950 fn from_ref_for_writer(value: &'a Self::Inner) -> Self::Wr {
951 CleanDirRefWr(value)
952 }
953}
954
955impl<T> NewtypeToInner for CleanDir<T>
956where
957 T: DirStructureItem,
958{
959 type Inner = T;
960
961 fn into_inner(self) -> Self::Inner {
962 self.0
963 }
964}
965
966pub struct CleanDirRefWr<'a, T: ?Sized + DirStructureItem>(&'a T);
968
969impl<'a, T> WriteTo for CleanDirRefWr<'a, T>
970where
971 T: ?Sized + DirStructureItem,
972{
973 fn write_to(&self, path: &Path) -> Result<()> {
974 if path.exists() {
975 std::fs::remove_dir_all(path).wrap_io_error_with(path)?;
976 } else {
977 utils::create_parent_dir(path)?;
978 }
979 self.0.write_to(path)
980 }
981}
982
983#[derive(Debug, Clone, Hash)]
1008pub struct Versioned<T: DirStructureItem> {
1009 value: T,
1010 version: usize,
1011 path: PathBuf,
1012}
1013
1014impl<T: DirStructureItem> Versioned<T> {
1015 const DEFAULT_VERSION: usize = 0;
1016
1017 pub fn new(value: T, path: impl Into<PathBuf>) -> Self {
1021 Self {
1022 value: value.into(),
1023 version: Self::DEFAULT_VERSION,
1024 path: path.into(),
1025 }
1026 }
1027
1028 pub fn new_dirty(value: T, path: impl Into<PathBuf>) -> Self {
1039 Self {
1040 value: value.into(),
1041 version: Self::DEFAULT_VERSION + 1,
1042 path: path.into(),
1043 }
1044 }
1045
1046 pub fn is_dirty(&self) -> bool {
1048 !self.is_clean()
1049 }
1050
1051 pub fn is_clean(&self) -> bool {
1053 self.version == Self::DEFAULT_VERSION
1054 }
1055
1056 pub fn edit_eq_check(&mut self, f: impl FnOnce(&mut T))
1072 where
1073 T: Eq + Clone,
1074 {
1075 let copy = self.value.clone();
1076
1077 f(&mut self.value);
1078
1079 if copy != self.value {
1080 self.version += 1;
1081 }
1082 }
1083}
1084
1085impl<T: DirStructureItem> ReadFrom for Versioned<T> {
1086 fn read_from(path: &Path) -> Result<Self>
1087 where
1088 Self: Sized,
1089 {
1090 T::read_from(path).map(|it| Self::new(it, path))
1091 }
1092}
1093
1094impl<T: DirStructureItem> WriteTo for Versioned<T> {
1095 fn write_to(&self, path: &Path) -> Result<()> {
1096 if self.path == path && self.is_clean() {
1097 return Ok(());
1098 }
1099
1100 self.value.write_to(path)
1101 }
1102}
1103
1104impl<T: DirStructureItem> Deref for Versioned<T> {
1105 type Target = T;
1106
1107 fn deref(&self) -> &Self::Target {
1108 &self.value
1109 }
1110}
1111
1112impl<T: DirStructureItem> DerefMut for Versioned<T> {
1113 fn deref_mut(&mut self) -> &mut Self::Target {
1114 self.version += 1;
1117
1118 &mut self.value
1119 }
1120}
1121
1122pub type VersionedString = Versioned<String>;
1123pub type VersionedBytes = Versioned<Vec<u8>>;
1124
1125impl ReadFrom for String {
1128 fn read_from(path: &Path) -> Result<Self>
1129 where
1130 Self: Sized,
1131 {
1132 FileString::read_from(path).map(|v| v.0)
1133 }
1134}
1135
1136impl WriteTo for String {
1137 fn write_to(&self, path: &Path) -> Result<()> {
1138 FileString::from_ref_for_writer(self).write_to(path)
1139 }
1140}
1141
1142impl ReadFrom for Vec<u8> {
1143 fn read_from(path: &Path) -> Result<Self>
1144 where
1145 Self: Sized,
1146 {
1147 FileBytes::read_from(path).map(|v| v.0)
1148 }
1149}
1150
1151impl WriteTo for Vec<u8> {
1152 fn write_to(&self, path: &Path) -> Result<()> {
1153 FileBytes::from_ref_for_writer(self).write_to(path)
1154 }
1155}
1156
1157impl WriteTo for str {
1158 fn write_to(&self, path: &Path) -> Result<()> {
1159 FileStrWr(self).write_to(path)
1160 }
1161}
1162
1163impl<'a> WriteTo for &'a str {
1164 fn write_to(&self, path: &Path) -> Result<()> {
1165 FileStrWr(self).write_to(path)
1166 }
1167}
1168
1169impl WriteTo for [u8] {
1170 fn write_to(&self, path: &Path) -> Result<()> {
1171 FileBytesRefWr(self).write_to(path)
1172 }
1173}
1174
1175impl<'a> WriteTo for &'a [u8] {
1176 fn write_to(&self, path: &Path) -> Result<()> {
1177 FileBytesRefWr(self).write_to(path)
1178 }
1179}
1180
1181mod utils {
1182 use crate::WrapIoError;
1183
1184 pub fn create_parent_dir(path: &std::path::Path) -> crate::Result<()> {
1185 if let Some(parent) = path.parent() {
1186 if !parent.exists() {
1187 std::fs::create_dir_all(parent).wrap_io_error_with(parent)?;
1188 }
1189 }
1190 Ok(())
1191 }
1192}