artichoke_backend/extn/core/array/
args.rs1use std::fmt::Write as _;
2
3use crate::convert::implicitly_convert_to_int;
4use crate::extn::prelude::*;
5use crate::fmt::WriteError;
6use crate::sys::protect;
7
8#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
9pub enum ElementReference {
10 Empty,
11 Index(i64),
12 StartLen(i64, usize),
13}
14
15pub fn element_reference(
16 interp: &mut Artichoke,
17 elem: Value,
18 len: Option<Value>,
19 ary_len: usize,
20) -> Result<ElementReference, Error> {
21 if let Some(len) = len {
22 let start = implicitly_convert_to_int(interp, elem)?;
23 let len = implicitly_convert_to_int(interp, len)?;
24 return if let Ok(len) = usize::try_from(len) {
25 Ok(ElementReference::StartLen(start, len))
26 } else {
27 Ok(ElementReference::Empty)
28 };
29 }
30 let rangelen = i64::try_from(ary_len).map_err(|_| Fatal::from("Range length exceeds Integer max"))?;
31 match elem.is_range(interp, rangelen)? {
32 None => {
33 let index = implicitly_convert_to_int(interp, elem)?;
34 Ok(ElementReference::Index(index))
35 }
36 Some(protect::Range::Out) => Ok(ElementReference::Empty),
43 Some(protect::Range::Valid { start, len }) => {
44 if let Ok(len) = usize::try_from(len) {
45 Ok(ElementReference::StartLen(start, len))
46 } else {
47 Ok(ElementReference::Empty)
48 }
49 }
50 }
51}
52
53pub fn element_assignment(
54 interp: &mut Artichoke,
55 first: Value,
56 second: Value,
57 third: Option<Value>,
58 len: usize,
59) -> Result<(usize, Option<usize>, Value), Error> {
60 if let Some(elem) = third {
61 let start = implicitly_convert_to_int(interp, first)?;
62 let start = if let Some(start) = aref::offset_to_index(start, len) {
63 start
64 } else {
65 let mut message = String::new();
66 write!(&mut message, "index {start} too small for array; minimum: -{len}").map_err(WriteError::from)?;
67 return Err(IndexError::from(message).into());
68 };
69 let slice_len = implicitly_convert_to_int(interp, second)?;
70 if let Ok(slice_len) = usize::try_from(slice_len) {
71 Ok((start, Some(slice_len), elem))
72 } else {
73 let mut message = String::new();
74 write!(&mut message, "negative length ({slice_len})").map_err(WriteError::from)?;
75 Err(IndexError::from(message).into())
76 }
77 } else {
78 let rangelen = i64::try_from(len).map_err(|_| Fatal::from("Range length exceeds Integer max"))?;
79 match first.is_range(interp, rangelen)? {
80 None => {
81 let index = implicitly_convert_to_int(interp, first)?;
82 if let Some(index) = aref::offset_to_index(index, len) {
83 Ok((index, None, second))
84 } else {
85 let mut message = String::new();
86 write!(&mut message, "index {index} too small for array; minimum: -{len}")
87 .map_err(WriteError::from)?;
88 Err(IndexError::from(message).into())
89 }
90 }
91 Some(protect::Range::Out) => Err(RangeError::with_message("out of range").into()),
102 Some(protect::Range::Valid { start, len }) => {
103 let start = usize::try_from(start)
104 .unwrap_or_else(|_| unimplemented!("should throw RangeError (-11..1 out of range)"));
105 let len = usize::try_from(len).unwrap_or_else(|_| unreachable!("Range can't have negative length"));
106 Ok((start, Some(len), second))
107 }
108 }
109 }
110}