path_abs/
read.rs

1/* Copyright (c) 2018 Garrett Berg, vitiral@gmail.com
2 *
3 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 * http://opensource.org/licenses/MIT>, at your option. This file may not be
6 * copied, modified, or distributed except according to those terms.
7 */
8//! Open file paths that are read-only.
9
10use std::fmt;
11use std::fs;
12use std::io;
13use std_prelude::*;
14
15use super::open::FileOpen;
16use super::{Error, PathAbs, PathFile, PathInfo, Result};
17
18/// A read-only file handle with `path()` attached and improved error messages. Contains only the
19/// methods and trait implementations which are allowed by a read-only file.
20///
21/// # Examples
22/// ```rust
23/// # extern crate path_abs;
24/// # extern crate tempdir;
25/// use std::io::Read;
26/// use path_abs::{PathFile, FileRead};
27///
28/// # fn try_main() -> ::std::io::Result<()> {
29/// let example = "example.txt";
30/// # let tmp = tempdir::TempDir::new("ex")?;
31/// # let example = &tmp.path().join(example);
32/// let file = PathFile::create(example)?;
33///
34/// let expected = "foo\nbar";
35/// file.write_str(expected)?;
36///
37/// let mut read = FileRead::open(example)?;
38/// let mut s = String::new();
39/// read.read_to_string(&mut s)?;
40/// assert_eq!(expected, s);
41/// # Ok(()) } fn main() { try_main().unwrap() }
42/// ```
43pub struct FileRead(pub(crate) FileOpen);
44
45impl FileRead {
46    /// Open the file as read-only.
47    pub fn open<P: AsRef<Path>>(path: P) -> Result<FileRead> {
48        let mut options = fs::OpenOptions::new();
49        options.read(true);
50        Ok(FileRead(FileOpen::open(path, options)?))
51    }
52
53    /// Shortcut to open the file if the path is already absolute.
54    pub(crate) fn open_abs<P: Into<PathAbs>>(path: P) -> Result<FileRead> {
55        let mut options = fs::OpenOptions::new();
56        options.read(true);
57        Ok(FileRead(FileOpen::open_abs(path, options)?))
58    }
59
60    pub fn path(&self) -> &PathFile {
61        &self.0.path
62    }
63
64    /// Read what remains of the file to a `String`.
65    pub fn read_string(&mut self) -> Result<String> {
66        let mut s = String::new();
67        self.0
68            .file
69            .read_to_string(&mut s)
70            .map_err(|err| Error::new(err, "reading", self.0.path.clone().into()))?;
71        Ok(s)
72    }
73}
74
75impl fmt::Debug for FileRead {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(f, "FileRead(")?;
78        self.0.path.fmt(f)?;
79        write!(f, ")")
80    }
81}
82
83impl io::Read for FileRead {
84    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
85        self.0.file.read(buf).map_err(|err| {
86            io::Error::new(
87                err.kind(),
88                format!("{} when reading {}", err, self.path().display()),
89            )
90        })
91    }
92}
93
94impl io::Seek for FileRead {
95    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
96        self.0.file.seek(pos).map_err(|err| {
97            io::Error::new(
98                err.kind(),
99                format!("{} seeking {}", err, self.path().display()),
100            )
101        })
102    }
103}
104
105impl AsRef<FileOpen> for FileRead {
106    fn as_ref(&self) -> &FileOpen {
107        &self.0
108    }
109}
110
111impl AsRef<File> for FileRead {
112    fn as_ref(&self) -> &File {
113        self.0.as_ref()
114    }
115}
116
117impl Borrow<FileOpen> for FileRead {
118    fn borrow(&self) -> &FileOpen {
119        &self.0
120    }
121}
122
123impl Borrow<File> for FileRead {
124    fn borrow(&self) -> &File {
125        self.0.borrow()
126    }
127}
128
129impl<'a> Borrow<FileOpen> for &'a FileRead {
130    fn borrow(&self) -> &FileOpen {
131        &self.0
132    }
133}
134
135impl<'a> Borrow<File> for &'a FileRead {
136    fn borrow(&self) -> &File {
137        self.0.borrow()
138    }
139}
140
141impl From<FileRead> for FileOpen {
142    fn from(orig: FileRead) -> FileOpen {
143        orig.0
144    }
145}
146
147impl From<FileRead> for File {
148    fn from(orig: FileRead) -> File {
149        orig.0.into()
150    }
151}