| // Copyright 2017 Serde Developers |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| #[allow(unused_imports)] |
| use std::str::FromStr; |
| |
| use self::RenameRule::*; |
| |
| #[derive(Debug, PartialEq)] |
| pub enum RenameRule { |
| /// Don't apply a default rename rule. |
| None, |
| /// Rename direct children to "lowercase" style. |
| LowerCase, |
| /// Rename direct children to "PascalCase" style, as typically used for enum variants. |
| PascalCase, |
| /// Rename direct children to "camelCase" style. |
| CamelCase, |
| /// Rename direct children to "snake_case" style, as commonly used for fields. |
| SnakeCase, |
| /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly used for constants. |
| ScreamingSnakeCase, |
| /// Rename direct children to "kebab-case" style. |
| KebabCase, |
| /// Rename direct children to "SCREAMING-KEBAB-CASE" style. |
| ScreamingKebabCase |
| } |
| |
| impl RenameRule { |
| pub fn apply_to_variant(&self, variant: &str) -> String { |
| match *self { |
| None | PascalCase => variant.to_owned(), |
| LowerCase => variant.to_ascii_lowercase(), |
| CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], |
| SnakeCase => { |
| let mut snake = String::new(); |
| for (i, ch) in variant.char_indices() { |
| if i > 0 && ch.is_uppercase() { |
| snake.push('_'); |
| } |
| snake.push(ch.to_ascii_lowercase()); |
| } |
| snake |
| } |
| ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), |
| KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), |
| ScreamingKebabCase => ScreamingSnakeCase.apply_to_variant(variant).replace('_', "-") |
| } |
| } |
| |
| pub fn apply_to_field(&self, field: &str) -> String { |
| match *self { |
| None | LowerCase | SnakeCase => field.to_owned(), |
| PascalCase => { |
| let mut pascal = String::new(); |
| let mut capitalize = true; |
| for ch in field.chars() { |
| if ch == '_' { |
| capitalize = true; |
| } else if capitalize { |
| pascal.push(ch.to_ascii_uppercase()); |
| capitalize = false; |
| } else { |
| pascal.push(ch); |
| } |
| } |
| pascal |
| } |
| CamelCase => { |
| let pascal = PascalCase.apply_to_field(field); |
| pascal[..1].to_ascii_lowercase() + &pascal[1..] |
| } |
| ScreamingSnakeCase => field.to_ascii_uppercase(), |
| KebabCase => field.replace('_', "-"), |
| ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-") |
| } |
| } |
| } |
| |
| impl FromStr for RenameRule { |
| type Err = (); |
| |
| fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> { |
| match rename_all_str { |
| "lowercase" => Ok(LowerCase), |
| "PascalCase" => Ok(PascalCase), |
| "camelCase" => Ok(CamelCase), |
| "snake_case" => Ok(SnakeCase), |
| "SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase), |
| "kebab-case" => Ok(KebabCase), |
| "SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase), |
| _ => Err(()), |
| } |
| } |
| } |
| |
| #[test] |
| fn rename_variants() { |
| for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in |
| &[ |
| ("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"), |
| ("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"), |
| ("A", "a", "a", "a", "A", "a", "A"), |
| ("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"), |
| ] { |
| assert_eq!(None.apply_to_variant(original), original); |
| assert_eq!(LowerCase.apply_to_variant(original), lower); |
| assert_eq!(PascalCase.apply_to_variant(original), original); |
| assert_eq!(CamelCase.apply_to_variant(original), camel); |
| assert_eq!(SnakeCase.apply_to_variant(original), snake); |
| assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming); |
| assert_eq!(KebabCase.apply_to_variant(original), kebab); |
| assert_eq!(ScreamingKebabCase.apply_to_variant(original), screaming_kebab); |
| } |
| } |
| |
| #[test] |
| fn rename_fields() { |
| for &(original, pascal, camel, screaming, kebab, screaming_kebab) in |
| &[ |
| ("outcome", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"), |
| ("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"), |
| ("a", "A", "a", "A", "a", "A"), |
| ("z42", "Z42", "z42", "Z42", "z42", "Z42"), |
| ] { |
| assert_eq!(None.apply_to_field(original), original); |
| assert_eq!(PascalCase.apply_to_field(original), pascal); |
| assert_eq!(CamelCase.apply_to_field(original), camel); |
| assert_eq!(SnakeCase.apply_to_field(original), original); |
| assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming); |
| assert_eq!(KebabCase.apply_to_field(original), kebab); |
| assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab); |
| } |
| } |