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
|
use std::{
cell::RefCell,
fs::File,
io::{
Read,
Seek,
Write
},
rc::Rc,
str::FromStr,
};
use html_escape::decode_html_entities_to_string;
use mlua::prelude::*;
use serde::Serialize;
pub fn decode_html(_: &Lua, string: String) -> LuaResult<String> {
let mut output = String::new();
decode_html_entities_to_string(string, &mut output);
Ok(output)
}
enum ReadMode {
Line,
Number,
All,
}
impl FromStr for ReadMode {
type Err = ();
fn from_str(value: &str) -> Result<Self, Self::Err> {
Ok(match value {
"l" => Self::Line,
"n" => Self::Number,
_ => Self::All,
})
}
}
#[derive(Serialize)]
#[serde(untagged)]
enum StringOrNumber {
String(String),
Number(u64),
}
pub struct FileHandle(Rc<RefCell<File>>);
impl LuaUserData for FileHandle {
fn add_methods<'lua, M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_method("read", |lua, this: &FileHandle, mode: String| {
let content = this.read()?;
Ok(lua.to_value(&match ReadMode::from_str(&mode).unwrap() {
ReadMode::Line => StringOrNumber::String(
content
.lines()
.next()
.map_or_else(String::new, |slice| slice.trim().to_owned()),
),
ReadMode::Number => StringOrNumber::Number(
content.trim().parse::<u64>().map_err(LuaError::external)?,
),
ReadMode::All => StringOrNumber::String(content),
}))
});
methods.add_method("write", |_, this: &FileHandle, content: String| {
this.write(content.as_bytes())
});
methods.add_method("lines", |_, this: &FileHandle, (): ()| {
Ok(this
.read()?
.lines()
.map(ToOwned::to_owned)
.collect::<Vec<String>>())
});
methods.add_method("rewind", |_, this: &FileHandle, (): ()| this.rewind());
}
}
impl FileHandle {
pub fn new(_: &Lua, path: String) -> LuaResult<Self> {
Ok(Self(Rc::new(RefCell::new(File::open(path)?))))
// Ok(Self(Rc::new(RefCell::new(OpenOptions::new().write(true).read(true).open(path)?))))
}
fn read(&self) -> LuaResult<String> {
let mut content = String::new();
self.0.borrow_mut().read_to_string(&mut content)?;
Ok(content)
}
fn rewind(&self) -> LuaResult<()> {
self.0.borrow_mut().rewind().map_err(LuaError::external)
}
fn write(&self, buf: &[u8]) -> LuaResult<usize> {
self.0.borrow_mut().write(buf).map_err(LuaError::external)
}
}
|