1use std::cell::RefCell;
11use std::rc::Rc;
12
13use deno_core::OpState;
14
15#[derive(Clone, Debug)]
17pub enum GeoCommand {
18 Triangle {
19 x1: f32, y1: f32,
20 x2: f32, y2: f32,
21 x3: f32, y3: f32,
22 r: f32, g: f32, b: f32, a: f32,
23 layer: i32,
24 },
25 LineSeg {
26 x1: f32, y1: f32,
27 x2: f32, y2: f32,
28 thickness: f32,
29 r: f32, g: f32, b: f32, a: f32,
30 layer: i32,
31 },
32}
33
34impl GeoCommand {
35 pub fn layer(&self) -> i32 {
36 match self {
37 GeoCommand::Triangle { layer, .. } => *layer,
38 GeoCommand::LineSeg { layer, .. } => *layer,
39 }
40 }
41}
42
43pub struct GeoState {
45 pub commands: Vec<GeoCommand>,
46}
47
48impl GeoState {
49 pub fn new() -> Self {
50 Self { commands: Vec::new() }
51 }
52}
53
54#[deno_core::op2(fast)]
57fn op_geo_triangle(
58 state: &mut OpState,
59 x1: f64, y1: f64,
60 x2: f64, y2: f64,
61 x3: f64, y3: f64,
62 r: f64, g: f64, b: f64, a: f64,
63 layer: f64,
64) {
65 let geo = state.borrow::<Rc<RefCell<GeoState>>>();
66 geo.borrow_mut().commands.push(GeoCommand::Triangle {
67 x1: x1 as f32, y1: y1 as f32,
68 x2: x2 as f32, y2: y2 as f32,
69 x3: x3 as f32, y3: y3 as f32,
70 r: r as f32, g: g as f32, b: b as f32, a: a as f32,
71 layer: layer as i32,
72 });
73}
74
75#[deno_core::op2(fast)]
79fn op_geo_line(
80 state: &mut OpState,
81 x1: f64, y1: f64,
82 x2: f64, y2: f64,
83 thickness: f64,
84 r: f64, g: f64, b: f64, a: f64,
85 layer: f64,
86) {
87 let geo = state.borrow::<Rc<RefCell<GeoState>>>();
88 geo.borrow_mut().commands.push(GeoCommand::LineSeg {
89 x1: x1 as f32, y1: y1 as f32,
90 x2: x2 as f32, y2: y2 as f32,
91 thickness: thickness as f32,
92 r: r as f32, g: g as f32, b: b as f32, a: a as f32,
93 layer: layer as i32,
94 });
95}
96
97deno_core::extension!(
98 geometry_ext,
99 ops = [
100 op_geo_triangle,
101 op_geo_line,
102 ],
103);
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_geo_command_triangle_layer() {
111 let cmd = GeoCommand::Triangle {
112 x1: 0.0, y1: 0.0,
113 x2: 10.0, y2: 0.0,
114 x3: 5.0, y3: 10.0,
115 r: 1.0, g: 0.0, b: 0.0, a: 1.0,
116 layer: 5,
117 };
118 assert_eq!(cmd.layer(), 5);
119 }
120
121 #[test]
122 fn test_geo_command_line_layer() {
123 let cmd = GeoCommand::LineSeg {
124 x1: 0.0, y1: 0.0,
125 x2: 100.0, y2: 100.0,
126 thickness: 2.0,
127 r: 0.0, g: 1.0, b: 0.0, a: 0.5,
128 layer: 10,
129 };
130 assert_eq!(cmd.layer(), 10);
131 }
132
133 #[test]
134 fn test_geo_state_new() {
135 let state = GeoState::new();
136 assert!(state.commands.is_empty());
137 }
138
139 #[test]
140 fn test_geo_state_add_commands() {
141 let mut state = GeoState::new();
142
143 state.commands.push(GeoCommand::Triangle {
144 x1: 0.0, y1: 0.0, x2: 10.0, y2: 0.0, x3: 5.0, y3: 10.0,
145 r: 1.0, g: 1.0, b: 1.0, a: 1.0, layer: 0,
146 });
147
148 state.commands.push(GeoCommand::LineSeg {
149 x1: 0.0, y1: 0.0, x2: 50.0, y2: 50.0,
150 thickness: 3.0, r: 0.5, g: 0.5, b: 0.5, a: 1.0, layer: 1,
151 });
152
153 assert_eq!(state.commands.len(), 2);
154 assert_eq!(state.commands[0].layer(), 0);
155 assert_eq!(state.commands[1].layer(), 1);
156 }
157
158 #[test]
159 fn test_geo_state_drain() {
160 let mut state = GeoState::new();
161
162 state.commands.push(GeoCommand::Triangle {
163 x1: 0.0, y1: 0.0, x2: 10.0, y2: 0.0, x3: 5.0, y3: 10.0,
164 r: 1.0, g: 0.0, b: 0.0, a: 1.0, layer: 0,
165 });
166
167 let drained: Vec<_> = state.commands.drain(..).collect();
168 assert_eq!(drained.len(), 1);
169 assert!(state.commands.is_empty());
170 }
171}