~kmaasrud/m2dir-rs

07969045b91efa3c8491b62561beaf67388af577 — Knut Magnus Aasrud 2 months ago c0eef07
feat: add copy_to and move_to functions
3 files changed, 41 insertions(+), 7 deletions(-)

M src/dir.rs
M src/entry.rs
M src/store.rs
M src/dir.rs => src/dir.rs +2 -2
@@ 50,7 50,7 @@ impl M2Dir {
    /// let m2dir = M2Dir::new("/path/to/m2dir").unwrap();
    /// let result = m2dir.store(&data[..]).unwrap();
    /// ```
    pub fn store<R: Read>(&self, mut reader: R) -> std::io::Result<PathBuf> {
    pub fn store<R: Read>(&self, mut reader: R) -> std::io::Result<Entry> {
        // Read into memory first. If the reader is slow (e.g. network bound,) this will
        // minimize the time spent in temporary disk state
        let mut bytes = Vec::new();


@@ 70,7 70,7 @@ impl M2Dir {
        let path = self.path.join(format!("{dt}:{checksum}"));
        write_atomic(&path, bytes.as_slice())?;

        Ok(path)
        Ok(Entry { path, id: checksum })
    }

    /// Returns an iterator over all valid email entries within the m2dir.

M src/entry.rs => src/entry.rs +37 -3
@@ 1,16 1,17 @@
use std::{
    error::Error,
    fmt::{self, Debug, Display},
    fs::File,
    io,
    path::{Path, PathBuf},
};

use crate::{meta::Metadata, walk::Walker};
use crate::{meta::Metadata, walk::Walker, M2Dir};

/// Represents a message entry in an m2dir.
pub struct Entry {
    id: String,
    path: PathBuf,
    pub(crate) id: String,
    pub(crate) path: PathBuf,
}

impl Entry {


@@ 105,6 106,39 @@ impl Entry {
        Ok(())
    }

    /// Copies the entry to the specified m2dir.
    ///
    /// If successful, returns a new [`Entry`] pointing to the copied message
    /// file.
    ///
    /// # Errors
    ///
    /// Returns an [std::io::Error] if there are any issues during the file
    /// copying process.
    pub fn copy_to(&self, dir: &M2Dir) -> io::Result<Self> {
        // NOTE: This will compute the checksum again. That might be beneficial as an
        // extra check, but we might want to improve performance somehow by copying
        // directly. Should be investigated at a later stage.
        dir.store(File::open(self.path())?)
    }

    /// Moves the entry to the specified m2dir.
    ///
    /// If successful, returns a new [`Entry`] pointing to the moved message
    /// file. Ownership is taken from the original [`Entry`] struct.
    ///
    /// # Errors
    ///
    /// Returns an [std::io::Error] if there are any issues during the file
    /// moving process.
    pub fn move_to(self, dir: &M2Dir) -> io::Result<Self> {
        // NOTE: See note in copy_to. This might benefit even more, as the only thing
        // required here is a rename. Worth benchmarking.
        let new = dir.store(File::open(self.path())?)?;
        self.delete()?;
        Ok(new)
    }

    /// Deletes the email message file and its associated metadata files.
    ///
    /// # Errors

M src/store.rs => src/store.rs +2 -2
@@ 13,7 13,7 @@ use crate::{
    fs::is_dotfile,
    percent::{percent_decode_bytes, percent_encode_bytes},
    walk::Walker,
    M2Dir,
    Entry, M2Dir,
};

/// Represents the an m2store directory structure.


@@ 55,7 55,7 @@ impl M2Store {
    /// This function will error if the delivery target is not a valid m2dir.
    /// Additionally, if any io errors arise while storing the message, they
    /// will also get thrown.
    pub fn deliver<R: Read>(&self, reader: R) -> Result<PathBuf, DeliveryError> {
    pub fn deliver<R: Read>(&self, reader: R) -> Result<Entry, DeliveryError> {
        Ok(self.delivery_target()?.store(reader)?)
    }