/// Functions for manipulating arrays of values.
@no_std
@settings(defaultLengthUnit = mm, kclVersion = 1.0)
/// Apply a function to every element of a list.
///
/// Given a list like `[a, b, c]`, and a function like `f`, returns
/// `[f(a), f(b), f(c)]`
///
/// ```kcl,legacySketch
/// r = 10 // radius
/// fn drawCircle(@id) {
/// return startSketchOn(XY)
/// |> circle( center= [id * 2 * r, 0], radius= r)
/// }
///
/// // Call `drawCircle`, passing in each element of the array.
/// // The outputs from each `drawCircle` form a new array,
/// // which is the return value from `map`.
/// circles = map(
/// [1..3],
/// f = drawCircle
/// )
/// ```
///
/// ```kcl,legacySketch
/// r = 10 // radius
/// // Call `map`, using an anonymous function instead of a named one.
/// circles = map(
/// [1..3],
/// f = fn(@id) {
/// return startSketchOn(XY)
/// |> circle( center= [id * 2 * r, 0], radius= r)
/// }
/// )
/// ```
@(impl = std_rust, feature_tree = false)
export fn map(
/// Input array. The output array is this input array, but every element has had the function `f` run on it.
@array: [any],
/// A function. The output array is just the input array, but `f` has been run on every item.
f: fn(any): any,
): [any] {}
/// Take a starting value. Then, for each element of an array, calculate the next value,
/// using the previous value and the element.
///
/// ```kcl,sketchSyntaxAgnostic
/// // This function adds two numbers.
/// fn add(@a, accum) { return a + accum }
///
/// // This function adds an array of numbers.
/// // It uses the `reduce` function, to call the `add` function on every
/// // element of the `arr` parameter. The starting value is 0.
/// fn sum(@arr) { return reduce(arr, initial = 0, f = add) }
///
/// /*
/// The above is basically like this pseudo-code:
/// fn sum(arr):
/// sumSoFar = 0
/// for i in arr:
/// sumSoFar = add(i, sumSoFar)
/// return sumSoFar
/// */
///
/// // We use `assert` to check that our `sum` function gives the
/// // expected result. It's good to check your work!
/// assert(sum([1, 2, 3]), isEqualTo = 6, tolerance = 0.1, error = "1 + 2 + 3 summed is 6")
/// ```
///
/// ```kcl,sketchSyntaxAgnostic
/// // This example works just like the previous example above, but it uses
/// // an anonymous `add` function as its parameter, instead of declaring a
/// // named function outside.
/// arr = [1, 2, 3]
/// sum = reduce(arr, initial = 0, f = fn (@i, accum) { return i + accum })
///
/// // We use `assert` to check that our `sum` function gives the
/// // expected result. It's good to check your work!
/// assert(sum, isEqualTo = 6, tolerance = 0.1, error = "1 + 2 + 3 summed is 6")
/// ```
///
/// ```kcl,legacySketch
/// // Declare a function that sketches a decagon.
/// fn decagon(@radius) {
/// // Each side of the decagon is turned this many radians from the previous angle.
/// stepAngle = ((1/10) * TAU): rad
///
/// // Start the decagon sketch at this point.
/// startOfDecagonSketch = startSketchOn(XY)
/// |> startProfile(at = [(cos(0)*radius), (sin(0) * radius)])
///
/// // Use a `reduce` to draw the remaining decagon sides.
/// // For each number in the array 1..10, run the given function,
/// // which takes a partially-sketched decagon and adds one more edge to it.
/// fullDecagon = reduce([1..10], initial = startOfDecagonSketch, f = fn(@i, accum) {
/// // Draw one edge of the decagon.
/// x = cos(stepAngle * i) * radius
/// y = sin(stepAngle * i) * radius
/// return line(accum, end = [x, y])
/// })
///
/// return fullDecagon
///
/// }
///
/// /*
/// The `decagon` above is basically like this pseudo-code:
/// fn decagon(radius):
/// stepAngle = ((1/10) * TAU): rad
/// plane = startSketchOn(XY)
/// startOfDecagonSketch = startProfile(plane, at = [(cos(0)*radius), (sin(0) * radius)])
///
/// // Here's the reduce part.
/// partialDecagon = startOfDecagonSketch
/// for i in [1..10]:
/// x = cos(stepAngle * i) * radius
/// y = sin(stepAngle * i) * radius
/// partialDecagon = line(partialDecagon, end = [x, y])
/// fullDecagon = partialDecagon // it's now full
/// return fullDecagon
/// */
///
/// // Use the `decagon` function declared above, to sketch a decagon with radius 5.
/// decagon(5.0) |> close()
/// ```
@(impl = std_rust, feature_tree = false)
export fn reduce(
/// Each element of this array gets run through the function `f`, combined with the previous output from `f`, and then used for the next run.
@array: [any],
/// The first time `f` is run, it will be called with the first item of `array` and this initial starting value.
initial: any,
/// Run once per item in the input `array`. This function takes an item from the array, and the previous output from `f` (or `initial` on the very first run). The final time `f` is run, its output is returned as the final output from `reduce`.
f: fn(any, accum: any): any,
): any {}
/// Append an element to the end of an array.
///
/// Returns a new array with the element appended.
///
/// ```kcl,sketchSyntaxAgnostic
/// arr = [1, 2, 3]
/// new_arr = push(arr, item = 4)
/// assert(new_arr[3], isEqualTo = 4, tolerance = 0.1, error = "4 was added to the end of the array")
/// ```
@(impl = std_rust, feature_tree = false)
export fn push(
/// The array which you're adding a new item to.
@array: [any],
/// The new item to add to the array
item: any,
): [any; 1+] {}
/// Remove the last element from an array.
///
/// Returns a new array with the last element removed.
///
/// ```kcl,sketchSyntaxAgnostic
/// arr = [1, 2, 3, 4]
/// new_arr = pop(arr)
/// assert(new_arr[0], isEqualTo = 1, tolerance = 0.00001, error = "1 is the first element of the array")
/// assert(new_arr[1], isEqualTo = 2, tolerance = 0.00001, error = "2 is the second element of the array")
/// assert(new_arr[2], isEqualTo = 3, tolerance = 0.00001, error = "3 is the third element of the array")
/// ```
@(impl = std_rust, feature_tree = false)
export fn pop(
/// The array to pop from. Must not be empty.
@array: [any; 1+],
): [any] {}
/// Combine two arrays into one by concatenating them.
///
/// Returns a new array with the all the elements of the first array followed by all the elements of the second array.
///
/// ```kcl,sketchSyntaxAgnostic
/// arr1 = [10, 20, 30]
/// arr2 = [40, 50, 60]
/// newArr = concat(arr1, items = arr2)
/// assert(newArr[0], isEqualTo = 10, tolerance = 0.00001)
/// assert(newArr[1], isEqualTo = 20, tolerance = 0.00001)
/// assert(newArr[2], isEqualTo = 30, tolerance = 0.00001)
/// assert(newArr[3], isEqualTo = 40, tolerance = 0.00001)
/// assert(newArr[4], isEqualTo = 50, tolerance = 0.00001)
/// assert(newArr[5], isEqualTo = 60, tolerance = 0.00001)
/// assert(count(newArr), isEqualTo = 6, tolerance = 0.00001)
/// ```
///
/// ```kcl,sketchSyntaxAgnostic
/// // Concatenating an empty array has no effect.
/// newArr = concat([10, 20, 30], items = [])
/// assert(newArr[0], isEqualTo = 10, tolerance = 0.00001)
/// assert(newArr[1], isEqualTo = 20, tolerance = 0.00001)
/// assert(newArr[2], isEqualTo = 30, tolerance = 0.00001)
/// assert(count(newArr), isEqualTo = 3, tolerance = 0.00001)
/// ```
@(impl = std_rust, feature_tree = false)
export fn concat(
/// The array of starting elements.
@array: [any],
/// The array of ending elements.
items: [any],
): [any] {}
/// Get a subarray from `start` (inclusive) to `end` (exclusive).
///
/// Returns a new array containing the elements in the requested range.
/// Negative indexes count from the end of the array, so `-1` is the last
/// element, `-2` is the second-to-last element, and so on.
///
/// If `start` is omitted, it defaults to `0`. If `end` is omitted, it
/// defaults to the length of the array.
///
/// It is an error to omit both `start` and `end`. Arrays are immutable, so
/// there's no need to copy the whole array.
///
/// ```kcl,sketchSyntaxAgnostic
/// s = slice([1, 2, 3, 4, 5], start = 1, end = 3)
/// assert(s[0], isEqualTo = 2)
/// assert(s[1], isEqualTo = 3)
/// assert(count(s), isEqualTo = 2)
/// ```
///
/// ```kcl,sketchSyntaxAgnostic
/// s = slice([1, 2, 3, 4, 5], end = -2)
/// assert(s[0], isEqualTo = 1)
/// assert(s[1], isEqualTo = 2)
/// assert(s[2], isEqualTo = 3)
/// assert(count(s), isEqualTo = 3)
/// ```
///
/// ```kcl,sketchSyntaxAgnostic
/// s = slice([1, 2, 3, 4, 5], start = -2)
/// assert(s[0], isEqualTo = 4)
/// assert(s[1], isEqualTo = 5)
/// assert(count(s), isEqualTo = 2)
/// ```
@(impl = std_rust, feature_tree = false)
export fn slice(
/// The array to slice.
@array: [any],
/// The starting index (inclusive). Defaults to `0`.
start?: number(Count),
/// The ending index (exclusive). Defaults to the array length.
end?: number(Count),
): [any] {}
/// Flatten an array by one level.
///
/// Returns a new array where any nested arrays are expanded into the top-level
/// array. This only flattens one level deep.
///
/// ```kcl,sketchSyntaxAgnostic
/// arr = [1, [2, 3], 4]
/// flat = flatten(arr)
/// assert(flat[0], isEqualTo = 1)
/// assert(flat[1], isEqualTo = 2)
/// assert(flat[2], isEqualTo = 3)
/// assert(flat[3], isEqualTo = 4)
/// ```
///
/// ```kcl,sketchSyntaxAgnostic
/// arr = [[1, 2], [3, [4]]]
/// flat = flatten(arr)
/// // Only one level of flattening occurs.
/// assert(flat[0], isEqualTo = 1)
/// assert(flat[1], isEqualTo = 2)
/// assert(flat[2], isEqualTo = 3)
/// assert(flat[3][0], isEqualTo = 4)
/// ```
@(impl = std_rust, feature_tree = false)
export fn flatten(
/// The array to flatten by one level.
@array: [any],
): [any] {}
/// Find the number of elements in an array.
/// ```kcl,sketchSyntaxAgnostic
/// arr1 = [10, 20, 30]
/// assert(count(arr1), isEqualTo = 3)
/// ```
@(feature_tree = false)
export fn count(
/// The array whose length will be returned.
@array: [any],
): number {
return reduce(array, initial = 0, f = fn(@i, accum) { return accum + 1})
}