trim-newlines 0.1.0

Trim newlines (\r and \n) from the start and/or end of a string. A faithful port of the trim-newlines npm package. Zero deps, no_std.
Documentation
//! # trim-newlines — trim newlines from the start and end of a string
//!
//! Remove leading and/or trailing newline characters (`\r` and `\n` only — not other
//! whitespace) from a string. A faithful Rust port of the widely-used
//! [`trim-newlines`](https://www.npmjs.com/package/trim-newlines) npm package.
//!
//! ```
//! use trim_newlines::{trim_newlines, trim_newlines_start, trim_newlines_end};
//!
//! assert_eq!(trim_newlines("\n\nfoo\n\n"), "foo");
//! assert_eq!(trim_newlines_start("\r\nbar\r\n"), "bar\r\n");
//! assert_eq!(trim_newlines_end("\r\nbar\r\n"), "\r\nbar");
//! ```
//!
//! Only `\r` and `\n` are trimmed, so surrounding spaces or tabs are preserved. The functions
//! return a borrowed slice of the input (no allocation).
//!
//! **Zero dependencies** and `#![no_std]`.

#![no_std]
#![forbid(unsafe_code)]
#![doc(html_root_url = "https://docs.rs/trim-newlines/0.1.0")]

// Compile-test the README's examples as part of `cargo test`.
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
struct ReadmeDoctests;

fn is_newline(c: char) -> bool {
    c == '\r' || c == '\n'
}

/// Trim newlines (`\r` and `\n`) from both ends of `string`.
///
/// ```
/// # use trim_newlines::trim_newlines;
/// assert_eq!(trim_newlines("\r\n\r\nbar\r\n"), "bar");
/// assert_eq!(trim_newlines("  spaced  "), "  spaced  "); // spaces kept
/// ```
#[must_use]
pub fn trim_newlines(string: &str) -> &str {
    string.trim_matches(is_newline)
}

/// Trim newlines (`\r` and `\n`) from the start of `string`.
///
/// ```
/// # use trim_newlines::trim_newlines_start;
/// assert_eq!(trim_newlines_start("\n\nfoo\n\n"), "foo\n\n");
/// ```
#[must_use]
pub fn trim_newlines_start(string: &str) -> &str {
    string.trim_start_matches(is_newline)
}

/// Trim newlines (`\r` and `\n`) from the end of `string`.
///
/// ```
/// # use trim_newlines::trim_newlines_end;
/// assert_eq!(trim_newlines_end("\n\nfoo\n\n"), "\n\nfoo");
/// ```
#[must_use]
pub fn trim_newlines_end(string: &str) -> &str {
    string.trim_end_matches(is_newline)
}

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

    #[test]
    fn both_ends() {
        assert_eq!(trim_newlines("\n\nfoo\n\n"), "foo");
        assert_eq!(trim_newlines("\r\n\r\nbar\r\n"), "bar");
        assert_eq!(trim_newlines("\r\rmid\r\r"), "mid");
        assert_eq!(trim_newlines("no"), "no");
        assert_eq!(trim_newlines(""), "");
    }

    #[test]
    fn start_only() {
        assert_eq!(trim_newlines_start("\n\nfoo\n\n"), "foo\n\n");
        assert_eq!(trim_newlines_start("\r\n\r\nbar\r\n"), "bar\r\n");
        assert_eq!(trim_newlines_start("no"), "no");
    }

    #[test]
    fn end_only() {
        assert_eq!(trim_newlines_end("\n\nfoo\n\n"), "\n\nfoo");
        assert_eq!(trim_newlines_end("\r\n\r\nbar\r\n"), "\r\n\r\nbar");
        assert_eq!(trim_newlines_end("no"), "no");
    }

    #[test]
    fn only_trims_newlines_not_other_whitespace() {
        assert_eq!(trim_newlines("  spaced  "), "  spaced  ");
        assert_eq!(trim_newlines("\tfoo\t"), "\tfoo\t");
        // A space between newlines stops the trim.
        assert_eq!(trim_newlines("\n \nx\n \n"), " \nx\n ");
        assert_eq!(trim_newlines_start("\n \nx\n \n"), " \nx\n \n");
        assert_eq!(trim_newlines_end("\n \nx\n \n"), "\n \nx\n ");
    }

    #[test]
    fn all_newlines() {
        assert_eq!(trim_newlines("\n\r\n\r"), "");
        assert_eq!(trim_newlines_start("\n\r\n\r"), "");
        assert_eq!(trim_newlines_end("\n\r\n\r"), "");
    }
}