siglus_scene_vm/runtime/forms/
int_list.rs1use crate::runtime::{CommandContext, Value};
2use anyhow::Result;
3
4fn ensure_len(v: &mut Vec<i64>, idx: usize) {
5 if v.len() <= idx {
6 v.resize(idx + 1, 0);
7 }
8}
9
10fn bit_unit(bit: i32) -> i32 {
11 if bit <= 0 {
12 32
13 } else {
14 bit
15 }
16}
17
18fn get_bit_width(ctx: &mut CommandContext, form_id: u32, op: i32) -> i32 {
19 if op == ctx.ids.elm_array {
20 return 32;
21 }
22 if let Some(&w) = ctx.globals.intlist_bit_widths.get(&(form_id, op)) {
23 return w;
24 }
25 let order = ctx.globals.intlist_bit_order.entry(form_id).or_default();
26 if !order.contains(&op) {
27 order.push(op);
28 }
29 let w = match order.iter().position(|&x| x == op).unwrap_or(0) {
30 0 => 1,
31 1 => 2,
32 2 => 4,
33 3 => 8,
34 4 => 16,
35 _ => 32,
36 };
37 ctx.globals.intlist_bit_widths.insert((form_id, op), w);
38 w
39}
40
41fn bit_get(list: &mut Vec<i64>, bit_width: i32, index: i64) -> i64 {
42 let bit_width = bit_unit(bit_width) as u32;
43 if bit_width >= 32 {
44 let idx = index.max(0) as usize;
45 ensure_len(list, idx);
46 return list[idx];
47 }
48 let per = 32 / bit_width;
49 let idx = (index.max(0) as u32 / per) as usize;
50 let shift = (index.max(0) as u32 % per) * bit_width;
51 ensure_len(list, idx);
52 let mask = (1u32 << bit_width) - 1;
53 let raw = list[idx] as u32;
54 ((raw >> shift) & mask) as i64
55}
56
57fn bit_set(list: &mut Vec<i64>, bit_width: i32, index: i64, value: i64) {
58 let bit_width = bit_unit(bit_width) as u32;
59 if bit_width >= 32 {
60 let idx = index.max(0) as usize;
61 ensure_len(list, idx);
62 list[idx] = value;
63 return;
64 }
65 let per = 32 / bit_width;
66 let idx = (index.max(0) as u32 / per) as usize;
67 let shift = (index.max(0) as u32 % per) * bit_width;
68 ensure_len(list, idx);
69 let mask = ((1u32 << bit_width) - 1) << shift;
70 let raw = list[idx] as u32;
71 let v = (value as u32) & ((1u32 << bit_width) - 1);
72 let next = (raw & !mask) | (v << shift);
73 list[idx] = next as i64;
74}
75
76pub fn dispatch(ctx: &mut CommandContext, form_id: u32, args: &[Value]) -> Result<bool> {
84 let mut chain_pos: Option<usize> = None;
86 let mut chain: Option<&[i32]> = None;
87 if let Some(vm_call) = ctx.vm_call.as_ref() {
88 if vm_call.element.first().copied() == Some(form_id as i32) {
89 chain_pos = Some(args.len());
90 chain = Some(vm_call.element.as_slice());
91 }
92 }
93 if chain.is_none() {
94 for (i, v) in args.iter().enumerate() {
95 if let Value::Element(c) = v {
96 if !c.is_empty() && c[0] == form_id as i32 {
97 chain_pos = Some(i);
98 chain = Some(c);
99 break;
100 }
101 }
102 }
103 }
104
105 let params = if let Some(pos) = chain_pos {
106 if pos == args.len() {
107 args
108 } else if pos > 1 {
109 &args[1..pos]
110 } else {
111 &[]
112 }
113 } else {
114 &[][..]
115 };
116
117 if chain_pos == Some(3) {
119 if let (Some(al_id), Some(rhs)) = (
120 args.get(1).and_then(|v| v.as_i64()),
121 args.get(2).and_then(|v| v.as_i64()),
122 ) {
123 if al_id == 1 {
124 if let Some(c_ref) = chain {
125 let c = c_ref.to_vec();
126 if c.len() >= 3 && c[1] == ctx.ids.elm_array {
127 let idx = c[2] as i64;
128 let list = ctx
129 .globals
130 .int_lists
131 .entry(form_id)
132 .or_insert_with(|| vec![0; 32]);
133 bit_set(list, 32, idx, rhs);
134 } else if c.len() >= 4 && c[2] == ctx.ids.elm_array {
135 let bit_width = get_bit_width(ctx, form_id, c[1]);
136 let idx = c[3] as i64;
137 let list = ctx
138 .globals
139 .int_lists
140 .entry(form_id)
141 .or_insert_with(|| vec![0; 32]);
142 bit_set(list, bit_width, idx, rhs);
143 }
144 }
145 }
146 ctx.push(Value::Int(0));
147 return Ok(true);
148 }
149 }
150
151 if let (Some(pos), Some(c_ref)) = (chain_pos, chain) {
153 let c = c_ref.to_vec();
154 let meta_al_id = ctx.vm_call.as_ref().map(|m| m.al_id).unwrap_or(0);
155 let meta_ret_form = ctx.vm_call.as_ref().map(|m| m.ret_form).unwrap_or(0);
156 let al_id = args
157 .get(pos + 1)
158 .and_then(|v| v.as_i64())
159 .unwrap_or(meta_al_id);
160 let _ret_form = args
161 .get(pos + 2)
162 .and_then(|v| v.as_i64())
163 .unwrap_or(meta_ret_form);
164
165 if c.len() >= 3 && c[1] == ctx.ids.elm_array {
166 let idx = c[2] as i64;
167 let out = {
168 let list = ctx
169 .globals
170 .int_lists
171 .entry(form_id)
172 .or_insert_with(|| vec![0; 32]);
173 if al_id == 1 {
174 if let Some(rhs) = args.get(0).and_then(|v| v.as_i64()) {
175 bit_set(list, 32, idx, rhs);
176 }
177 0
178 } else {
179 bit_get(list, 32, idx)
180 }
181 };
182 ctx.push(Value::Int(out));
183 return Ok(true);
184 }
185
186 if c.len() >= 4 && c[2] == ctx.ids.elm_array {
187 let bit_width = get_bit_width(ctx, form_id, c[1]);
188 let idx = c[3] as i64;
189 let out = {
190 let list = ctx
191 .globals
192 .int_lists
193 .entry(form_id)
194 .or_insert_with(|| vec![0; 32]);
195 if al_id == 1 {
196 if let Some(rhs) = args.get(0).and_then(|v| v.as_i64()) {
197 bit_set(list, bit_width, idx, rhs);
198 }
199 0
200 } else {
201 bit_get(list, bit_width, idx)
202 }
203 };
204 ctx.push(Value::Int(out));
205 return Ok(true);
206 }
207
208 if c.len() == 3 && c[1] != ctx.ids.elm_array && c[2] != ctx.ids.elm_array {
209 let bit_width = get_bit_width(ctx, form_id, c[1]);
210 let list = ctx
211 .globals
212 .int_lists
213 .entry(form_id)
214 .or_insert_with(|| vec![0; 32]);
215
216 if _ret_form != 0 && params.is_empty() {
217 let unit = bit_unit(bit_width) as i64;
218 let per = if unit >= 32 { 1 } else { 32 / unit };
219 let size = list.len() as i64 * per as i64;
220 ctx.push(Value::Int(size));
221 return Ok(true);
222 }
223
224 if _ret_form == 0 {
225 if params.is_empty() {
226 list.clear();
227 ctx.push(Value::Int(0));
228 return Ok(true);
229 }
230 if params.len() == 1 {
231 let n = params[0].as_i64().unwrap_or(0).max(0) as usize;
232 list.resize(n, 0);
233 ctx.push(Value::Int(0));
234 return Ok(true);
235 }
236 if params.len() >= 2 {
237 let start = params[0].as_i64().unwrap_or(0);
238 let end = params[1].as_i64().unwrap_or(start);
239 let value = if params.len() >= 3 {
240 params[2].as_i64().unwrap_or(0)
241 } else {
242 0
243 };
244 for i in start..=end {
245 bit_set(list, bit_width, i, value);
246 }
247 ctx.push(Value::Int(0));
248 return Ok(true);
249 }
250 }
251 }
252
253 if c.len() == 2 {
254 if _ret_form != 0 && params.is_empty() {
255 let size = {
256 let list = ctx
257 .globals
258 .int_lists
259 .entry(form_id)
260 .or_insert_with(|| vec![0; 32]);
261 list.len() as i64
262 };
263 ctx.push(Value::Int(size));
264 return Ok(true);
265 }
266
267 let list = ctx
268 .globals
269 .int_lists
270 .entry(form_id)
271 .or_insert_with(|| vec![0; 32]);
272
273 if _ret_form == 0 {
274 if params.is_empty() {
275 list.clear();
276 ctx.push(Value::Int(0));
277 return Ok(true);
278 }
279 if params.len() == 1 {
280 let n = params[0].as_i64().unwrap_or(0).max(0) as usize;
281 list.resize(n, 0);
282 ctx.push(Value::Int(0));
283 return Ok(true);
284 }
285 if params.len() >= 2 {
286 let start = params[0].as_i64().unwrap_or(0);
287 let end = params[1].as_i64().unwrap_or(start);
288 let value = if params.len() >= 3 {
289 params[2].as_i64().unwrap_or(0)
290 } else {
291 0
292 };
293 for i in start..=end {
294 bit_set(list, 32, i, value);
295 }
296 ctx.push(Value::Int(0));
297 return Ok(true);
298 }
299 }
300 }
301 }
302
303 ctx.push(Value::Int(0));
304 Ok(true)
305}