nmd_core/resource/
cached_disk_resource.rs

1use std::{path::PathBuf, str::FromStr};
2
3use super::{disk_resource::DiskResource, ResourceError, Resource};
4
5
6
7/// Resource which uses filesystem to store information. It use simple cache logics avoid duplicating read and write operations
8#[derive(Debug, Clone)]
9pub struct CachedDiskResource {
10    name: String, 
11    location: PathBuf,
12    shadow_resource: DiskResource,
13    cached_content: Option<String>
14}
15
16impl FromStr for CachedDiskResource {
17    type Err = ResourceError;
18
19    fn from_str(path: &str) -> Result<Self, Self::Err> {
20
21        if path.is_empty() {
22            return Err(ResourceError::Creation("resource cannot be an empty string".to_string()));
23        }
24
25        Self::try_from(PathBuf::from_str(path).unwrap())
26    }
27}
28
29
30impl ToString for CachedDiskResource {
31    fn to_string(&self) -> String {
32        self.location().to_string_lossy().to_string()
33    }
34}
35
36impl TryFrom<PathBuf> for CachedDiskResource {
37    type Error = ResourceError;
38
39    fn try_from(location: PathBuf) -> Result<Self, Self::Error> {
40        if location.is_dir() {
41            return Err(ResourceError::InvalidResourceVerbose(format!("{} is a directory", location.to_string_lossy())))
42        }
43
44        if let Some(name) = location.file_name() {
45
46            let l = location.clone();
47
48            Ok(Self {
49                name: name.to_string_lossy().to_string(),
50                location: l.clone(),
51                shadow_resource: DiskResource::try_from(l)?,
52                cached_content: Option::None
53            })
54        } else {
55            Err(ResourceError::InvalidResource)
56        }
57    }
58}
59
60
61#[allow(dead_code)]
62impl CachedDiskResource {
63    fn new(location: PathBuf) -> Result<Self, ResourceError> {
64
65        Self::try_from(location)
66    }
67
68    pub fn cached_content(&self) -> &Option<String> {
69        &self.cached_content
70    }
71
72    pub fn set_cached_content(&mut self, content: &str) -> () {
73        self.cached_content = Some(content.to_string())
74    }
75
76    pub fn append_to_cached_content(&mut self, content: &str) -> () {
77        if self.cached_content.is_some() {
78            self.cached_content = Option::Some(self.cached_content.clone().unwrap() + content);
79            
80        } else {
81            self.cached_content = Option::Some(content.to_string())
82        }
83    }
84
85    pub fn dump_cached_content(&mut self) -> Result<(), ResourceError> {
86        self.shadow_resource.write(self.cached_content.as_ref().unwrap().as_str())
87    }
88
89    pub fn clear_cached_content(&mut self) -> () {
90        self.cached_content = Option::None
91    }
92
93    pub fn refresh_cached_content(&mut self) -> Result<(), ResourceError> {
94        self.cached_content = Option::Some(self.shadow_resource.read()?);
95
96        Ok(())   
97    }
98}
99
100impl Resource for CachedDiskResource {
101    type LocationType = PathBuf;
102
103    fn write(&mut self, content: &str) -> Result<(), ResourceError> {
104
105        self.set_cached_content(content);
106
107        self.shadow_resource.write(self.cached_content.as_ref().unwrap().as_str())
108    }
109
110    fn append(&mut self, content: &str) -> Result<(), ResourceError> {
111
112        self.append_to_cached_content(content);
113
114        self.shadow_resource.append(self.cached_content.as_ref().unwrap().as_str())
115    }
116
117    fn read(&self) -> Result<String, ResourceError> {
118
119        match &self.cached_content {
120            Some(content) => Ok(content.clone()),
121            None => self.shadow_resource.read()
122        }
123    }
124
125    fn name(&self) -> &String {
126        &self.name
127    }
128
129    fn location(&self) -> &Self::LocationType {
130        &self.location
131    }
132
133    fn erase(&mut self) -> Result<(), ResourceError> {
134        self.shadow_resource.erase()
135    }
136}