Files
another-boids-in-rust/vendor/inflections/src/case.rs

623 lines
21 KiB
Rust

//! Utilities to change the case of a string to another case. Supports “lower
//! case,” “UPPER CASE,” “sentence case,” “Title Case,” “camelCase,”
//! “PascalCase,” “kebab-case,” “Train-Case,” “snake_case,” and
//! “CONSTANT_CASE.”
//!
//! For more information [Wikipedia][1] has an interesting article on these
//! special case styles.
//!
//! [1]: https://en.wikipedia.org/wiki/Letter_case#Special_case_styles
//!
//! # Example
//! ```rust
//! use inflections::case::to_camel_case;
//!
//! assert_eq!(to_camel_case("Hello World"), "helloWorld".to_owned());
//! ```
use std::char::ToUppercase;
use std::iter::Peekable;
/// Converts any case into lower case ignoring separators.
///
/// # Example
/// ```rust
/// # use inflections::case::to_lower_case;
/// let lower = "hello world".to_owned();
/// assert_eq!(to_lower_case("hello world"), lower);
/// assert_eq!(to_lower_case("HELLO WORLD"), lower);
/// assert_eq!(to_lower_case("Hello World"), lower);
/// assert_eq!(to_lower_case("helloWorld"), "helloworld".to_owned());
/// assert_eq!(to_lower_case("HelloWorld"), "helloworld".to_owned());
/// assert_eq!(to_lower_case("hello-world"), "hello-world".to_owned());
/// assert_eq!(to_lower_case("Hello-World"), "hello-world".to_owned());
/// assert_eq!(to_lower_case("hello_world"), "hello_world".to_owned());
/// assert_eq!(to_lower_case("HELLO_WORLD"), "hello_world".to_owned());
/// ```
pub fn to_lower_case(string: &str) -> String {
string
.chars()
.flat_map(char::to_lowercase)
.collect()
}
/// Check to see if a string is completely lower case.
///
/// # Example
/// ```rust
/// # use inflections::case::is_lower_case;
/// assert_eq!(is_lower_case("hello world"), true);
/// assert_eq!(is_lower_case("HELLO WORLD"), false);
/// assert_eq!(is_lower_case("Hello World"), false);
/// assert_eq!(is_lower_case("helloWorld"), false);
/// assert_eq!(is_lower_case("HelloWorld"), false);
/// assert_eq!(is_lower_case("hello-world"), true);
/// assert_eq!(is_lower_case("Hello-World"), false);
/// assert_eq!(is_lower_case("hello_world"), true);
/// assert_eq!(is_lower_case("HELLO_WORLD"), false);
pub fn is_lower_case(string: &str) -> bool {
string == to_lower_case(string)
}
/// Converts any case into UPPER CASE ignoring separators.
///
/// # Example
/// ```rust
/// # use inflections::case::to_upper_case;
/// let upper = "HELLO WORLD".to_owned();
/// assert_eq!(to_upper_case("hello world"), upper);
/// assert_eq!(to_upper_case("HELLO WORLD"), upper);
/// assert_eq!(to_upper_case("Hello World"), upper);
/// assert_eq!(to_upper_case("helloWorld"), "HELLOWORLD".to_owned());
/// assert_eq!(to_upper_case("HelloWorld"), "HELLOWORLD".to_owned());
/// assert_eq!(to_upper_case("hello-world"), "HELLO-WORLD".to_owned());
/// assert_eq!(to_upper_case("Hello-World"), "HELLO-WORLD".to_owned());
/// assert_eq!(to_upper_case("hello_world"), "HELLO_WORLD".to_owned());
/// assert_eq!(to_upper_case("HELLO_WORLD"), "HELLO_WORLD".to_owned());
/// ```
pub fn to_upper_case(string: &str) -> String {
string
.chars()
.flat_map(char::to_uppercase)
.collect()
}
/// Check to see if a string is completely UPPER CASE.
///
/// # Example
/// ```rust
/// # use inflections::case::is_upper_case;
/// assert_eq!(is_upper_case("hello world"), false);
/// assert_eq!(is_upper_case("HELLO WORLD"), true);
/// assert_eq!(is_upper_case("Hello World"), false);
/// assert_eq!(is_upper_case("helloWorld"), false);
/// assert_eq!(is_upper_case("HelloWorld"), false);
/// assert_eq!(is_upper_case("hello-world"), false);
/// assert_eq!(is_upper_case("Hello-World"), false);
/// assert_eq!(is_upper_case("hello_world"), false);
/// assert_eq!(is_upper_case("HELLO_WORLD"), true);
pub fn is_upper_case(string: &str) -> bool {
string == to_upper_case(string)
}
/// Converts any case into traditional sentence case without capitalizing the
/// first letter.
///
/// # Example
/// ```rust
/// # use inflections::case::to_sentence_case;
/// let sentence = "hello world".to_owned();
/// assert_eq!(to_sentence_case("hello world"), sentence);
/// assert_eq!(to_sentence_case("HELLO WORLD"), sentence);
/// assert_eq!(to_sentence_case("Hello World"), sentence);
/// assert_eq!(to_sentence_case("helloWorld"), sentence);
/// assert_eq!(to_sentence_case("HelloWorld"), sentence);
/// assert_eq!(to_sentence_case("hello-world"), sentence);
/// assert_eq!(to_sentence_case("Hello-World"), sentence);
/// assert_eq!(to_sentence_case("hello_world"), sentence);
/// assert_eq!(to_sentence_case("HELLO_WORLD"), sentence);
/// ```
pub fn to_sentence_case(string: &str) -> String {
string
.chars()
.map(|c| swap_separator(c, ' '))
.break_camel(' ')
.flat_map(char::to_lowercase)
.collect()
}
/// Check to see if a string is sentence case.
///
/// # Example
/// ```rust
/// # use inflections::case::is_sentence_case;
/// assert_eq!(is_sentence_case("hello world"), true);
/// assert_eq!(is_sentence_case("HELLO WORLD"), false);
/// assert_eq!(is_sentence_case("Hello World"), false);
/// assert_eq!(is_sentence_case("helloWorld"), false);
/// assert_eq!(is_sentence_case("HelloWorld"), false);
/// assert_eq!(is_sentence_case("hello-world"), false);
/// assert_eq!(is_sentence_case("Hello-World"), false);
/// assert_eq!(is_sentence_case("hello_world"), false);
/// assert_eq!(is_sentence_case("HELLO_WORLD"), false);
pub fn is_sentence_case(string: &str) -> bool {
string == to_sentence_case(string)
}
/// Converts any case into title case where *every* word is capitalized.
///
/// # Example
/// ```rust
/// # use inflections::case::to_title_case;
/// let title = "Hello World".to_owned();
/// assert_eq!(to_title_case("hello world"), title);
/// assert_eq!(to_title_case("HELLO WORLD"), title);
/// assert_eq!(to_title_case("Hello World"), title);
/// assert_eq!(to_title_case("helloWorld"), title);
/// assert_eq!(to_title_case("HelloWorld"), title);
/// assert_eq!(to_title_case("hello-world"), title);
/// assert_eq!(to_title_case("Hello-World"), title);
/// assert_eq!(to_title_case("hello_world"), title);
/// assert_eq!(to_title_case("HELLO_WORLD"), title);
/// ```
pub fn to_title_case(string: &str) -> String {
string
.chars()
.map(|c| swap_separator(c, ' '))
.break_camel(' ')
.flat_map(char::to_lowercase)
.capitalize_words()
.collect()
}
/// Check to see if a string is Title Case.
///
/// # Example
/// ```rust
/// # use inflections::case::is_title_case;
/// assert_eq!(is_title_case("Hello World"), true);
/// assert_eq!(is_title_case("hello world"), false);
/// assert_eq!(is_title_case("HELLO WORLD"), false);
/// assert_eq!(is_title_case("helloWorld"), false);
/// assert_eq!(is_title_case("HelloWorld"), false);
/// assert_eq!(is_title_case("hello-world"), false);
/// assert_eq!(is_title_case("Hello-World"), false);
/// assert_eq!(is_title_case("hello_world"), false);
/// assert_eq!(is_title_case("HELLO_WORLD"), false);
pub fn is_title_case(string: &str) -> bool {
string == to_title_case(string)
}
/// Converts any case into camelCase.
///
/// # Example
/// ```rust
/// # use inflections::case::to_camel_case;
/// let camel = "helloWorld".to_owned();
/// assert_eq!(to_camel_case("hello world"), camel);
/// assert_eq!(to_camel_case("HELLO WORLD"), camel);
/// assert_eq!(to_camel_case("Hello World"), camel);
/// assert_eq!(to_camel_case("helloWorld"), camel);
/// assert_eq!(to_camel_case("HelloWorld"), camel);
/// assert_eq!(to_camel_case("hello-world"), camel);
/// assert_eq!(to_camel_case("Hello-World"), camel);
/// assert_eq!(to_camel_case("hello_world"), camel);
/// assert_eq!(to_camel_case("HELLO_WORLD"), camel);
/// ```
pub fn to_camel_case(string: &str) -> String {
string
.chars()
.scan((false, None), scan_to_camel)
.collect()
}
/// Check to see if a string is camelCase.
///
/// # Example
/// ```rust
/// # use inflections::case::is_camel_case;
/// assert_eq!(is_camel_case("helloWorld"), true);
/// assert_eq!(is_camel_case("hello world"), false);
/// assert_eq!(is_camel_case("HELLO WORLD"), false);
/// assert_eq!(is_camel_case("Hello World"), false);
/// assert_eq!(is_camel_case("HelloWorld"), false);
/// assert_eq!(is_camel_case("hello-world"), false);
/// assert_eq!(is_camel_case("Hello-World"), false);
/// assert_eq!(is_camel_case("hello_world"), false);
/// assert_eq!(is_camel_case("HELLO_WORLD"), false);
pub fn is_camel_case(string: &str) -> bool {
string == to_camel_case(string)
}
/// Converts any case into PascalCase.
///
/// # Example
/// ```rust
/// # use inflections::case::to_pascal_case;
/// let pascal = "HelloWorld".to_owned();
/// assert_eq!(to_pascal_case("hello world"), pascal);
/// assert_eq!(to_pascal_case("HELLO WORLD"), pascal);
/// assert_eq!(to_pascal_case("Hello World"), pascal);
/// assert_eq!(to_pascal_case("helloWorld"), pascal);
/// assert_eq!(to_pascal_case("HelloWorld"), pascal);
/// assert_eq!(to_pascal_case("hello-world"), pascal);
/// assert_eq!(to_pascal_case("Hello-World"), pascal);
/// assert_eq!(to_pascal_case("hello_world"), pascal);
/// assert_eq!(to_pascal_case("HELLO_WORLD"), pascal);
/// ```
pub fn to_pascal_case(string: &str) -> String {
string
.chars()
.scan((true, None), scan_to_camel)
.collect()
}
/// Check to see if a string is PascalCase.
///
/// # Example
/// ```rust
/// # use inflections::case::is_pascal_case;
/// assert_eq!(is_pascal_case("HelloWorld"), true);
/// assert_eq!(is_pascal_case("hello world"), false);
/// assert_eq!(is_pascal_case("HELLO WORLD"), false);
/// assert_eq!(is_pascal_case("Hello World"), false);
/// assert_eq!(is_pascal_case("helloWorld"), false);
/// assert_eq!(is_pascal_case("hello-world"), false);
/// assert_eq!(is_pascal_case("Hello-World"), false);
/// assert_eq!(is_pascal_case("hello_world"), false);
/// assert_eq!(is_pascal_case("HELLO_WORLD"), false);
pub fn is_pascal_case(string: &str) -> bool {
string == to_pascal_case(string)
}
/// Converts any case into kebab-case.
///
/// # Example
/// ```rust
/// # use inflections::case::to_kebab_case;
/// let kebab = "hello-world".to_owned();
/// assert_eq!(to_kebab_case("hello world"), kebab);
/// assert_eq!(to_kebab_case("HELLO WORLD"), kebab);
/// assert_eq!(to_kebab_case("Hello World"), kebab);
/// assert_eq!(to_kebab_case("helloWorld"), kebab);
/// assert_eq!(to_kebab_case("HelloWorld"), kebab);
/// assert_eq!(to_kebab_case("hello-world"), kebab);
/// assert_eq!(to_kebab_case("Hello-World"), kebab);
/// assert_eq!(to_kebab_case("hello_world"), kebab);
/// assert_eq!(to_kebab_case("HELLO_WORLD"), kebab);
/// ```
pub fn to_kebab_case(string: &str) -> String {
string
.chars()
.map(|c| swap_separator(c, '-'))
.break_camel('-')
.flat_map(char::to_lowercase)
.collect()
}
/// Check to see if a string is kebab-case.
///
/// # Example
/// ```rust
/// # use inflections::case::is_kebab_case;
/// assert_eq!(is_kebab_case("hello-world"), true);
/// assert_eq!(is_kebab_case("hello world"), false);
/// assert_eq!(is_kebab_case("HELLO WORLD"), false);
/// assert_eq!(is_kebab_case("Hello World"), false);
/// assert_eq!(is_kebab_case("helloWorld"), false);
/// assert_eq!(is_kebab_case("HelloWorld"), false);
/// assert_eq!(is_kebab_case("Hello-World"), false);
/// assert_eq!(is_kebab_case("hello_world"), false);
/// assert_eq!(is_kebab_case("HELLO_WORLD"), false);
pub fn is_kebab_case(string: &str) -> bool {
string == to_kebab_case(string)
}
/// Converts any case into Train-Case.
///
/// # Example
/// ```rust
/// # use inflections::case::to_train_case;
/// let train = "Hello-World".to_owned();
/// assert_eq!(to_train_case("hello world"), train);
/// assert_eq!(to_train_case("HELLO WORLD"), train);
/// assert_eq!(to_train_case("Hello World"), train);
/// assert_eq!(to_train_case("helloWorld"), train);
/// assert_eq!(to_train_case("HelloWorld"), train);
/// assert_eq!(to_train_case("hello-world"), train);
/// assert_eq!(to_train_case("Hello-World"), train);
/// assert_eq!(to_train_case("hello_world"), train);
/// assert_eq!(to_train_case("HELLO_WORLD"), train);
/// ```
pub fn to_train_case(string: &str) -> String {
string
.chars()
.map(|c| swap_separator(c, '-'))
.break_camel('-')
.flat_map(char::to_lowercase)
.capitalize_words()
.collect()
}
/// Check to see if a string is Train-Case.
///
/// # Example
/// ```rust
/// # use inflections::case::is_train_case;
/// assert_eq!(is_train_case("Hello-World"), true);
/// assert_eq!(is_train_case("hello world"), false);
/// assert_eq!(is_train_case("HELLO WORLD"), false);
/// assert_eq!(is_train_case("Hello World"), false);
/// assert_eq!(is_train_case("helloWorld"), false);
/// assert_eq!(is_train_case("HelloWorld"), false);
/// assert_eq!(is_train_case("hello-world"), false);
/// assert_eq!(is_train_case("hello_world"), false);
/// assert_eq!(is_train_case("HELLO_WORLD"), false);
pub fn is_train_case(string: &str) -> bool {
string == to_train_case(string)
}
/// Converts any case into snake_case.
///
/// # Example
/// ```rust
/// # use inflections::case::to_snake_case;
/// let snake = "hello_world".to_owned();
/// assert_eq!(to_snake_case("hello world"), snake);
/// assert_eq!(to_snake_case("HELLO WORLD"), snake);
/// assert_eq!(to_snake_case("Hello World"), snake);
/// assert_eq!(to_snake_case("helloWorld"), snake);
/// assert_eq!(to_snake_case("HelloWorld"), snake);
/// assert_eq!(to_snake_case("hello-world"), snake);
/// assert_eq!(to_snake_case("Hello-World"), snake);
/// assert_eq!(to_snake_case("hello_world"), snake);
/// assert_eq!(to_snake_case("HELLO_WORLD"), snake);
/// ```
pub fn to_snake_case(string: &str) -> String {
string
.chars()
.map(|c| swap_separator(c, '_'))
.break_camel('_')
.flat_map(char::to_lowercase)
.collect()
}
/// Check to see if a string is snake_case.
///
/// # Example
/// ```rust
/// # use inflections::case::is_snake_case;
/// assert_eq!(is_snake_case("hello_world"), true);
/// assert_eq!(is_snake_case("hello world"), false);
/// assert_eq!(is_snake_case("HELLO WORLD"), false);
/// assert_eq!(is_snake_case("Hello World"), false);
/// assert_eq!(is_snake_case("helloWorld"), false);
/// assert_eq!(is_snake_case("HelloWorld"), false);
/// assert_eq!(is_snake_case("hello-world"), false);
/// assert_eq!(is_snake_case("Hello-World"), false);
/// assert_eq!(is_snake_case("HELLO_WORLD"), false);
pub fn is_snake_case(string: &str) -> bool {
string == to_snake_case(string)
}
/// Converts any case into CONSTANT_CASE.
///
/// # Example
/// ```rust
/// # use inflections::case::to_constant_case;
/// let constant = "HELLO_WORLD".to_owned();
/// assert_eq!(to_constant_case("hello world"), constant);
/// assert_eq!(to_constant_case("HELLO WORLD"), constant);
/// assert_eq!(to_constant_case("Hello World"), constant);
/// assert_eq!(to_constant_case("helloWorld"), constant);
/// assert_eq!(to_constant_case("HelloWorld"), constant);
/// assert_eq!(to_constant_case("hello-world"), constant);
/// assert_eq!(to_constant_case("Hello-World"), constant);
/// assert_eq!(to_constant_case("hello_world"), constant);
/// assert_eq!(to_constant_case("HELLO_WORLD"), constant);
/// ```
pub fn to_constant_case(string: &str) -> String {
string
.chars()
.map(|c| swap_separator(c, '_'))
.break_camel('_')
.flat_map(char::to_uppercase)
.collect()
}
/// Check to see if a string is CONSTANT_CASE.
///
/// # Example
/// ```rust
/// # use inflections::case::is_constant_case;
/// assert_eq!(is_constant_case("HELLO_WORLD"), true);
/// assert_eq!(is_constant_case("hello world"), false);
/// assert_eq!(is_constant_case("HELLO WORLD"), false);
/// assert_eq!(is_constant_case("Hello World"), false);
/// assert_eq!(is_constant_case("helloWorld"), false);
/// assert_eq!(is_constant_case("HelloWorld"), false);
/// assert_eq!(is_constant_case("hello-world"), false);
/// assert_eq!(is_constant_case("Hello-World"), false);
/// assert_eq!(is_constant_case("hello_world"), false);
pub fn is_constant_case(string: &str) -> bool {
string == to_constant_case(string)
}
/// Checks if a character is a separator.
#[inline]
fn is_separator(c: char) -> bool {
c == ' ' || c == '-' || c == '_'
}
/// Swaps the current character (which may be a separator), with the separator
/// of choice. Currently ' ', '-', and '_' are considered separators which will
/// be swapped.
#[inline]
fn swap_separator(c: char, sep: char) -> char {
if is_separator(c) {
sep
} else {
c
}
}
/// The function to be used with the iterator `scan` method which converts a
/// char iterator into a string iterator which has
/// removed/uppercased/lowercased the bits which need for the conversion to be
/// successful. This would work best with a `flat_scan`.
#[inline]
fn scan_to_camel(state: &mut (bool, Option<char>), curr: char) -> Option<String> {
// Store the last character in the scope and update the state to use the
// current character.
let last = state.1;
state.1 = Some(curr);
if state.0 {
// If the state has signaled the next character must be capitalized,
// capitalize it and mark the state as finished.
state.0 = false;
Some(curr.to_uppercase().collect())
} else if is_separator(curr) {
// If the current character is a separator, mark the state to capitalize
// the next character and remove the separator.
state.0 = true;
Some("".to_owned())
} else if !last.map_or(false, char::is_lowercase) {
// If the last character was not lowercase, this character should be
// lower cased. This magic preserves camelCase strings while lowercasing
// cases like CONSTANT_CASE.
Some(curr.to_lowercase().collect())
} else {
// Otherwise, just return the character.
let mut string = String::with_capacity(1);
string.push(curr);
Some(string)
}
}
/// Trait with some extra methods for the iterators we use.
trait Extras: Iterator<Item=char> {
/// Uses the `BreakCamel` type to break apart camel case strings, i.e.
/// strings like `helloWorld` to `hello world` using the `sep` argument to
/// seperate the new words.
#[inline]
fn break_camel(self, sep: char) -> BreakCamel<Self> where Self: Sized {
BreakCamel {
iter: self.peekable(),
sep: sep,
br: false
}
}
/// Uses the `CapitalizeWords` type to capitilize individual words seperated
/// by a separator (as defined by `is_separator`).
#[inline]
fn capitalize_words(self) -> CapitalizeWords<Self> where Self: Sized {
let mut iter = self.peekable();
// If the first character is not a separator, we want to capitilize it.
let cap = !iter.peek().cloned().map_or(false, is_separator);
CapitalizeWords {
iter: iter,
cap: cap,
upper: None
}
}
}
/// Add the extra methods to the iterators.
impl<I> Extras for I where I: Iterator<Item=char> {}
/// Utility for breaking apart camelCased strings.
struct BreakCamel<I> where I: Iterator<Item=char> {
/// The source iterator.
iter: Peekable<I>,
/// Character to use when breaking apart camelCase strings.
sep: char,
/// Iterator state representing whether the iterator should insert a break.
br: bool
}
impl<I> Iterator for BreakCamel<I> where I: Iterator<Item=char> {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
// If we have been signaled to break, the next item is a separator and we
// should disable break mode.
if self.br {
self.br = false;
return Some(self.sep);
}
match (self.iter.next(), self.iter.peek()) {
// If we have a current character that is lowercase and we have a next
// character that is uppercase, we need to break the string apart next
// time `next` is called.
(Some(curr), Some(next)) if curr.is_lowercase() && next.is_uppercase() => {
self.br = true;
Some(curr)
},
// Otherwise behave as normal.
(Some(curr), _) => Some(curr),
(None, _) => None
}
}
}
/// Utility for capitalizing words.
struct CapitalizeWords<I> where I: Iterator<Item=char> {
/// The source iterator.
iter: Peekable<I>,
/// Iteration state indicating whether or not the next letter should be
/// capitalized.
cap: bool,
/// An iterator for the letter being upper cased.
upper: Option<ToUppercase>
}
impl<I> Iterator for CapitalizeWords<I> where I: Iterator<Item=char> {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
// Note: only one control path should allow this loop to continue.
loop {
// If there is an upper casing still in progress…
if let Some(ref mut upper) = self.upper {
if let Some(next) = upper.next() {
// If there was a character in the uppercase iterator, return it.
return Some(next);
}
}
// If we are here this means we have exhausted the upper case iterator,
// therefore we reset the upper iterator state.
if self.upper.is_some() {
self.upper = None;
}
if let Some(c) = self.iter.next() {
// If there is a character…
if self.cap {
// If we have been signaled to capitalize the next character, disable
// the signal, and enable the capitalization iterator.
self.cap = false;
self.upper = Some(c.to_uppercase());
// We want it to loop back here…
} else {
// Otherwise return the character, but if it is a separator, and the
// next character is not a separator—signal the next character should
// be capitalized.
if is_separator(c) && !self.iter.peek().cloned().map_or(false, is_separator) {
self.cap = true;
}
return Some(c);
}
} else {
// End the iterator.
return None;
}
}
}
}