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
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};

use crate::kv_store::KV;

#[derive(Debug)]
pub struct Storage {
    file_path: Option<String>,
    pub file: Option<File>,
}

impl Storage {
    /// Creates a new Storage instance with an optional file path.
    ///
    /// # Arguments
    ///
    /// * `file_path` - An optional string slice that holds the file path.
    ///
    /// # Returns
    ///
    /// * A new instance of Storage.
    pub fn new(file_path: Option<&str>) -> Self {
        Storage {
            file_path: file_path.map(|path| path.to_string()), // Convert the file path to a String and store it in the struct
            file: None, // Initialize the file as None
        }
    }

    /// Loads the file from the specified or existing file path and deserializes the content.
    ///
    /// # Arguments
    ///
    /// * `file_path` - An optional string slice that holds the file path.
    ///
    /// # Returns
    ///
    /// * `Ok(Vec<KV>)` - A vector of deserialized KV structs if the operation is successful.
    /// * `Box<dyn Error>>` - An error message if the operation fails.
    pub fn load_file(&mut self, file_path: Option<&str>) -> Result<Vec<KV>, Box<dyn Error>> {
        match file_path {
            Some(path) => {
                self.file_path = Some(path.to_string()); // Set the file path if provided
            }
            None => {
                if self.file_path.is_none() {
                    return Err("No file path set.".into()); 
                }
            }
        }

        let path = self.file_path.as_ref().unwrap(); // Safely unwrap the file path
        self.file = Some(
            OpenOptions::new()
                .read(true) // Open the file for reading
                .write(true) // Open the file for writing
                .create(true) // Create the file if it doesn't exist
                .open(path)? // Open the file at the specified path
        );

        if let Some(ref mut file) = self.file {
            let mut buffer = Vec::new(); // Create a buffer to store file contents
            // file.seek(SeekFrom::Start(0))?; // TODO :doc
            file.read_to_end(&mut buffer)?; // Read the file content into the buffer
            if buffer.is_empty() {
                return Ok(Vec::new())
            }
            let data: Vec<KV> = bincode::deserialize(&buffer)?;
            return Ok(data); // Return the deserialized data
        } else {
           return Err("No file open to read data.".into())
        }
    }

    /// Saves the provided data to the file by serializing it into binary format.
    ///
    /// # Arguments
    ///
    /// * `data` - A vector of KV structs to be serialized and saved.
    ///
    /// # Returns
    ///
    /// * `Ok(())` - If the operation is successful.
    /// * `Err(Box<dyn Error>)` - An error message if the operation fails.
    pub fn save_file(&mut self, data: Vec<KV>) -> Result<(), Box<dyn Error>> {
        if let Some(ref mut file) = self.file {
            let buffer: Vec<u8> = bincode::serialize(&data)?; // Serialize the data into a binary buffer
            file.set_len(0)?; // Clear the content of the file
            file.seek(SeekFrom::Start(0))?; // Move the cursor to the beginning of the file
            file.write_all(&buffer)?; // Write the binary buffer to the file
            file.sync_all()?; // Sync all changes to the file
            Ok(())
        } else {
            Err("No file open to save data.".into()) // Return an error if no file is open
        }
    }
}