use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::ops::{Deref, DerefMut};
use std::error;
use std::fmt;
use std::env;
use std;
use util;
use super::imp;
pub struct NamedTempFile(Option<NamedTempFileInner>);
impl AsRef<File> for NamedTempFile {
fn as_ref(&self) -> &File {
self
}
}
impl AsMut<File> for NamedTempFile {
fn as_mut(&mut self) -> &mut File {
self
}
}
struct NamedTempFileInner {
file: File,
path: PathBuf,
}
impl fmt::Debug for NamedTempFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "NamedTempFile({:?})", self.0.as_ref().unwrap().path)
}
}
impl Deref for NamedTempFile {
type Target = File;
#[inline]
fn deref(&self) -> &File {
&self.inner().file
}
}
impl DerefMut for NamedTempFile {
#[inline]
fn deref_mut(&mut self) -> &mut File {
&mut self.inner_mut().file
}
}
#[derive(Debug)]
pub struct PersistError {
pub error: io::Error,
pub file: NamedTempFile,
}
impl From<PersistError> for io::Error {
#[inline]
fn from(error: PersistError) -> io::Error {
error.error
}
}
impl From<PersistError> for NamedTempFile {
#[inline]
fn from(error: PersistError) -> NamedTempFile {
error.file
}
}
impl fmt::Display for PersistError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "failed to persist temporary file: {}", self.error)
}
}
impl error::Error for PersistError {
fn description(&self) -> &str {
"failed to persist temporary file"
}
fn cause(&self) -> Option<&error::Error> {
Some(&self.error)
}
}
impl NamedTempFile {
#[inline]
fn inner(&self) -> &NamedTempFileInner {
self.0.as_ref().unwrap()
}
#[inline]
fn inner_mut(&mut self) -> &mut NamedTempFileInner {
self.0.as_mut().unwrap()
}
pub fn new() -> io::Result<NamedTempFile> {
NamedTempFileOptions::new().create()
}
pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
NamedTempFileOptions::new().create_in(dir)
}
#[inline]
pub fn path(&self) -> &Path {
&self.inner().path
}
pub fn close(mut self) -> io::Result<()> {
let NamedTempFileInner { path, file } = self.0.take().unwrap();
drop(file);
fs::remove_file(path)
}
pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<File, PersistError> {
match imp::persist(&self.inner().path, new_path.as_ref(), true) {
Ok(_) => Ok(self.0.take().unwrap().file),
Err(e) => {
Err(PersistError {
file: self,
error: e,
})
}
}
}
pub fn persist_noclobber<P: AsRef<Path>>(mut self, new_path: P) -> Result<File, PersistError> {
match imp::persist(&self.inner().path, new_path.as_ref(), false) {
Ok(_) => Ok(self.0.take().unwrap().file),
Err(e) => {
Err(PersistError {
file: self,
error: e,
})
}
}
}
pub fn reopen(&self) -> io::Result<File> {
imp::reopen(&self, self.path())
}
}
impl From<NamedTempFile> for File {
fn from(mut f: NamedTempFile) -> File {
let NamedTempFileInner { path, file } = f.0.take().unwrap();
let _ = fs::remove_file(path);
file
}
}
impl Drop for NamedTempFile {
fn drop(&mut self) {
if let Some(NamedTempFileInner { file, path }) = self.0.take() {
drop(file);
let _ = fs::remove_file(path);
}
}
}
impl Read for NamedTempFile {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
}
impl<'a> Read for &'a NamedTempFile {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(&***self).read(buf)
}
}
impl Write for NamedTempFile {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
(**self).write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
(**self).flush()
}
}
impl<'a> Write for &'a NamedTempFile {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
(&***self).write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
(&***self).flush()
}
}
impl Seek for NamedTempFile {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
(**self).seek(pos)
}
}
impl<'a> Seek for &'a NamedTempFile {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
(&***self).seek(pos)
}
}
#[cfg(unix)]
impl std::os::unix::io::AsRawFd for NamedTempFile {
#[inline]
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
(**self).as_raw_fd()
}
}
#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for NamedTempFile {
#[inline]
fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
(**self).as_raw_handle()
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct NamedTempFileOptions<'a, 'b> {
random_len: usize,
prefix: &'a str,
suffix: &'b str,
}
impl<'a, 'b> NamedTempFileOptions<'a, 'b> {
pub fn new() -> Self {
NamedTempFileOptions {
random_len: ::NUM_RAND_CHARS,
prefix: ".tmp",
suffix: "",
}
}
pub fn prefix(&mut self, prefix: &'a str) -> &mut Self {
self.prefix = prefix;
self
}
pub fn suffix(&mut self, suffix: &'b str) -> &mut Self {
self.suffix = suffix;
self
}
pub fn rand_bytes(&mut self, rand: usize) -> &mut Self {
self.random_len = rand;
self
}
pub fn create(&self) -> io::Result<NamedTempFile> {
self.create_in(&env::temp_dir())
}
pub fn create_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<NamedTempFile> {
for _ in 0..::NUM_RETRIES {
let path = dir.as_ref().join(util::tmpname(self.prefix, self.suffix, self.random_len));
return match imp::create_named(&path) {
Ok(file) => {
Ok(NamedTempFile(Some(NamedTempFileInner {
path: path,
file: file,
})))
}
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
Err(e) => Err(e),
};
}
Err(io::Error::new(io::ErrorKind::AlreadyExists,
"too many temporary files exist"))
}
}