1use std::fs::File;
2use std::io::{Write, BufReader, BufRead};
3
4#[derive(Default)]
16pub struct BufData{
17 filepath:String,
18 data:Vec<DataType>,
19}
20enum DataType {
21 Notes(String),
22 Data((String,String)),
23}
24
25impl BufData {
26 pub fn new()->Self{
28 Self { filepath:"default.iii".to_string(),..Default::default() }
29 }
30 pub fn loadfromiii(filepath:&str)->Result<Self,&'static str>{
37 let mut data = Vec::new();
38 if let Ok(file)=File::open(filepath){
39 for idx in BufReader::new(file).lines(){
40 if let Ok(iidx) = idx{
41 if iidx.trim().starts_with("#"){
42 data.push(DataType::Notes(iidx));
43 }else{
44 let cc:Vec<&str> = iidx.trim().split("=").collect();
45 if cc.len() == 2{
46 data.push(DataType::Data((cc[0].trim().to_string(),cc[1].trim().to_string())));
47 }
48 }
49 }
50 }
51 Ok(Self{filepath:filepath.to_string(),data:data})
52 }else{
53 Err("load file fail")
54 }
55
56 }
57
58 fn onlywrite(&self,path:&str)->Result<(),&'static str>{
59 if let Ok(mut f) = File::create(path){
60 let mut bufstr = String::new();
61 for idx in &self.data{
62 match idx {
63 DataType::Data((s1,s2))=>{
64 bufstr.push_str(&format!("{} = {}\r\n",s1,s2));
65 },
66 DataType::Notes(commet)=>{
67 bufstr.push_str(&commet);
68 bufstr.push_str("\r\n");
69 },
70 }
71 }
72 if let Ok(_) = f.write(bufstr.as_bytes()){
73 return Ok(());
74 }
75 }
76 Err("write err")
77
78 }
79
80 pub fn save(&self,newfilepath:Option<&str>)->Result<(),&'static str>{
97 if let Some(pth) = newfilepath{
98 self.onlywrite(pth)
99 }else{
100 self.onlywrite(&self.filepath)
101 }
102 }
103 pub fn getvalue<T: std::str::FromStr>(&self,key:&str)->Result<T,()>{
116 for idx in &self.data{
117 if let DataType::Data((s1,s2))=idx{
118 if &key.to_string() == s1{
119 if let Ok(ss) = s2.parse::<T>(){
120 return Ok(ss);
121 }
122 }
123 }
124 }
125 return Err(());
126 }
127 pub fn chgvalue<T:std::fmt::Display>(&mut self,key:&str,value:T){
139 for idx in &mut self.data{
140 if let DataType::Data((s1,s2))=idx{
141 if &key.to_string() == s1{
142 s2.clear();
143 s2.push_str(&value.to_string());
144 return;
145 }
146 }
147 }
148 self.data.push(DataType::Data((key.to_string(),value.to_string())));
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn crate1(){
158 let mut cc = BufData::new();
159 cc.chgvalue("c1", "value");
160 cc.chgvalue("c2", "value2");
161 cc.chgvalue("c3", "value3");
162 if let Ok(_) = cc.save(None){
163 println!("file write success")
164 };
165 }
166 #[test]
167 fn readwrite(){
168 if let Ok(mut cc) = BufData::loadfromiii("default.iii"){
169 cc.chgvalue("c3", "ccc3");
170 cc.chgvalue("c5", "5c");
171 if let Ok(_) = cc.save(None){
172 println!("file write success")
173 };
174 };
175 }
176
177 #[test]
178 fn readvalue(){
179 if let Ok(cc) = BufData::loadfromiii("default.iii"){
180 if let Ok(v) = cc.getvalue::<String>("c2"){
181 println!("K:{},V:{}","c2",v);
182 }
183 if let Ok(v) = cc.getvalue::<String>("c5"){
184 println!("K:{},V:{}","c5",v);
185 }
186 };
187 }
188 #[test]
189 fn getnumbervalue()->Result<(),()>{
190 let mut cc = BufData::new();
191 cc.chgvalue("c2", "33");
192 cc.chgvalue("c4", &true.to_string());
193 let Ok(value) = cc.getvalue::<u32>("c2") else {return Err(())};
194 assert!(33==value);
195 let Ok(value) = cc.getvalue::<bool>("c4") else {return Err(());};
196 assert!(true==value);
197 Ok(())
198 }
199}