Skip to main content

aver/types/
vector.rs

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