mattwparas / steel

An embedded scheme interpreter in Rust
Apache License 2.0
1.1k stars 49 forks source link

Support rest args in native function macro #66

Closed mattwparas closed 1 year ago

mattwparas commented 1 year ago

Now the last argument in the arguments can be a rest argument.

Take for example the following:

/// Concatenates all of the given strings into one
///
/// (string-append strs...) -> string?
///
/// * strs ... : string?
///
/// # Examples
/// ```scheme
/// > (string-append) ;; => ""
/// > (string-append "foo" "bar") ;; => "foobar"
// ```
#[function(name = "string-append")]
pub fn string_append(rest: RestArgs<SteelString>) -> SteelVal {
    let accumulated = rest
        .0
        .into_iter()
        .fold("".to_string(), |accum, next| accum + next.as_str());

    SteelVal::StringV(accumulated.into())
}

However, this will allocate a new Vec<T> for the rest. The alternative implementation will use an iterator over the rest args, making it optional to allocate:

/// Concatenates all of the given strings into one
///
/// (string-append strs...) -> string?
///
/// * strs ... : string?
///
/// # Examples
/// ```scheme
/// > (string-append) ;; => ""
/// > (string-append "foo" "bar") ;; => "foobar"
// ```
#[function(name = "string-append")]
pub fn string_append(mut rest: RestArgsIter<'_, &SteelString>) -> Result<SteelVal> {
    rest.0
        .try_fold("".to_string(), |accum, next| Ok(accum + next?.as_str()))
        .map(|x| SteelVal::StringV(x.into()))
}

Closes #64