pub struct Phazer<'cs> { /* private fields */ }
Expand description
Phazer
manages the transition of the working file to the target file.
Phazer
is the core component of this crate. One Phazer
is constructed for each target
file. Phazer
essentially a wrapper over the target path. For example, if the application
downloads three files from the internet then one Phazer
is created for each file.
By default, Phazer
uses a simple rename commit strategy (SIMPLE_RENAME_STRATEGY
). When
Phazer::commit
is called, rename
is used to replace the target file with the working
file. PhazerBuilder
can be used to construct a Phazer
with a different commit strategy.
The one other commit strategy available with this crate is RENAME_WITH_RETRY_STRATEGY
.
Implementations§
Source§impl<'cs> Phazer<'cs>
impl<'cs> Phazer<'cs>
Sourcepub fn simple_writer<'a>(&'a self) -> Result<SimplePhazerWriter<'_, '_>>
pub fn simple_writer<'a>(&'a self) -> Result<SimplePhazerWriter<'_, '_>>
Returns a synchronous file-like thing that’s used to build the working file.
In addition to managing the transition from working file to target file (a commit),
Phazer
provides a way to build the working file. That process starts here with the
creation of a SimplePhazerWriter
. If a working file has not yet been created this
method creates the working file. If a working file exists this method opens the existing
file for read / write access.
The working file cannot be open when Phazer::commit
is called. This is enforced by
a lifetime connecting each SimplePhazerWriter
to the Phazer
that created it. If
Phazer::commit
is called when a SimplePhazerWriter
is active an error similar to
the following occurs when compiling…
error[E0505]: cannot move out of 'phazer' because it is borrowed
This method is available when the simple
feature is enabled.
§Return Value
An Error
is returned if the working file cannot be created or opened for read
/ write access. Otherwise a new SimplePhazerWriter
is returned that provides access to
the working file.
§Example
use std::fs::canonicalize;
use std::io::Write;
use phazer::Phazer;
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
// Use a full path so we can freely change the working directory
let full_path = canonicalize("config.toml")?;
// Create the Phazer
let phazer = Phazer::new(&full_path);
// Write some stuff. Drop the writer to ensure the file is not open.
let mut writer = phazer.simple_writer()?;
writer.write_all("[Serial Port]\nbaud = 250000\n".as_bytes())?;
drop(writer);
// Rename the working file to the target file ("save" the changes)
phazer.commit()?;
Ok(())
}
Source§impl<'cs> Phazer<'cs>
impl<'cs> Phazer<'cs>
Sourcepub async fn tokio_writer<'a>(&'a self) -> Result<TokioPhazerWriter<'_, '_>>
pub async fn tokio_writer<'a>(&'a self) -> Result<TokioPhazerWriter<'_, '_>>
Returns an asynchronous file-like thing that’s used to build the working file.
In addition to managing the transition from working file to target file (a commit),
Phazer
provides a way to build the working file. That process starts here with the
creation of a TokioPhazerWriter
. If a working file has not yet been created this
method creates the working file. If a working file exists this method opens the existing
file for read / write access.
The working file cannot be open when Phazer::commit
is called. This is enforced by
a lifetime connecting each TokioPhazerWriter
to the Phazer
that created it. If
Phazer::commit
is called when a TokioPhazerWriter
is active an error similar to
the following occurs when compiling…
error[E0505]: cannot move out of 'phazer' because it is borrowed
This method is available when the tokio
feature is enabled.
§Return Value
An Error
is returned if the working file cannot be created or opened for read
/ write access. Otherwise a new TokioPhazerWriter
is returned that provides access to
the working file.
§Example
use tokio::fs::canonicalize;
use tokio::io::AsyncWriteExt;
use phazer::Phazer;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Use a full path so we can freely change the working directory
let full_path = canonicalize("config.toml").await?;
// Create the Phazer
let phazer = Phazer::new(&full_path);
// Write some stuff. Drop the writer to ensure the file is not open.
let mut writer = phazer.tokio_writer().await?;
writer.write_all("[Serial Port]\nbaud = 250000\n".as_bytes()).await?;
drop(writer);
// Rename the working file to the target file ("save" the changes)
phazer.commit()?;
Ok(())
}
Source§impl<'cs> Phazer<'cs>
impl<'cs> Phazer<'cs>
Sourcepub fn new<P>(path: P) -> Self
pub fn new<P>(path: P) -> Self
Creates a Phazer
where path
is the target file.
§Arguments
path
- Target file. Ideally, the full path is specified so changes to the working directory do not cause problems. canonicalize is helpful.
§Return Value
A new Phazer
is always returned; Phazer::new
is infallible.
Sourcepub fn commit(self) -> Result<(), Error>
pub fn commit(self) -> Result<(), Error>
commit
transfers the working file to the target file; by default this is done with
a rename.
If the working file was not created then commit
simply returns Ok(())
.
The working file cannot be open when commit
is called. This is enforced by a
lifetime connecting each writer to the Phazer
that created it. If commit
is
called when a writer is active then an error similar to the following occurs when
compiling…
error[E0505]: cannot move out of 'phazer' because it is borrowed
Often, writers must be explicitly dropped before calling commit
. This is shown in
the example.
§Return Value
An Error
is returned if the working file cannot be transferred to the target file.
In this case the working file is removed.
§Example
use std::fs::canonicalize;
use std::io::Write;
use phazer::Phazer;
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
// Use a full path so we can freely change the working directory
let target = canonicalize("config.toml")?;
// Create the Phazer
let phazer = Phazer::new(&target);
// Write some stuff. Drop the writer to ensure the file is not open.
let mut writer = phazer.simple_writer()?;
writer.write_all("[Serial Port]\nbaud = 250000\n".as_bytes())?;
// Note the explicit `drop`. This ensures `writer` does not exist when `commit` is
// called. That the working file is no longer open.
drop(writer);
// Rename the working file to the target file ("save" the changes)
phazer.commit()?;
Ok(())
}
Sourcepub fn commit2(self) -> Result<(), (Error, Phazer<'cs>)>
pub fn commit2(self) -> Result<(), (Error, Phazer<'cs>)>
commit2
transfers the working file to the target file; by default this is done with
a rename.
If the working file was not created then commit2
simply returns Ok(())
.
The working file cannot be open when commit2
is called. This is enforced by a
lifetime connecting each writer to the Phazer
that created it. If commit2
is
called when a writer is active then an error similar to the following occurs when
compiling…
error[E0505]: cannot move out of 'phazer' because it is borrowed
Often, writers must be explicitly dropped before calling commit2
. This is shown in
the example.
§Return Value
An Error
and the Phazer
are returned if the working file cannot be transferred
to the target file. This allows for error recovery not provided by this crate. For
example, on Windows, a target file with the read-only attribute set cannot be replaced with
a rename
. This is demonstrated in the example.
§Example
use std::fs::{canonicalize, metadata, set_permissions};
use std::io::{ErrorKind, Write};
use std::path::Path;
use phazer::Phazer;
fn set_readonly<P: AsRef<Path>>(path: P, value: bool) -> Result<bool, std::io::Error> {
let path = path.as_ref();
let m = metadata(path)?;
let mut p = m.permissions();
let rv = p.readonly();
p.set_readonly(value);
set_permissions(path, p)?;
Ok(rv)
}
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
// Use a full path so we can freely change the working directory
let target = canonicalize("read-only-windows.txt")?;
// Create the target
let phazer = Phazer::new(&target);
let mut writer = phazer.simple_writer()?;
writer.write_all("read-only".as_bytes())?;
drop(writer);
phazer.commit()?;
// Set the read-only attribute
set_readonly(&target, true)?;
// Try to update it...
let phazer = Phazer::new(&target);
let mut writer = phazer.simple_writer()?;
writer.write_all("something new".as_bytes())?;
drop(writer);
// ...using commit2 so we can recover if the read-only attribute is set.
match phazer.commit2() {
Ok(()) => {
println!("Success! This was unexpected. Windows up to 11 always failed.");
}
Err((e, p)) => {
// If the error is anything except PermissionDenied then return it
if e.kind() != ErrorKind::PermissionDenied {
return Err(e.into());
}
// Clear the read-only attribute
let _ = set_readonly(&target, false);
// Try again
p.commit()?;
}
}
Ok(())
}