use std::fs::Permissions;
use std::io::{self, Write};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use thiserror::Error;
use crate::verbatim_path;
#[derive(Debug)]
pub struct NamedTempFile(tempfile::NamedTempFile);
pub fn tempfile_in(path: &Path) -> io::Result<NamedTempFile> {
tempfile_in_with_permissions(path, None)
}
pub(crate) fn tempfile_in_with_permissions(
path: &Path,
permissions: Option<Permissions>,
) -> io::Result<NamedTempFile> {
#[cfg(unix)]
let permissions = Some(permissions.unwrap_or_else(|| Permissions::from_mode(0o666)));
let mut builder = tempfile::Builder::new();
if let Some(permissions) = permissions {
builder.permissions(permissions);
}
Ok(NamedTempFile(builder.tempfile_in(verbatim_path(path))?))
}
impl NamedTempFile {
#[expect(clippy::disallowed_types, reason = "tempfile exposes a std::fs::File")]
pub fn as_file(&self) -> &std::fs::File {
self.0.as_file()
}
#[expect(clippy::disallowed_types, reason = "tempfile exposes a std::fs::File")]
pub fn persist(self, path: impl AsRef<Path>) -> Result<std::fs::File, PersistError> {
self.0
.persist(verbatim_path(path.as_ref()))
.map_err(|error| PersistError {
error: error.error,
file: Self(error.file),
})
}
}
impl AsRef<Path> for NamedTempFile {
fn as_ref(&self) -> &Path {
self.0.path()
}
}
impl Write for NamedTempFile {
fn write(&mut self, buffer: &[u8]) -> io::Result<usize> {
self.0.write(buffer)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
#[derive(Debug, Error)]
#[error("failed to persist temporary file: {error}")]
pub struct PersistError {
#[source]
pub error: io::Error,
pub file: NamedTempFile,
}