pochoir-lang 0.12.2

Custom parser and interpreter for the pochoir template engine
Documentation
//! Take (only) the n-th first or last elements of an array.
//!
//! A negative offset means the n-th **last** elements of the array will be taken.
//!
//! If the original array is too short, then the returned array is empty.
//!
//! ### Example
//!
//! <div class="example-wrap"><pre class="rust rust-example-rendered" style="border-left: 2px solid red;"><span style="position: absolute; right: 0; top: 0; padding: 0.1rem 0.4rem 0 0; font-size: 0.75em; font-weight: bold; color: #333;">input</span><code><span class="fn">take</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>], <span class="number">2</span>)</code></pre></div>
//!
//! <div class="example-wrap"><pre class="rust rust-example-rendered" style="border-left: 2px solid red;"><span style="position: absolute; right: 0; top: 0; padding: 0.1rem 0.4rem 0 0; font-size: 0.75em; font-weight: bold; color: #333;">output</span><code>[<span class="number">1</span>, <span class="number">2</span>]</code></pre></div>
//!
//! <div class="example-wrap"><pre class="rust rust-example-rendered" style="position: relative; margin-top: 2rem; border-left: 2px solid blue;"><span style="position: absolute; right: 0; top: 0; padding: 0.1rem 0.4rem 0 0; font-size: 0.75em; font-weight: bold; color: #333;">input</span><code><span class="fn">take</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>], <span class="number">-2</span>)</code></pre></div>
//!
//! <div class="example-wrap"><pre class="rust rust-example-rendered" style="border-left: 2px solid blue;"><span style="position: absolute; right: 0; top: 0; padding: 0.1rem 0.4rem 0 0; font-size: 0.75em; font-weight: bold; color: #333;">output</span><code>[<span class="number">3</span>, <span class="number">4</span>]</code></pre></div>
use std::cmp::Ordering;

use crate::{FunctionResult, Value};

pub(crate) fn take(val: Vec<Value>, offset: isize) -> FunctionResult<Vec<Value>> {
    if val.len() <= offset.unsigned_abs() {
        return Ok(val);
    }

    Ok(match offset.cmp(&0) {
        Ordering::Equal => val,
        Ordering::Less => {
            let offset = val.len() - offset.unsigned_abs();
            val[offset..].to_vec()
        }
        Ordering::Greater => {
            #[allow(clippy::cast_sign_loss)]
            let offset = offset as usize;
            val[..offset].to_vec()
        }
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn take_test() {
        assert_eq!(
            take(
                vec![
                    Value::Number(1.0),
                    Value::Number(2.0),
                    Value::Number(3.0),
                    Value::Number(4.0),
                ],
                2,
            )
            .unwrap(),
            vec![Value::Number(1.0), Value::Number(2.0)]
        );

        assert_eq!(
            take(
                vec![
                    Value::Number(1.0),
                    Value::Number(2.0),
                    Value::Number(3.0),
                    Value::Number(4.0),
                ],
                -2,
            )
            .unwrap(),
            vec![Value::Number(3.0), Value::Number(4.0)]
        );

        assert_eq!(
            take(vec![Value::Number(1.0),], 2,).unwrap(),
            vec![Value::Number(1.0)]
        );

        assert_eq!(
            take(vec![Value::Number(1.0),], -2,).unwrap(),
            vec![Value::Number(1.0)]
        );
    }
}