Skip to content

Commit 75e43ea

Browse files
committed
implement remotes + large rewrite
1 parent 57f8be1 commit 75e43ea

File tree

22 files changed

+1565
-1238
lines changed

22 files changed

+1565
-1238
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"luau-lsp.sourcemap.enabled": false,
3-
"luau-lsp.types.definitionFiles": ["src/zap.d.luau"]
3+
"luau-lsp.types.definitionFiles": ["src/zap.d.luau"],
4+
"luau-lsp.ignoreGlobs": ["src/*"],
45
}

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ edition = "2024"
55

66
[dependencies]
77
clap = { version = "4.5", features = ["derive"] }
8-
lu = "0.4"
8+
lu = "0.5.1"
99
uuid = { version = "1.17", features = ["v4"] }
1010

1111
[build-dependencies]

src/api.rs

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
use std::{ops::ControlFlow, rc::Rc};
1+
use std::ops::ControlFlow;
22

3-
use uuid::Uuid;
3+
use lu::Methods;
44

5-
use crate::shared::{ApiCheck, Casing, NetworkSide, NumberKind, Options, Range};
5+
use crate::{
6+
options,
7+
shared::{ApiCheck, Casing, NetworkSide, NumberKind, Range, Remote},
8+
};
69

710
#[derive(Default)]
811
struct Config;
@@ -22,9 +25,13 @@ pub fn exec(source: &[u8]) -> Result<Table, String> {
2225

2326
let mut state = lu::State::new((), lu::DefaultAllocator);
2427
state.open_std();
25-
state.open_userdata::<Type>();
26-
state.open_userdata::<Event>();
27-
state.open_userdata::<Options>();
28+
state.open_userdata::<Type>(Methods::default());
29+
state.open_userdata::<Event>(Methods::default());
30+
state.open_userdata::<OptionUserdata>(Methods::default());
31+
state.open_userdata::<RemoteUserdata>(Methods::default().with_method(
32+
"event",
33+
lu::Function::norm("RemoteUserdata::event", RemoteUserdata::event),
34+
));
2835
state.open_library("zap", library());
2936
state.sandbox();
3037

@@ -52,7 +59,7 @@ pub fn exec(source: &[u8]) -> Result<Table, String> {
5259
Err(format!("yielded: {trace}"))
5360
},
5461

55-
_ => table(stack, Rc::new(Options::default())),
62+
_ => table(stack),
5663
}
5764
}
5865

@@ -62,14 +69,14 @@ pub enum Item {
6269
Event(Event),
6370
}
6471

