1use super::{iterator::adaptors, value_sort::compare_values};
4use crate::{Result, prelude::*};
5use std::cmp::Ordering;
6
7pub fn make_module() -> KMap {
9 let result = KMap::with_type("core.map");
10
11 result.add_fn("clear", |ctx| {
12 let expected_error = "|Map|";
13
14 match map_instance_and_args(ctx, expected_error)? {
15 (KValue::Map(m), []) => {
16 m.data_mut().clear();
17 Ok(KValue::Map(m.clone()))
18 }
19 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
20 }
21 });
22
23 result.add_fn("contains_key", |ctx| {
24 let expected_error = "|Map, Any|";
25
26 match map_instance_and_args(ctx, expected_error)? {
27 (KValue::Map(m), [key]) => {
28 let result = m.data().contains_key(&ValueKey::try_from(key.clone())?);
29 Ok(result.into())
30 }
31 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
32 }
33 });
34
35 result.add_fn("extend", |ctx| {
36 let expected_error = "|Map, Iterable|";
37
38 match map_instance_and_args(ctx, expected_error)? {
39 (KValue::Map(m), [KValue::Map(other)]) => {
40 m.data_mut().extend(
41 other
42 .data()
43 .iter()
44 .map(|(key, value)| (key.clone(), value.clone())),
45 );
46 Ok(KValue::Map(m.clone()))
47 }
48 (KValue::Map(m), [iterable]) if iterable.is_iterable() => {
49 let m = m.clone();
50 let iterable = iterable.clone();
51 let iterator = ctx.vm.make_iterator(iterable)?;
52
53 {
54 let mut map_data = m.data_mut();
55 let (size_hint, _) = iterator.size_hint();
56 map_data.reserve(size_hint);
57
58 for output in iterator {
59 use KIteratorOutput as Output;
60 let (key, value) = match output {
61 Output::ValuePair(key, value) => (key, value),
62 Output::Value(KValue::Tuple(t)) if t.len() == 2 => {
63 let key = t[0].clone();
64 let value = t[1].clone();
65 (key, value)
66 }
67 Output::Value(value) => (value, KValue::Null),
68 Output::Error(error) => return Err(error),
69 };
70
71 map_data.insert(ValueKey::try_from(key.clone())?, value);
72 }
73 }
74
75 Ok(KValue::Map(m))
76 }
77 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
78 }
79 });
80
81 result.add_fn("get", |ctx| {
82 let (map, key, default) = {
83 let expected_error = "|Map, Any|, or |Map, Any, Any|";
84
85 match map_instance_and_args(ctx, expected_error)? {
86 (KValue::Map(map), [key]) => (map, key, &KValue::Null),
87 (KValue::Map(map), [key, default]) => (map, key, default),
88 (instance, args) => {
89 return unexpected_args_after_instance(expected_error, instance, args);
90 }
91 }
92 };
93
94 let result = map
95 .get(&ValueKey::try_from(key.clone())?)
96 .unwrap_or_else(|| default.clone());
97
98 Ok(result)
99 });
100
101 result.add_fn("get_index", |ctx| {
102 use KValue::{Map, Null, Number};
103 let expected_error = "|Map, Number|";
104
105 let (map, index, default) = match map_instance_and_args(ctx, expected_error)? {
106 (Map(map), [Number(n)]) => (map, n, Null),
107 (Map(map), [Number(n), default]) => (map, n, default.clone()),
108 (instance, args) => {
109 return unexpected_args_after_instance(expected_error, instance, args);
110 }
111 };
112
113 if *index >= 0 {
114 match map.data().get_index(usize::from(index)) {
115 Some((key, value)) => Ok(KValue::Tuple(
116 vec![key.value().clone(), value.clone()].into(),
117 )),
118 None => Ok(default),
119 }
120 } else {
121 Ok(default)
122 }
123 });
124
125 result.add_fn("get_meta", |ctx| {
126 let expected_error = "|Map|";
127
128 match map_instance_and_args(ctx, expected_error)? {
129 (KValue::Map(map), []) => {
130 if map.meta_map().is_some() {
131 Ok(KValue::Map(KMap::from_data_and_meta_maps(
132 &KMap::default(),
133 map,
134 )))
135 } else {
136 Ok(KValue::Null)
137 }
138 }
139 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
140 }
141 });
142
143 result.add_fn("insert", |ctx| {
144 let expected_error = "|Map, Any|, or |Map, Any, Any|";
145
146 match map_instance_and_args(ctx, expected_error)? {
147 (KValue::Map(m), [key]) => match m
148 .data_mut()
149 .insert(ValueKey::try_from(key.clone())?, KValue::Null)
150 {
151 Some(old_value) => Ok(old_value),
152 None => Ok(KValue::Null),
153 },
154 (KValue::Map(m), [key, value]) => {
155 match m
156 .data_mut()
157 .insert(ValueKey::try_from(key.clone())?, value.clone())
158 {
159 Some(old_value) => Ok(old_value),
160 None => Ok(KValue::Null),
161 }
162 }
163 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
164 }
165 });
166
167 result.add_fn("is_empty", |ctx| {
168 let expected_error = "|Map|";
169
170 match map_instance_and_args(ctx, expected_error)? {
171 (KValue::Map(m), []) => Ok(m.is_empty().into()),
172 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
173 }
174 });
175
176 result.add_fn("keys", |ctx| {
177 let expected_error = "|Map|";
178
179 match map_instance_and_args(ctx, expected_error)? {
180 (KValue::Map(m), []) => {
181 let result = adaptors::PairFirst::new(KIterator::with_map(m.clone()));
182 Ok(KIterator::new(result).into())
183 }
184 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
185 }
186 });
187
188 result.add_fn("remove", |ctx| {
189 let expected_error = "|Map, Any|";
190
191 match map_instance_and_args(ctx, expected_error)? {
192 (KValue::Map(m), [key]) => {
193 match m.data_mut().shift_remove(&ValueKey::try_from(key.clone())?) {
194 Some(old_value) => Ok(old_value),
195 None => Ok(KValue::Null),
196 }
197 }
198 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
199 }
200 });
201
202 result.add_fn("sort", |ctx| {
203 let expected_error = "|Map|, or |Map, |Any, Any| -> Any|";
204
205 match map_instance_and_args(ctx, expected_error)? {
206 (KValue::Map(m), []) => {
207 let mut error = None;
208 m.data_mut().sort_by(|key_a, _, key_b, _| {
209 if error.is_some() {
210 return Ordering::Equal;
211 }
212
213 match key_a.partial_cmp(key_b) {
214 Some(ordering) => ordering,
215 None => {
216 error = Some(runtime_error!("invalid map key encountered"));
218 Ordering::Equal
219 }
220 }
221 });
222
223 if let Some(error) = error {
224 error
225 } else {
226 Ok(KValue::Map(m.clone()))
227 }
228 }
229 (KValue::Map(m), [f]) if f.is_callable() => {
230 let m = m.clone();
231 let f = f.clone();
232 let mut error = None;
233
234 let get_sort_key = |vm: &mut KotoVm,
235 cache: &mut ValueMap,
236 key: &ValueKey,
237 value: &KValue|
238 -> Result<KValue> {
239 let value =
240 vm.call_function(f.clone(), &[key.value().clone(), value.clone()])?;
241 cache.insert(key.clone(), value.clone());
242 Ok(value)
243 };
244
245 let mut cache = ValueMap::with_capacity(m.len());
246 m.data_mut().sort_by(|key_a, value_a, key_b, value_b| {
247 if error.is_some() {
248 return Ordering::Equal;
249 }
250
251 let value_a = match cache.get(key_a) {
252 Some(value) => value.clone(),
253 None => match get_sort_key(ctx.vm, &mut cache, key_a, value_a) {
254 Ok(val) => val,
255 Err(e) => {
256 error.get_or_insert(Err(e));
257 KValue::Null
258 }
259 },
260 };
261 let value_b = match cache.get(key_b) {
262 Some(value) => value.clone(),
263 None => match get_sort_key(ctx.vm, &mut cache, key_b, value_b) {
264 Ok(val) => val,
265 Err(e) => {
266 error.get_or_insert(Err(e));
267 KValue::Null
268 }
269 },
270 };
271
272 match compare_values(ctx.vm, &value_a, &value_b) {
273 Ok(ordering) => ordering,
274 Err(e) => {
275 error.get_or_insert(Err(e));
276 Ordering::Equal
277 }
278 }
279 });
280
281 if let Some(error) = error {
282 error
283 } else {
284 Ok(KValue::Map(m))
285 }
286 }
287 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
288 }
289 });
290
291 result.add_fn("update", |ctx| {
292 let expected_error = "|Map, Any, |Any| -> Any||, or |Map, Any, Any, |Any| -> Any|";
293
294 match map_instance_and_args(ctx, expected_error)? {
295 (KValue::Map(m), [key, f]) if f.is_callable() => do_map_update(
296 m.clone(),
297 ValueKey::try_from(key.clone())?,
298 KValue::Null,
299 f.clone(),
300 ctx.vm,
301 ),
302 (KValue::Map(m), [key, default, f]) if f.is_callable() => do_map_update(
303 m.clone(),
304 ValueKey::try_from(key.clone())?,
305 default.clone(),
306 f.clone(),
307 ctx.vm,
308 ),
309 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
310 }
311 });
312
313 result.add_fn("values", |ctx| {
314 let expected_error = "|Map|";
315
316 match map_instance_and_args(ctx, expected_error)? {
317 (KValue::Map(m), []) => {
318 let result = adaptors::PairSecond::new(KIterator::with_map(m.clone()));
319 Ok(KIterator::new(result).into())
320 }
321 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
322 }
323 });
324
325 result.add_fn("with_meta", |ctx| {
326 let expected_error = "|Map, Map|";
327
328 match map_instance_and_args(ctx, expected_error)? {
329 (KValue::Map(data), [KValue::Map(meta)]) => {
330 let mut data = data.clone();
331 data.set_meta_map(meta.meta_map().cloned());
332 Ok(data.into())
333 }
334 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
335 }
336 });
337
338 result
339}
340
341fn do_map_update(
342 map: KMap,
343 key: ValueKey,
344 default: KValue,
345 f: KValue,
346 vm: &mut KotoVm,
347) -> Result<KValue> {
348 if !map.data().contains_key(&key) {
349 map.data_mut().insert(key.clone(), default);
350 }
351 let value = map.get(&key).unwrap();
352 match vm.call_function(f, value) {
353 Ok(new_value) => {
354 map.data_mut().insert(key, new_value.clone());
355 Ok(new_value)
356 }
357 Err(error) => Err(error),
358 }
359}
360
361fn map_instance_and_args<'a>(
362 ctx: &'a CallContext<'_>,
363 expected_error: &str,
364) -> Result<(&'a KValue, &'a [KValue])> {
365 use KValue::Map;
366
367 match (ctx.instance(), ctx.args()) {
370 (instance @ Map(m), args) if m.meta_map().is_none() => Ok((instance, args)),
371 (_, [first @ Map(_), rest @ ..]) => Ok((first, rest)),
372 (instance, args) => unexpected_args_after_instance(expected_error, instance, args),
373 }
374}