wasm4fun-fmt 0.1.0

Formatting primitives for WASM-4 fantasy console
Documentation
// Copyright Claudio Mattera 2022.
//
// Distributed under the MIT License or the Apache 2.0 License at your option.
// See the accompanying files License-MIT.txt and License-Apache-2.0.txt, or
// online at
// https://opensource.org/licenses/MIT
// https://opensource.org/licenses/Apache-2.0

/// Format an integer number to a buffer
///
/// # Example
///
/// ```
/// use wasm4fun_fmt::format_i32;
///
/// let n = -4;
///
/// // Create a buffer to store the str
/// let mut buffer: [u8; 10] = [0; 10];
/// let s = format_i32(&mut buffer, n);
/// assert_eq!(s, "-4");
/// ```
///
/// # Undefined Behaviour
///
/// This function had undefined behaviour if the formatted number cannot fit
/// the buffer.
pub fn format_i32(buffer: &mut [u8], n: i32) -> &str {
    format_i32_padded(buffer, n, 0, '0')
}

/// Format an integer number to a buffer with padding
///
/// The `length` argument can be used to specify the minimal output width.
/// If the output is shorter than that, it will be padded left using character
/// `placeholder`.
///
/// # Example
///
/// ```
/// use wasm4fun_fmt::format_i32_padded;
///
/// let n = -4;
///
/// // Create a buffer to store the str
/// let mut buffer: [u8; 10] = [0; 10];
/// let s = format_i32_padded(&mut buffer, n, 4, ' ');
/// assert_eq!(s, "  -4");
/// ```
///
/// # Undefined Behaviour
///
/// This function had undefined behaviour if the formatted number cannot fit
/// the buffer.
pub fn format_i32_padded(buffer: &mut [u8], mut n: i32, length: usize, placeholder: char) -> &str {
    let mut m = 0; // End of padding
    let mut j = 0; // Start of digits
    let mut k = 0; // Digits count

    // Handle negative sign
    if n < 0 {
        n *= -1;
        buffer[0] = b'-';
        j = 1;
    }

    // Extract digits in inverse order
    if n == 0 {
        buffer[j + k] = b'0';
        k += 1;
    } else {
        while n > 0 {
            let digit = (n % 10) as u8;
            n /= 10;

            let digit = char::from_u32(digit as u32 + '0' as u32).unwrap();
            buffer[j + k] = digit as u8;
            k += 1;
        }
    }

    // Reverse digits
    for i in 0..(k / 2) {
        buffer.swap(i + j, k + j - i - 1);
    }

    // Add padding
    if length > k {
        m = length - k - j;
        // Shift digits
        for i in 0..(j + k) {
            buffer[(j + k - i - 1) + m] = buffer[j + k - i - 1];
        }
        // Overwrite with placeholder
        #[allow(clippy::needless_range_loop)]
        for i in 0..m {
            buffer[i] = placeholder as u8;
        }
    }

    // Convert buffer to str
    unsafe { core::str::from_utf8_unchecked(&buffer[..(m + j + k)]) }
}

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

    #[test]
    fn test_format_i32_0() {
        let n = 0;
        let mut buffer = [0; 10];
        let text = format_i32(&mut buffer, n);
        let expected = "0";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_5() {
        let n = 5;
        let mut buffer = [0; 10];
        let text = format_i32(&mut buffer, n);
        let expected = "5";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_minus_5() {
        let n = -5;
        let mut buffer = [0; 10];
        let text = format_i32(&mut buffer, n);
        let expected = "-5";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_23() {
        let n = 23;
        let mut buffer = [0; 10];
        let text = format_i32(&mut buffer, n);
        let expected = "23";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_100() {
        let n = 100;
        let mut buffer = [0; 10];
        let text = format_i32(&mut buffer, n);
        let expected = "100";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_padded_5() {
        let n = 5;
        let mut buffer = [0; 10];
        let text = format_i32_padded(&mut buffer, n, 5, '0');
        let expected = "00005";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_padded_23() {
        let n = 23;
        let mut buffer = [0; 10];
        let text = format_i32_padded(&mut buffer, n, 5, ' ');
        let expected = "   23";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_padded_100() {
        let n = 100;
        let mut buffer = [0; 10];
        let text = format_i32_padded(&mut buffer, n, 5, '.');
        let expected = "..100";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_padded_minus_5() {
        let n = -5;
        let mut buffer = [0; 10];
        let text = format_i32_padded(&mut buffer, n, 5, '0');
        let expected = "000-5";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_padded_minus_23() {
        let n = -23;
        let mut buffer = [0; 10];
        let text = format_i32_padded(&mut buffer, n, 5, ' ');
        let expected = "  -23";
        assert_eq!(text, expected);
    }

    #[test]
    fn test_format_i32_padded_minus_100() {
        let n = -100;
        let mut buffer = [0; 10];
        let text = format_i32_padded(&mut buffer, n, 5, '.');
        let expected = ".-100";
        assert_eq!(text, expected);
    }
}