Move case conversion to its own file
This commit is contained in:
parent
3308f81c3a
commit
7952bad41f
@ -12,6 +12,8 @@ use std::str::FromStr;
|
|||||||
// user will see errors simultaneously for all bad attributes in the crate
|
// user will see errors simultaneously for all bad attributes in the crate
|
||||||
// rather than just the first.
|
// rather than just the first.
|
||||||
|
|
||||||
|
pub use case::RenameRule;
|
||||||
|
|
||||||
struct Attr<'c, T> {
|
struct Attr<'c, T> {
|
||||||
cx: &'c Ctxt,
|
cx: &'c Ctxt,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
@ -86,102 +88,6 @@ impl Name {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum RenameRule {
|
|
||||||
/// Don't apply a default rename rule.
|
|
||||||
None,
|
|
||||||
/// 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenameRule {
|
|
||||||
pub fn apply_to_variant(&self, variant_name: String) -> Result<String, String> {
|
|
||||||
if *self == RenameRule::None {
|
|
||||||
return Ok(variant_name);
|
|
||||||
}
|
|
||||||
let mut chars = variant_name.chars();
|
|
||||||
let start = chars.next().unwrap();
|
|
||||||
if start.is_lowercase() {
|
|
||||||
return Err(format!("#[serde(rename_all = \"...\")] expects enum variants to be \
|
|
||||||
named in `PascalCase`."));
|
|
||||||
}
|
|
||||||
Ok(self.apply_to_words(chars.fold(vec![start.to_lowercase().collect()], |mut words, c| {
|
|
||||||
if c.is_uppercase() {
|
|
||||||
words.push(c.to_lowercase().collect());
|
|
||||||
} else {
|
|
||||||
words.last_mut().unwrap().push(c);
|
|
||||||
}
|
|
||||||
words
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply_to_field(&self, field_name: String) -> Result<String, String> {
|
|
||||||
if *self == RenameRule::None {
|
|
||||||
return Ok(field_name);
|
|
||||||
}
|
|
||||||
if field_name != field_name.to_lowercase() {
|
|
||||||
return Err(format!("#[serde(rename_all = \"...\")] expects fields to be named in \
|
|
||||||
`snake_case`."));
|
|
||||||
}
|
|
||||||
Ok(self.apply_to_words(field_name.split('_').map(|s| s.to_string()).collect()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply_to_words(&self, lowercased_words: Vec<String>) -> String {
|
|
||||||
match *self {
|
|
||||||
RenameRule::PascalCase => Self::capitalising_join(lowercased_words),
|
|
||||||
RenameRule::CamelCase => {
|
|
||||||
let mut iter = lowercased_words.into_iter();
|
|
||||||
let mut first = iter.next().unwrap();
|
|
||||||
first.push_str(Self::capitalising_join(iter.collect()).as_str());
|
|
||||||
first
|
|
||||||
}
|
|
||||||
RenameRule::SnakeCase => Self::delimiting_join(lowercased_words, "_"),
|
|
||||||
RenameRule::ScreamingSnakeCase => Self::delimiting_join(lowercased_words, "_").to_uppercase(),
|
|
||||||
RenameRule::KebabCase => Self::delimiting_join(lowercased_words, "-"),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delimiting_join(lowercased_words: Vec<String>, delimiter: &str) -> String {
|
|
||||||
lowercased_words.join(delimiter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn capitalising_join(lowercased_words: Vec<String>) -> String {
|
|
||||||
lowercased_words.into_iter().map(Self::capitalise).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn capitalise(lowercased_word: String) -> String {
|
|
||||||
let mut iter = lowercased_word.chars();
|
|
||||||
let mut first: String = iter.next().unwrap().to_uppercase().collect();
|
|
||||||
first.push_str(iter.collect::<String>().as_str());
|
|
||||||
first
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for RenameRule {
|
|
||||||
type Err = String;
|
|
||||||
|
|
||||||
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
|
|
||||||
match rename_all_str {
|
|
||||||
"PascalCase" => Ok(RenameRule::PascalCase),
|
|
||||||
"camelCase" => Ok(RenameRule::CamelCase),
|
|
||||||
"snake_case" => Ok(RenameRule::SnakeCase),
|
|
||||||
"SCREAMING_SNAKE_CASE" => Ok(RenameRule::ScreamingSnakeCase),
|
|
||||||
"kebab-case" => Ok(RenameRule::KebabCase),
|
|
||||||
other => Err(other.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents container (e.g. struct) attribute information
|
/// Represents container (e.g. struct) attribute information
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
|
97
serde_codegen_internals/src/case.rs
Normal file
97
serde_codegen_internals/src/case.rs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum RenameRule {
|
||||||
|
/// Don't apply a default rename rule.
|
||||||
|
None,
|
||||||
|
/// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenameRule {
|
||||||
|
pub fn apply_to_variant(&self, variant_name: String) -> Result<String, String> {
|
||||||
|
if *self == RenameRule::None {
|
||||||
|
return Ok(variant_name);
|
||||||
|
}
|
||||||
|
let mut chars = variant_name.chars();
|
||||||
|
let start = chars.next().unwrap();
|
||||||
|
if start.is_lowercase() {
|
||||||
|
return Err(format!("#[serde(rename_all = \"...\")] expects enum variants to be \
|
||||||
|
named in `PascalCase`."));
|
||||||
|
}
|
||||||
|
Ok(self.apply_to_words(chars.fold(vec![start.to_lowercase().collect()], |mut words, c| {
|
||||||
|
if c.is_uppercase() {
|
||||||
|
words.push(c.to_lowercase().collect());
|
||||||
|
} else {
|
||||||
|
words.last_mut().unwrap().push(c);
|
||||||
|
}
|
||||||
|
words
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_to_field(&self, field_name: String) -> Result<String, String> {
|
||||||
|
if *self == RenameRule::None {
|
||||||
|
return Ok(field_name);
|
||||||
|
}
|
||||||
|
if field_name != field_name.to_lowercase() {
|
||||||
|
return Err(format!("#[serde(rename_all = \"...\")] expects fields to be named in \
|
||||||
|
`snake_case`."));
|
||||||
|
}
|
||||||
|
Ok(self.apply_to_words(field_name.split('_').map(|s| s.to_string()).collect()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_to_words(&self, lowercased_words: Vec<String>) -> String {
|
||||||
|
match *self {
|
||||||
|
RenameRule::PascalCase => Self::capitalising_join(lowercased_words),
|
||||||
|
RenameRule::CamelCase => {
|
||||||
|
let mut iter = lowercased_words.into_iter();
|
||||||
|
let mut first = iter.next().unwrap();
|
||||||
|
first.push_str(Self::capitalising_join(iter.collect()).as_str());
|
||||||
|
first
|
||||||
|
}
|
||||||
|
RenameRule::SnakeCase => Self::delimiting_join(lowercased_words, "_"),
|
||||||
|
RenameRule::ScreamingSnakeCase => Self::delimiting_join(lowercased_words, "_").to_uppercase(),
|
||||||
|
RenameRule::KebabCase => Self::delimiting_join(lowercased_words, "-"),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delimiting_join(lowercased_words: Vec<String>, delimiter: &str) -> String {
|
||||||
|
lowercased_words.join(delimiter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capitalising_join(lowercased_words: Vec<String>) -> String {
|
||||||
|
lowercased_words.into_iter().map(Self::capitalise).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capitalise(lowercased_word: String) -> String {
|
||||||
|
let mut iter = lowercased_word.chars();
|
||||||
|
let mut first: String = iter.next().unwrap().to_uppercase().collect();
|
||||||
|
first.push_str(iter.collect::<String>().as_str());
|
||||||
|
first
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for RenameRule {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
|
||||||
|
match rename_all_str {
|
||||||
|
"PascalCase" => Ok(RenameRule::PascalCase),
|
||||||
|
"camelCase" => Ok(RenameRule::CamelCase),
|
||||||
|
"snake_case" => Ok(RenameRule::SnakeCase),
|
||||||
|
"SCREAMING_SNAKE_CASE" => Ok(RenameRule::ScreamingSnakeCase),
|
||||||
|
"kebab-case" => Ok(RenameRule::KebabCase),
|
||||||
|
other => Err(other.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,3 +5,5 @@ pub mod attr;
|
|||||||
|
|
||||||
mod ctxt;
|
mod ctxt;
|
||||||
pub use ctxt::Ctxt;
|
pub use ctxt::Ctxt;
|
||||||
|
|
||||||
|
mod case;
|
||||||
|
Loading…
Reference in New Issue
Block a user