versatiles_core/utils/io/
data_writer_file.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! This module provides functionality for writing data to files.
//!
//! # Overview
//!
//! The `DataWriterFile` struct allows for writing data to files on the filesystem.
//! It implements the `DataWriterTrait` to provide methods for appending data, writing data from the start,
//! and managing the write position. The module ensures the file path is absolute before attempting to create or write to the file.
//!
//! # Examples
//!
//! ```rust
//! use versatiles::{utils::io::{DataWriterFile, DataWriterTrait}, types::{Blob, ByteRange}};
//! use anyhow::Result;
//! use std::path::Path;
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//!     let path = std::env::current_dir()?.join("../testdata/temp.txt");
//!     let mut writer = DataWriterFile::from_path(&path)?;
//!     let data = Blob::from(vec![1, 2, 3, 4]);
//!
//!     // Appending data
//!     writer.append(&data)?;
//!     assert_eq!(writer.get_position()?, 4);
//!
//!     // Writing data from the start
//!     writer.write_start(&Blob::from(vec![5, 6, 7, 8]))?;
//!     writer.set_position(0)?;
//!     assert_eq!(writer.get_position()?, 0);
//!
//!     Ok(())
//! }
//! ```

use super::DataWriterTrait;
use crate::types::{Blob, ByteRange};
use anyhow::{ensure, Result};
use async_trait::async_trait;
use std::{
	fs::File,
	io::{BufWriter, Seek, SeekFrom, Write},
	path::Path,
};

/// A struct that provides writing capabilities to a file.
pub struct DataWriterFile {
	writer: BufWriter<File>,
}

impl DataWriterFile {
	/// Creates a `DataWriterFile` from a file path.
	///
	/// # Arguments
	///
	/// * `path` - A reference to the file path to create and write to.
	///
	/// # Returns
	///
	/// * A Result containing the new `DataWriterFile` instance or an error.
	pub fn from_path(path: &Path) -> Result<DataWriterFile> {
		ensure!(path.is_absolute(), "path {path:?} must be absolute");

		Ok(DataWriterFile {
			writer: BufWriter::new(File::create(path)?),
		})
	}
}

#[async_trait]
impl DataWriterTrait for DataWriterFile {
	/// Appends data to the file.
	///
	/// # Arguments
	///
	/// * `blob` - A reference to the `Blob` to append.
	///
	/// # Returns
	///
	/// * A Result containing a `ByteRange` indicating the position and length of the appended data, or an error.
	fn append(&mut self, blob: &Blob) -> Result<ByteRange> {
		let pos = self.writer.stream_position()?;
		let len = self.writer.write(blob.as_slice())?;

		Ok(ByteRange::new(pos, len as u64))
	}

	/// Writes data from the start of the file.
	///
	/// # Arguments
	///
	/// * `blob` - A reference to the `Blob` to write.
	///
	/// # Returns
	///
	/// * A Result indicating success or an error.
	fn write_start(&mut self, blob: &Blob) -> Result<()> {
		let pos = self.writer.stream_position()?;
		self.writer.rewind()?;
		self.writer.write_all(blob.as_slice())?;
		self.writer.seek(SeekFrom::Start(pos))?;
		Ok(())
	}

	/// Gets the current write position.
	///
	/// # Returns
	///
	/// * A Result containing the current write position in bytes or an error.
	fn get_position(&mut self) -> Result<u64> {
		Ok(self.writer.stream_position()?)
	}

	/// Sets the write position.
	///
	/// # Arguments
	///
	/// * `position` - The position to set in bytes.
	///
	/// # Returns
	///
	/// * A Result indicating success or an error.
	fn set_position(&mut self, position: u64) -> Result<()> {
		self.writer.seek(SeekFrom::Start(position))?;
		Ok(())
	}
}