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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
//! 假网络发送器:读写在固定内存缓冲中完成
//! (对标 libs/server/Lua/ScratchBufferNetworkSender.cs:ScratchBufferNetworkSender)。
//!
//! C# 经 INetworkSender 把 redis.call 的响应字节写进 ScratchBufferBuilder
//! 的剩余空间(head/tail 裸指针视图);Rust 侧以安全切片视图承接同语义:
//! [`ScratchBufferNetworkSender::spare_capacity_mut`] 写入 +
//! [`ScratchBufferNetworkSender::send_response`] 推进有效区。
/// 发送缓冲上限(对标 BufferSizeUtils.ServerBufferSize 默认档位)。
pub const SERVER_BUFFER_SIZE: usize = 16 * 1024;
/// 最大尺寸设置(C# MaxSizeSettings 的接收/发送档位)。
#[derive(Debug, Clone, Copy)]
pub struct MaxSizeSettings {
/// 接收缓冲尺寸。
pub receive_buffer_size: usize,
/// 发送缓冲尺寸。
pub send_buffer_size: usize,
/// 最大发送页尺寸。
pub max_send_size: usize,
}
impl Default for MaxSizeSettings {
fn default() -> Self {
Self {
receive_buffer_size: 512 * 1024,
send_buffer_size: 16 * 1024,
max_send_size: 16 * 1024,
}
}
}
/// 假网络发送器:响应字节累积于内存缓冲。
pub struct ScratchBufferNetworkSender {
/// 已写入的有效字节(有效区 = buffer[..offset])。
buffer: Vec<u8>,
/// 有效区长度(C# ScratchBufferBuilder 的 offset 语义)。
offset: usize,
/// 最大尺寸设置。
max_size_settings: MaxSizeSettings,
/// 服务端缓冲容量。
server_buffer_size: usize,
}
impl Default for ScratchBufferNetworkSender {
fn default() -> Self {
Self::new()
}
}
impl ScratchBufferNetworkSender {
/// Create a new dummy network sender with a simple in-memory buffer
///
/// libs/server/Lua/ScratchBufferNetworkSender.cs:ScratchBufferNetworkSender
pub fn new() -> Self {
let max_size_settings = MaxSizeSettings::default();
Self {
buffer: Vec::with_capacity(SERVER_BUFFER_SIZE),
offset: 0,
server_buffer_size: SERVER_BUFFER_SIZE,
max_size_settings,
}
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:Reset
///
/// 清空有效区(C# ScratchBufferBuilder.Reset)。
pub fn reset(&mut self) {
self.buffer.clear();
self.offset = 0;
}
/// 服务端缓冲容量(构造时由 MaxSizeSettings 折算)。
pub fn server_buffer_size(&self) -> usize {
self.server_buffer_size
}
/// 最大尺寸设置。
pub fn max_size_settings(&self) -> &MaxSizeSettings {
&self.max_size_settings
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:GetResponse
///
/// 取当前已写出的完整响应字节(ViewFullArgSlice)。
pub fn get_response(&self) -> &[u8] {
&self.buffer[..self.offset]
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:IsLocalConnection
///
/// 假发送器恒为本机连接。
pub fn is_local_connection(&self) -> bool {
true
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:DisposeNetworkSender
///
/// 内存缓冲无需清理(C# 空方法)。
pub fn dispose_network_sender(&mut self, _wait_for_send_completion: bool) {}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:Enter
///
/// 进入响应写区(C# 空方法)。
pub fn enter(&mut self) {}
/// 剩余可写空间的安全视图(C# head..tail 裸指针区间的切片形态)。
/// 写入后经 [`Self::send_response`] 提交推进有效区。
pub fn spare_capacity_mut(&mut self) -> &mut [u8] {
self.ensure_capacity();
&mut self.buffer[self.offset..self.server_buffer_size]
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:EnterAndGetResponseObject
///
/// 剩余可写空间视图(C# head..tail 裸指针区间的安全形态):
/// 返回 (可写切片, 可写字节数);写入后经 [`Self::send_response`] 提交。
pub fn enter_and_get_response_object(&mut self) -> (&mut [u8], usize) {
let spare = self.spare_capacity_mut();
let tail = spare.len();
(spare, tail)
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:GetResponseObjectHead
///
/// 剩余空间首指针(C# head 裸指针形态;写入经 spare_capacity_mut 安全承接)。
pub fn get_response_object_head(&mut self) -> *mut u8 {
self.ensure_capacity();
unsafe { self.buffer.as_mut_ptr().add(self.offset) }
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:GetResponseObjectTail
///
/// 剩余空间尾指针。
pub fn get_response_object_tail(&mut self) -> *const u8 {
self.ensure_capacity();
unsafe { self.buffer.as_ptr().add(self.server_buffer_size) }
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:Exit
///
/// 退出响应写区(C# 空方法)。
pub fn exit(&mut self) {}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:ExitAndReturnResponseObject
///
/// 交还响应对象(C# 空方法)。
pub fn exit_and_return_response_object(&mut self) {}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:GetResponseObject
///
/// 取响应对象(C# 空方法)。
pub fn get_response_object(&mut self) {}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:ReturnResponseObject
///
/// 归还响应对象(C# 空方法)。
pub fn return_response_object(&mut self) {}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:SendCallback
///
/// 发送回调(C# 空方法)。
pub fn send_callback(&mut self) {}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:SendResponse
///
/// 以 `offset`(相对有效区末尾的起始)+ `size` 推进有效区
/// (C# ScratchBufferBuilder.MoveOffset(offset + size))。
pub fn send_response(&mut self, offset: usize, size: usize) -> bool {
let advanced = self.offset.saturating_add(offset.saturating_add(size));
self.offset = advanced.min(self.server_buffer_size);
true
}
/// 直写响应字节(RespWriteUtils 写入面的安全承接,
/// ScriptingApi 实现方把序列化结果直接落入发送缓冲)。
pub fn write_response_bytes(&mut self, bytes: &[u8]) {
self.buffer.extend_from_slice(bytes);
self.offset = self.buffer.len().min(self.server_buffer_size);
}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:Throttle
///
/// 背压节流(C# 空方法)。
pub fn throttle(&mut self) {}
/// libs/server/Lua/ScratchBufferNetworkSender.cs:TryClose
///
/// 假发送器无连接可关。
pub fn try_close(&mut self) -> bool {
false
}
/// 容量保障(剩余空间视图的前提)。
fn ensure_capacity(&mut self) {
if self.buffer.len() < self.server_buffer_size {
self.buffer.resize(self.server_buffer_size, 0);
}
}
}
/// RESP 请求拼装缓冲(对标 Garnet.common ScratchBufferBuilder 的命令拼装面)。
#[derive(Default)]
pub struct ScratchBufferBuilder {
/// 已拼装字节。
buffer: Vec<u8>,
}
impl ScratchBufferBuilder {
/// libs/server/Lua/LuaRunner.Functions.cs:StartCommand(经 ScratchBufferBuilder)
///
/// 以 RESP 数组形态起头:`*N\r\n`。
pub fn start_command(&mut self, command: &[u8], arg_count: usize) {
self.buffer.push(b'*');
self.write_decimal(arg_count + 1);
self.write_arg_inner(command);
}
/// libs/server/Lua/LuaRunner.Functions.cs:WriteArgument(经 ScratchBufferBuilder)
pub fn write_argument(&mut self, arg: &[u8]) {
self.write_arg_inner(arg);
}
/// libs/server/Lua/LuaRunner.Functions.cs:WriteNullArgument(经 ScratchBufferBuilder)
pub fn write_null_argument(&mut self) {
self.buffer.extend_from_slice(b"$-1\r\n");
}
/// libs/server/Lua/LuaRunner.Functions.cs:ViewFullArgSlice
pub fn view_full_arg_slice(&self) -> &[u8] {
&self.buffer
}
/// libs/server/Lua/LuaRunner.Functions.cs:Reset
pub fn reset(&mut self) {
self.buffer.clear();
}
/// 原样追加字节(对标 C# ViewRemainingArgSlice + MoveOffset 的直写形态,
/// cjson/cmsgpack/struct 编码层使用)。
pub fn append(&mut self, bytes: &[u8]) {
self.buffer.extend_from_slice(bytes);
}
/// 追加单字节。
pub fn append_byte(&mut self, byte: u8) {
self.buffer.push(byte);
}
/// `$len\r\n` + 字节 + `\r\n`。
fn write_arg_inner(&mut self, arg: &[u8]) {
self.buffer.push(b'$');
self.write_decimal(arg.len());
self.buffer.extend_from_slice(arg);
self.buffer.extend_from_slice(b"\r\n");
}
/// 十进制正文(无前导零)。
fn write_decimal(&mut self, value: usize) {
let mut buffer = itoa::Buffer::new();
self
.buffer
.extend_from_slice(buffer.format(value).as_bytes());
self.buffer.extend_from_slice(b"\r\n");
}
}
#[cfg(test)]
mod tests {
use super::{ScratchBufferBuilder, ScratchBufferNetworkSender};
#[test]
fn sender_response_region() {
let mut sender = ScratchBufferNetworkSender::new();
assert!(sender.is_local_connection());
assert!(!sender.try_close());
// 剩余空间视图 → 写入 → SendResponse 推进有效区。
sender.enter();
sender.spare_capacity_mut()[..4].copy_from_slice(b"+OK\r");
sender.exit_and_return_response_object();
assert!(sender.send_response(0, 4));
assert_eq!(sender.get_response(), b"+OK\r");
sender.return_response_object();
sender.exit();
sender.get_response_object();
sender.send_callback();
sender.throttle();
sender.dispose_network_sender(false);
sender.reset();
assert!(sender.get_response().is_empty());
}
#[test]
fn sender_direct_write_clamps_to_buffer_size() {
let mut sender = ScratchBufferNetworkSender::new();
sender.write_response_bytes(b"+PONG\r\n");
assert_eq!(sender.get_response(), b"+PONG\r\n");
// 超量直写截断在服务端缓冲容量内(C# 缓冲上限语义)。
let big = vec![b'a'; sender.server_buffer_size() + 16];
sender.write_response_bytes(&big);
assert_eq!(sender.get_response().len(), sender.server_buffer_size());
sender.reset();
assert!(sender.get_response().is_empty());
}
#[test]
fn builder_formats_resp_array() {
let mut builder = ScratchBufferBuilder::default();
builder.start_command(b"SET", 2);
builder.write_argument(b"k");
builder.write_null_argument();
assert_eq!(
builder.view_full_arg_slice(),
b"*3\r\n$3\r\nSET\r\n$1\r\nk\r\n$-1\r\n"
);
builder.reset();
assert_eq!(builder.view_full_arg_slice(), b"");
}
}