flix

0.78.0

StringBuilder.flix

/*
 * Copyright 2019 Stephen Tetley
 *
 * Use of this source code is governed by the Apache 2.0 license
 * that can be found in the LICENSE.md file.
 */

///
/// Type of mutable string builders, and its functions.
///
pub mod StringBuilder {

    use IoError.IoError

    import java.lang.{StringBuilder => JStringBuilder}

    ///
    /// Type of mutable string builders.
    ///
    pub enum StringBuilder[_: Region](JStringBuilder)

    instance Writable[StringBuilder[r]] {

        type Elm = Char

        type Aef = r

        pub def write(buffer: Array[Char, r1], sb: StringBuilder[r]): Result[IoError, Int32] \ r1 + r =
            let len = Array.length(buffer);
            Array.forEach(c -> StringBuilder.append(c, sb), buffer);
            Ok(len)

    }

    ///
    /// Returns a new mutable StringBuilder.
    ///
    pub def empty(_: Region[r]): StringBuilder[r] \ r =
        StringBuilder(unsafe IO as r { new JStringBuilder() })

    ///
    /// Append `x` to the StringBuilder `sb`.
    ///
    pub def append(x: a, sb: StringBuilder[r]): Unit \ r with ToString[a] =
        let s = ToString.toString(x);
        s `appendString` sb;
        ()

    ///
    /// Append the String `s` to the StringBuilder `sb`.
    ///
    pub def appendString(s: String, sb: StringBuilder[r]): Unit \ r =
        let StringBuilder(msb) = sb;
        discard unsafe IO as r { msb.append(s) }

    ///
    /// Append the code point `cp` to the StringBuilder `sb`.
    ///
    pub def appendCodePoint(cp: Int32, sb: StringBuilder[r]): Unit \ r =
        let StringBuilder(msb) = sb;
        discard unsafe IO as r { msb.appendCodePoint(cp) }

    ///
    /// Append the system line separator to the StringBuilder `sb`.
    ///
    pub def appendLineSeparator(sb: StringBuilder[r]): Unit \ r =
        String.lineSeparator() `appendString` sb

    ///
    /// Append the String `s` followed by the system line separator to the StringBuilder `sb`.
    ///
    pub def appendLine(s: String, sb: StringBuilder[r]): Unit \ r =
        s `appendString` sb;
        appendLineSeparator(sb)

    ///
    /// Appends `f(x)` to the string builder `sb`.
    ///
    pub def appendLineWith(f: a -> String \ ef, x: a, sb: StringBuilder[r]): Unit \ { ef, r } =
        f(x) `appendString` sb;
        appendLineSeparator(sb)

    ///
    /// Appends each string in the array `a` to the string builder `sb`.
    ///
    pub def appendLines(a: Array[String, r1], sb: StringBuilder[r2]): Unit \ { r1, r2 } =
        Array.forEach(x -> appendLine(x, sb), a)

    ///
    /// Appends `f(x)` for each x in the foldable collection `t` to the string builder `sb`.
    ///
    pub def appendLinesWith(f: a -> String \ ef, t: t[a], sb: StringBuilder[r]): Unit \ (ef + r + Foldable.Aef[t]) with Foldable[t] =
        Foldable.forEach(x -> appendLineWith(f, x, sb), t)

    ///
    /// Append the array of strings `a` separating each pair of string with `sep` to the StringBuilder `sb`.
    ///
    pub def intercalate(sep: String, a: Array[String, r1], sb: StringBuilder[r2]): Unit \ { r1, r2 } =
        let append1 = (i, s) ->
            if (i > 0) {
                appendString(sep, sb);
                appendString(s, sb)
            } else {
                appendString(s, sb)
            };
        Array.forEachWithIndex(append1, a)

    ///
    /// Returns an iterator over `sb`.
    ///
    pub def iterator(rc: Region[r1], sb: StringBuilder[r2]): Iterator[Char, r1 + r2, r1] \ { r1, r2 } =
        let StringBuilder(msb) = sb;
        Iterator.range(rc, 0, length(sb)) |> Iterator.map(i -> unsafe IO as r2 { msb.charAt(i) })

    ///
    /// Return the number of characters in the StringBuilder `sb`.
    ///
    pub def length(sb: StringBuilder[r]): Int32 \ r =
        let StringBuilder(msb) = sb;
        unsafe IO as r { msb.length() }

    ///
    /// Return the number of characters in the StringBuilder `sb`.
    ///
    pub def size(sb: StringBuilder[r]): Int32 \ r = length(sb)

    ///
    /// Sets the length of the StringBuilder `sb`.
    ///
    pub def setLength(newLength: Int32, sb: StringBuilder[r]): Unit \ r =
        let StringBuilder.StringBuilder(msb) = sb;
        unsafe IO as r { msb.setLength(newLength) }

    ///
    /// Convert the StringBuilder `sb` to a string.
    ///
    pub def toString(sb: StringBuilder[r]): String \ r =
        let StringBuilder(msb) = sb;
        unsafe IO as r { msb.toString() }

}