1use std::collections::HashMap;
13use std::sync::Arc as Rc;
14
15use aver_rt::AverVector;
16
17use crate::nan_value::{Arena, NanIntExt, NanValue};
18use crate::value::{RuntimeError, Value, list_from_vec, list_view};
19
20pub fn register(global: &mut HashMap<String, Value>) {
21 let mut members = HashMap::new();
22 for method in &["new", "get", "set", "len", "fromList"] {
23 members.insert(
24 method.to_string(),
25 Value::Builtin(format!("Vector.{}", method)),
26 );
27 }
28 global.insert(
29 "Vector".to_string(),
30 Value::Namespace {
31 name: "Vector".to_string(),
32 members,
33 },
34 );
35}
36
37pub fn effects(_name: &str) -> &'static [&'static str] {
38 &[]
39}
40
41pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
42 match name {
43 "Vector.new" => Some(vec_new(args)),
44 "Vector.get" => Some(vec_get(args)),
45 "Vector.set" => Some(vec_set(args)),
46 "Vector.len" => Some(vec_len(args)),
47 "Vector.fromList" => Some(vec_from_list(args)),
48 "List.fromVector" => Some(vec_to_list(args)),
49 _ => None,
50 }
51}
52
53fn vec_new(args: &[Value]) -> Result<Value, RuntimeError> {
54 if args.len() != 2 {
55 return Err(RuntimeError::Error(format!(
56 "Vector.new() takes 2 arguments (size, default), got {}",
57 args.len()
58 )));
59 }
60 let Value::Int(size) = &args[0] else {
61 return Err(RuntimeError::Error(
62 "Vector.new: size must be an Int".to_string(),
63 ));
64 };
65 let Some(size) = size.to_usize() else {
66 return Err(RuntimeError::Error(
69 "Vector.new: size must be a non-negative, machine-sized Int".to_string(),
70 ));
71 };
72 Ok(Value::Vector(AverVector::new(size, args[1].clone())))
73}
74
75fn vec_get(args: &[Value]) -> Result<Value, RuntimeError> {
76 if args.len() != 2 {
77 return Err(RuntimeError::Error(format!(
78 "Vector.get() takes 2 arguments, got {}",
79 args.len()
80 )));
81 }
82 let Value::Vector(vec) = &args[0] else {
83 return Err(RuntimeError::Error(
84 "Vector.get: first argument must be a Vector".to_string(),
85 ));
86 };
87 let Value::Int(idx) = &args[1] else {
88 return Err(RuntimeError::Error(
89 "Vector.get: index must be an Int".to_string(),
90 ));
91 };
92 let Some(idx) = idx.to_usize() else {
93 return Ok(Value::None);
94 };
95 Ok(match vec.get(idx) {
96 Some(v) => Value::Some(Box::new(v.clone())),
97 None => Value::None,
98 })
99}
100
101fn vec_set(args: &[Value]) -> Result<Value, RuntimeError> {
102 if args.len() != 3 {
103 return Err(RuntimeError::Error(format!(
104 "Vector.set() takes 3 arguments, got {}",
105 args.len()
106 )));
107 }
108 let Value::Vector(vec) = &args[0] else {
109 return Err(RuntimeError::Error(
110 "Vector.set: first argument must be a Vector".to_string(),
111 ));
112 };
113 let Value::Int(idx) = &args[1] else {
114 return Err(RuntimeError::Error(
115 "Vector.set: index must be an Int".to_string(),
116 ));
117 };
118 let Some(idx) = idx.to_usize() else {
119 return Ok(Value::None);
120 };
121 Ok(match vec.set(idx, args[2].clone()) {
122 Some(new_vec) => Value::Some(Box::new(Value::Vector(new_vec))),
123 None => Value::None,
124 })
125}
126
127fn vec_len(args: &[Value]) -> Result<Value, RuntimeError> {
128 if args.len() != 1 {
129 return Err(RuntimeError::Error(format!(
130 "Vector.len() takes 1 argument, got {}",
131 args.len()
132 )));
133 }
134 let Value::Vector(vec) = &args[0] else {
135 return Err(RuntimeError::Error(
136 "Vector.len: argument must be a Vector".to_string(),
137 ));
138 };
139 Ok(Value::int(vec.len() as i64))
140}
141
142fn vec_from_list(args: &[Value]) -> Result<Value, RuntimeError> {
143 if args.len() != 1 {
144 return Err(RuntimeError::Error(format!(
145 "Vector.fromList() takes 1 argument, got {}",
146 args.len()
147 )));
148 }
149 let items = list_view(&args[0]).ok_or_else(|| {
150 RuntimeError::Error("Vector.fromList: argument must be a List".to_string())
151 })?;
152 Ok(Value::Vector(AverVector::from_list(items)))
153}
154
155fn vec_to_list(args: &[Value]) -> Result<Value, RuntimeError> {
156 if args.len() != 1 {
157 return Err(RuntimeError::Error(format!(
158 "List.fromVector() takes 1 argument, got {}",
159 args.len()
160 )));
161 }
162 let Value::Vector(vec) = &args[0] else {
163 return Err(RuntimeError::Error(
164 "List.fromVector: argument must be a Vector".to_string(),
165 ));
166 };
167 Ok(list_from_vec(vec.to_vec()))
168}
169
170pub fn register_nv(global: &mut HashMap<String, NanValue>, arena: &mut Arena) {
173 let methods = &["new", "get", "set", "len", "fromList"];
174 let mut members: Vec<(Rc<str>, NanValue)> = Vec::with_capacity(methods.len());
175 for method in methods {
176 let idx = arena.push_builtin(&format!("Vector.{}", method));
177 members.push((Rc::from(*method), NanValue::new_builtin(idx)));
178 }
179 let ns_idx = arena.push(crate::nan_value::ArenaEntry::Namespace {
180 name: Rc::from("Vector"),
181 members,
182 });
183 global.insert("Vector".to_string(), NanValue::new_namespace(ns_idx));
184}
185
186pub fn call_nv(
187 name: &str,
188 args: &[NanValue],
189 arena: &mut Arena,
190) -> Option<Result<NanValue, RuntimeError>> {
191 match name {
192 "Vector.new" => Some(vec_new_nv(args, arena)),
193 "Vector.get" => Some(vec_get_nv(args, arena)),
194 "Vector.set" => Some(vec_set_nv(args, arena)),
195 "Vector.len" => Some(vec_len_nv(args, arena)),
196 "Vector.fromList" => Some(vec_from_list_nv(args, arena)),
197 "List.fromVector" => Some(vec_to_list_nv(args, arena)),
198 _ => None,
199 }
200}
201
202fn vec_new_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
203 if args.len() != 2 {
204 return Err(RuntimeError::Error(format!(
205 "Vector.new() takes 2 arguments (size, default), got {}",
206 args.len()
207 )));
208 }
209 if !args[0].is_int() {
210 return Err(RuntimeError::Error(
211 "Vector.new: size must be an Int".to_string(),
212 ));
213 }
214 let Some(size) = args[0].as_aver_int(arena).to_usize() else {
215 return Err(RuntimeError::Error(
217 "Vector.new: size must be a non-negative, machine-sized Int".to_string(),
218 ));
219 };
220 let items = vec![args[1]; size];
221 if items.is_empty() {
222 Ok(NanValue::EMPTY_VECTOR)
223 } else {
224 Ok(NanValue::new_vector(arena.push_vector(items)))
225 }
226}
227
228fn vec_get_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
229 if args.len() != 2 {
230 return Err(RuntimeError::Error(format!(
231 "Vector.get() takes 2 arguments, got {}",
232 args.len()
233 )));
234 }
235 if !args[0].is_vector() {
236 return Err(RuntimeError::Error(
237 "Vector.get: first argument must be a Vector".to_string(),
238 ));
239 }
240 if !args[1].is_int() {
241 return Err(RuntimeError::Error(
242 "Vector.get: index must be an Int".to_string(),
243 ));
244 }
245 let Some(idx) = args[1].as_aver_int(arena).to_usize() else {
246 return Ok(NanValue::NONE);
247 };
248 let items = arena.vector_ref_value(args[0]);
249 match items.get(idx) {
250 Some(&v) => Ok(NanValue::new_some_value(v, arena)),
251 None => Ok(NanValue::NONE),
252 }
253}
254
255pub fn vec_set_nv_owned(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
257 if args.len() != 3 {
258 return Err(RuntimeError::Error(format!(
259 "Vector.set() takes 3 arguments, got {}",
260 args.len()
261 )));
262 }
263 if !args[0].is_vector() {
264 return Err(RuntimeError::Error(
265 "Vector.set: first argument must be a Vector".to_string(),
266 ));
267 }
268 if !args[1].is_int() {
269 return Err(RuntimeError::Error(
270 "Vector.set: index must be an Int".to_string(),
271 ));
272 }
273 let Some(uidx) = args[1].as_aver_int(arena).to_usize() else {
274 return Ok(NanValue::NONE);
275 };
276 let source = args[0];
277 let mut items = arena.take_vector_value(source);
278 if uidx >= items.len() {
279 return Ok(NanValue::NONE);
280 }
281 items[uidx] = args[2];
282 let new_vec_idx =
283 arena.push_inheriting_source_space(aver_memory::ArenaEntry::Vector(items), source);
284 Ok(NanValue::new_some_value(
285 NanValue::new_vector(new_vec_idx),
286 arena,
287 ))
288}
289
290fn vec_set_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
291 if args.len() != 3 {
292 return Err(RuntimeError::Error(format!(
293 "Vector.set() takes 3 arguments, got {}",
294 args.len()
295 )));
296 }
297 if !args[0].is_vector() {
298 return Err(RuntimeError::Error(
299 "Vector.set: first argument must be a Vector".to_string(),
300 ));
301 }
302 if !args[1].is_int() {
303 return Err(RuntimeError::Error(
304 "Vector.set: index must be an Int".to_string(),
305 ));
306 }
307 let Some(uidx) = args[1].as_aver_int(arena).to_usize() else {
308 return Ok(NanValue::NONE);
309 };
310 let mut items = arena.clone_vector_value(args[0]);
311 if uidx >= items.len() {
312 return Ok(NanValue::NONE);
313 }
314 items[uidx] = args[2];
315 let new_vec_idx = arena.push_vector(items);
316 Ok(NanValue::new_some_value(
317 NanValue::new_vector(new_vec_idx),
318 arena,
319 ))
320}
321
322fn vec_len_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
323 if args.len() != 1 {
324 return Err(RuntimeError::Error(format!(
325 "Vector.len() takes 1 argument, got {}",
326 args.len()
327 )));
328 }
329 if !args[0].is_vector() {
330 return Err(RuntimeError::Error(
331 "Vector.len: argument must be a Vector".to_string(),
332 ));
333 }
334 let items = arena.vector_ref_value(args[0]);
335 Ok(NanValue::new_int(items.len() as i64, arena))
336}
337
338fn vec_from_list_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
339 if args.len() != 1 {
340 return Err(RuntimeError::Error(format!(
341 "Vector.fromList() takes 1 argument, got {}",
342 args.len()
343 )));
344 }
345 if !args[0].is_list() {
346 return Err(RuntimeError::Error(
347 "Vector.fromList: argument must be a List".to_string(),
348 ));
349 }
350 let items = arena.list_to_vec_value(args[0]);
351 if items.is_empty() {
352 Ok(NanValue::EMPTY_VECTOR)
353 } else {
354 Ok(NanValue::new_vector(arena.push_vector(items)))
355 }
356}
357
358fn vec_to_list_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
359 if args.len() != 1 {
360 return Err(RuntimeError::Error(format!(
361 "List.fromVector() takes 1 argument, got {}",
362 args.len()
363 )));
364 }
365 if !args[0].is_vector() {
366 return Err(RuntimeError::Error(
367 "List.fromVector: argument must be a Vector".to_string(),
368 ));
369 }
370 let items = arena.clone_vector_value(args[0]);
371 if items.is_empty() {
372 Ok(NanValue::EMPTY_LIST)
373 } else {
374 let list_idx = arena.push_list(items);
375 Ok(NanValue::new_list(list_idx))
376 }
377}