refmt/
lib.rs

1use std::io::Read;
2
3pub fn read(mut reader: impl Read) -> (String, bool) {
4  let mut buffer = [0; 1]; // Read one byte at a time
5
6  let mut change = false;
7  let mut li = Vec::new();
8  let mut line = Vec::new();
9
10  while let Ok(bytes_read) = xerr::ok!(reader.read(&mut buffer)) {
11    if bytes_read == 0 {
12      break;
13    }
14
15    let c = buffer[0];
16    match c {
17      b'\n' => {
18        let t = String::from_utf8_lossy(&line);
19        let trimmed_line = t.trim_end();
20        if trimmed_line.len() != t.len() {
21          change = true;
22        }
23        li.push(trimmed_line.to_owned());
24        line.clear();
25      }
26      b'\r' => {
27        change = true;
28        let t = String::from_utf8_lossy(&line);
29        let trimmed_line = t.trim_end();
30        li.push(trimmed_line.to_owned());
31        line.clear();
32        if let Ok(bytes_read) = xerr::ok!(reader.read(&mut buffer)) {
33          if bytes_read > 0 {
34            let c = buffer[0];
35            if c != b'\n' {
36              // Skip the next \n
37              if c == b'\r' {
38                li.push("".into());
39              } else {
40                line.push(c);
41              }
42            }
43          }
44        }
45      }
46      b'\0' => {
47        // 不能包含 '\0' 因为用这个做缓存的占位符
48        change = true;
49      }
50      _ => {
51        line.push(c);
52      }
53    }
54  }
55
56  if !line.is_empty() {
57    let t = String::from_utf8_lossy(&line);
58    let trimmed_line = t.trim_end();
59    if trimmed_line.len() != t.len() {
60      change = true;
61    }
62    li.push(trimmed_line.to_owned());
63  }
64
65  while let Some(i) = li.last() {
66    if i.is_empty() {
67      change = true;
68      li.pop();
69    } else {
70      break;
71    }
72  }
73
74  let txt = li.join("\n");
75  (txt, change)
76}
77
78#[cfg(feature = "fs")]
79pub fn fp(fp: impl AsRef<std::path::Path>) -> std::io::Result<String> {
80  use std::{
81    fs::File,
82    io::{BufReader, Write},
83  };
84  let file = File::open(&fp)?;
85  let mut reader = BufReader::new(file);
86  let (txt, change) = read(&mut reader);
87  if change {
88    let mut file = File::create(fp)?;
89    file.write_all(txt.as_bytes())?;
90  }
91
92  Ok(txt)
93}
94
95#[cfg(feature = "str")]
96pub fn str(txt: impl AsRef<str>) -> (String, bool) {
97  use std::io::Cursor;
98  let txt = txt.as_ref();
99  read(Cursor::new(txt))
100}