65-
fn table(stack: &lu::Stack<Config>, parent: Rc<Options>) -> Result<Table, String> {
66-
let mut options = Rc::new(Options::default().with_parent(parent));
72+
fn table(stack: &lu::Stack<Config>) -> Result<Table, String> {
73+
let mut options = options::Node::from(options::Partial::default());
6774
let mut items = Vec::new();
6875

6976
let result = stack.iter(-1, || {
7077
if stack.to_number(-2).is_some_and(|n| n == 1.0) {
71-
options = match stack.to_userdata::<Options>(-1) {
72-
Some(options) => Rc::new(options.borrow().clone()),
78+
options = match stack.to_userdata::<OptionUserdata>(-1) {
79+
Some(options) => options.borrow().0.clone(),
7380
None => return ControlFlow::Break("index 1 may only contain options".to_string()),
7481
};
7582
} else {
@@ -79,11 +86,12 @@ fn table(stack: &lu::Stack<Config>, parent: Rc<Options>) -> Result<Table, String
7986

8087
match stack.type_of(-1) {
8188
lu::Type::Table => {
82-
let table = match table(stack, options.clone()) {
89+
let table = match table(stack) {
8390
Ok(table) => table,
8491
Err(err) => return ControlFlow::Break(err),
8592
};
8693

94+
table.opts.set_parent(options.clone());
8795
items.push((name.to_owned(), Item::Table(table)));
8896
}
8997

@@ -107,7 +115,10 @@ fn table(stack: &lu::Stack<Config>, parent: Rc<Options>) -> Result<Table, String
107115
if let Some(err) = result {
108116
Err(err)
109117
} else {
110-
Ok(Table { options, items })
118+
Ok(Table {
119+
opts: options,
120+
items,
121+
})
111122
}
112123
}
113124

@@ -118,7 +129,7 @@ fn library() -> lu::Library<Config> {
118129

119130
lu::Library::default()
120131
.with_function_norm("options", options)
121-
.with_function_norm("event", event)
132+
.with_function_norm("remote", remote)
122133
.with_function_norm("boolean", boolean)
123134
.with_function_norm("u8", u8)
124135
.with_function_norm("u16", u16)
@@ -143,12 +154,15 @@ fn library() -> lu::Library<Config> {
143154

144155
#[derive(Clone)]
145156
pub struct Table {
146-
pub options: Rc<Options>,
157+
pub opts: options::Node,
147158
pub items: Vec<(String, Item)>,
148159
}
149160

161+
#[derive(lu::Userdata)]
162+
pub struct OptionUserdata(options::Node);
163+
150164
extern "C-unwind" fn options(ctx: Context) -> lu::FnReturn {
151-
let mut options = Options::default();
165+
let mut options = options::Partial::default();
152166
ctx.arg_table(1);
153167

154168
ctx.iter(1, || {
@@ -162,7 +176,7 @@ extern "C-unwind" fn options(ctx: Context) -> lu::FnReturn {
162176
_ => ctx.error_msg("apicheck must be 'none', 'some', or 'full'"),
163177
};
164178

165-
options = options.clone().with_apicheck(value);
179+
options.apicheck = Some(value)
166180
}
167181

168182
Some("casing") => {
@@ -175,7 +189,7 @@ extern "C-unwind" fn options(ctx: Context) -> lu::FnReturn {
175189
_ => ctx.error_msg("casing must be 'lower', 'snake', 'camel', or 'pascal'"),
176190
};
177191

178-
options = options.clone().with_casing(value);
192+
options.casing = Some(value);
179193
}
180194

181195
Some(str) => ctx.error_msg(format!("unknown option: {str}")),
@@ -185,45 +199,57 @@ extern "C-unwind" fn options(ctx: Context) -> lu::FnReturn {
185199
ControlFlow::<()>::Continue(())
186200
});
187201

188-
ctx.push_userdata(options);
202+
ctx.push_userdata(OptionUserdata(options::Node::from(options)));
189203
ctx.ret_with(1)
190204
}
191205

192206
#[derive(lu::Userdata, Clone)]
193207
pub struct Event {
194-
pub uuid: Uuid,
208+
pub thru: Remote,
195209
pub from: NetworkSide,
196210
pub data: Vec<Type>,
197211
}
198212

199-
extern "C-unwind" fn event(ctx: Context) -> lu::FnReturn {
200-
let from = ctx.arg_string_str(1);
201-
ctx.arg_table(2);
213+
#[derive(lu::Userdata)]
214+
pub struct RemoteUserdata(Remote);
202215

203-
let uuid = Uuid::new_v4();
204-
let from = match from {
205-
"server" => NetworkSide::Server,
206-
"client" => NetworkSide::Client,
216+
impl RemoteUserdata {
217+
extern "C-unwind" fn event(ctx: Context) -> lu::FnReturn {
218+
let remote = ctx.arg_userdata::<RemoteUserdata>(1);
219+
let from = ctx.arg_string_str(2);
220+
ctx.arg_table(3);
207221

208-
_ => ctx.arg_error(1, c"must be 'server' or 'client'"),
209-
};
222+
let thru = remote.borrow().0.clone();
210223

211-
let mut data = Vec::new();
212-
ctx.iter(2, || {
213-
if !ctx.is_number(-2) {
214-
ctx.error_msg("event data must be an array")
215-
}
224+
let from = match from {
225+
"server" => NetworkSide::Server,
226+
"client" => NetworkSide::Client,
216227

217-
if let Some(item) = ctx.to_userdata::<Type>(-1) {
218-
data.push(item.borrow().clone());
219-
} else {
220-
ctx.error_msg("event data must be a type");
221-
}
228+
_ => ctx.arg_error(2, c"must be 'server' or 'client'"),
229+
};
222230

223-
ControlFlow::<()>::Continue(())
224-
});
231+
let mut data = Vec::new();
232+
ctx.iter(3, || {
233+
if !ctx.is_number(-2) {
234+
ctx.error_msg("event data must be an array")
235+
}
236+
237+
if let Some(item) = ctx.to_userdata::<Type>(-1) {
238+
data.push(item.borrow().clone());
239+
} else {
240+
ctx.error_msg("event data must be a type");
241+
}
242+
243+
ControlFlow::<()>::Continue(())
244+
});
245+
246+
ctx.push_userdata(Event { thru, from, data });
247+
ctx.ret_with(1)
248+
}
249+
}
225250

226-
ctx.push_userdata(Event { uuid, from, data });
251+
extern "C-unwind" fn remote(ctx: Context) -> lu::FnReturn {
252+
ctx.push_userdata(RemoteUserdata(Remote::default()));
227253
ctx.ret_with(1)
228254
}
229255

src/footer.luau

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
exportmt.__index = nil
2+
return export

src/header.luau

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
--!nocheck
22
--!nolint
33
-- This file was generated by zap
4-
local buf, pos, len = buffer.create(1024), 0, 1024
4+
local exportmt = {
5+
__index = function(self, key)
6+
self[key] = setmetatable({}, exportmt)
7+
end
8+
}
9+
local export = setmetatable({}, exportmt)
510
local bit = { [true] = 1, [false] = 0 }
6-
local function resize(bytes)
7-
local newlen = pos * 2
11+
local function resize(buf, pos, len, bytes)
12+
local newlen = len * 2
813
if newlen < pos + bytes then
914
newlen = pos + bytes
1015
end
1116
local newbuf = buffer.create(newlen)
1217
buffer.copy(newbuf, 0, buf, 0, pos)
13-
buf, len = newbuf, newlen
18+
return newbuf, newlen
1419
end

src/hir/build.rs

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,47 @@
1+
use std::collections::HashMap;
2+
13
use crate::{
24
api,
35
hir::{
4-
ArrayType, BinaryStringType, BooleanType, EnumType, Event, Item, Length, MapType,
5-
NumberType, SetType, StructType, Table, Type, Utf8StringType, VectorType,
6+
ArrayType, BinaryStringType, BooleanType, EnumType, Event, Hir, Item, Length, MapType,
7+
NumberType, SetType, StructType, Type, Utf8StringType, VectorType,
68
},
7-
shared::Range,
9+
shared::{Range, Remote},
810
};
911

10-
impl From<api::Item> for Item {
11-
fn from(value: api::Item) -> Self {
12-
match value {
13-
api::Item::Table(table) => Item::Table(table.into()),
14-
api::Item::Event(event) => Item::Event(event.into()),
15-
}
16-
}
17-
}
12+
pub fn build(table: api::Table) -> Hir {
13+
fn build(buckets: &mut HashMap<Remote, Vec<Item>>, path: String, table: api::Table) {
14+
let opts = table.opts.resolved();
1815

19-
impl From<api::Table> for Table {
20-
fn from(value: api::Table) -> Self {
21-
let options = value.options;
22-
let items = value
23-
.items
24-
.into_iter()
25-
.map(|(name, item)| (name, Item::from(item)))
26-
.collect();
16+
for (name, item) in table.items {
17+
let path = format!("{path}.{name}");
2718

28-
Table { options, items }
29-
}
30-
}
19+
match item {
20+
api::Item::Table(table) => build(buckets, path, table),
21+
22+
api::Item::Event(api::Event { thru, from, data }) => {
23+
let data = data.into_iter().map(Type::from).collect();
3124

32-
impl From<api::Event> for Event {
33-
fn from(value: api::Event) -> Self {
34-
let uuid = value.uuid;
35-
let from = value.from;
36-
let data = value.data.into_iter().map(Type::from).collect();
25+
let event = Event {
26+
opts: opts.clone(),
27+
path,
28+
from,
29+
data,
30+
};
3731

38-
Event { uuid, from, data }
32+
buckets
33+
.entry(thru.clone())
34+
.or_default()
35+
.push(Item::Event(event));
36+
}
37+
}
38+
}
3939
}
40+
41+
let mut buckets = HashMap::new();
42+
build(&mut buckets, String::new(), table);
43+
44+
Hir { buckets }
4045
}
4146

4247
impl From<api::Type> for Type {

src/hir/mod.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
1-
use std::rc::Rc;
1+
use std::collections::HashMap;
22

3-
use uuid::Uuid;
4-
5-
use crate::shared::{NetworkSide, NumberKind, Options, Range};
3+
use crate::{
4+
options::Options,
5+
shared::{NetworkSide, NumberKind, Range, Remote},
6+
};
67

78
mod build;
89
mod size;
910

10-
#[derive(Clone)]
11-
pub enum Item {
12-
Table(Table),
13-
Event(Event),
11+
pub use build::build;
12+
13+
pub struct Hir {
14+
pub buckets: HashMap<Remote, Vec<Item>>,
1415
}
1516

1617
#[derive(Clone)]
17-
pub struct Table {
18-
pub options: Rc<Options>,
19-
pub items: Vec<(String, Item)>,
18+
pub enum Item {
19+
Event(Event),
2020
}
2121

2222
#[derive(Clone)]
2323
pub struct Event {
24-
pub uuid: Uuid,
24+
pub opts: Options,
25+
pub path: String,
2526
pub from: NetworkSide,
2627
pub data: Vec<Type>,
2728
}

0 commit comments

Comments
 (0)