Loading pageâŚ
Rust walkthroughs
Loading pageâŚ
heck::ToTitleCase for human-readable title formatting?heck::ToTitleCase is a trait implementation that transforms identifiers from programming conventions like snake_case, camelCase, or kebab-case into properly formatted human-readable titles with appropriate capitalization and spacing. The heck crate provides case conversion traits that handle the mechanical work of splitting compound identifiers on word boundaries, capitalizing first letters appropriately, and joining with spacesâproducing output suitable for user interfaces, documentation generation, or any context where machine identifiers need human presentation. ToTitleCase specifically follows title case conventions where each significant word is capitalized, making it distinct from ToUpperCamelCase (which produces PascalCase without spaces) or ToSentenceCase (which capitalizes only the first word). The trait works on any type implementing AsRef<str>, and its to_title_case() method returns a String with the transformed output, handling edge cases like consecutive capitals (e.g., "XMLHttpRequest" becomes "Xml Http Request") and preserving numbers as separate words.
use heck::ToTitleCase;
fn main() {
// Snake case to title case
let snake = "user_account_settings";
println!("{}", snake.to_title_case()); // "User Account Settings"
// Kebab case to title case
let kebab = "background-color";
println!("{}", kebab.to_title_case()); // "Background Color"
// Camel case to title case
let camel = "firstName";
println!("{}", camel.to_title_case()); // "First Name"
// Pascal case to title case
let pascal = "HttpRequestHandler";
println!("{}", pascal.to_title_case()); // "Http Request Handler"
}ToTitleCase handles multiple input formats and produces consistent title output.
use heck::ToTitleCase;
fn main() {
// Detects boundaries at:
// 1. Underscores
println!("{}", "user_name".to_title_case()); // "User Name"
// 2. Hyphens
println!("{}", "background-color".to_title_case()); // "Background Color"
// 3. Spaces
println!("{}", "error message".to_title_case()); // "Error Message"
// 4. Transitions from lowercase to uppercase
println!("{}", "camelCase".to_title_case()); // "Camel Case"
// 5. Transitions from uppercase to lowercase (acronyms)
println!("{}", "XMLParser".to_title_case()); // "Xml Parser"
// 6. Numbers
println!("{}", "version2Update".to_title_case()); // "Version 2 Update"
}The trait uses heuristics to detect word boundaries in various naming conventions.
use heck::{ToTitleCase, ToUpperCamelCase, ToLowerCamelCase, ToSnakeCase, ToKebabCase};
fn main() {
let input = "user_account_settings";
// Title case: words with spaces, each capitalized
println!("Title: {}", input.to_title_case()); // "User Account Settings"
// Upper camel case (PascalCase): no spaces, each word capitalized
println!("UpperCamel: {}", input.to_upper_camel_case()); // "UserAccountSettings"
// Lower camel case: no spaces, first word lowercase
println!("LowerCamel: {}", input.to_lower_camel_case()); // "userAccountSettings"
// Snake case: underscores, all lowercase
println!("Snake: {}", input.to_snake_case()); // "user_account_settings"
// Kebab case: hyphens, all lowercase
println!("Kebab: {}", input.to_kebab_case()); // "user-account-settings"
}Each trait produces a specific format suitable for different contexts.
use heck::ToTitleCase;
fn main() {
// Acronyms are split intelligently
println!("{}", "XMLHttpRequest".to_title_case()); // "Xml Http Request"
println!("{}", "IOError".to_title_case()); // "Io Error"
println!("{}", "HTTPSConnection".to_title_case()); // "Https Connection"
// Numbers create word boundaries
println!("{}", "UTF8Encoding".to_title_case()); // "Utf 8 Encoding"
println!("{}", "Model3Prediction".to_title_case()); // "Model 3 Prediction"
// Consecutive capitals
println!("{}", "HTMLParser".to_title_case()); // "Html Parser"
// Mixed scenarios
println!("{}", "API2JSONConverter".to_title_case()); // "Api 2 Json Converter"
}Word boundaries are detected heuristically for natural splitting.
use heck::ToTitleCase;
struct UserSettings {
first_name: String,
last_name: String,
email_address: String,
phone_number: String,
date_of_birth: String,
}
fn generate_form_labels() {
let fields = [
"first_name",
"last_name",
"email_address",
"phone_number",
"date_of_birth",
];
for field in fields {
println!("<label>{}</label>", field.to_title_case());
println!(" <input name=\"{}\" />", field);
}
// Output:
// <label>First Name</label>
// <input name="first_name" />
// <label>Last Name</label>
// <input name="last_name" />
// ... etc
}ToTitleCase generates user-friendly labels from database field names.
use heck::ToTitleCase;
struct ApiEndpoint {
name: String,
description: String,
}
fn generate_documentation(endpoints: &[ApiEndpoint]) {
println!("# API Documentation\n");
for endpoint in endpoints {
// Convert endpoint name to title for section header
println!("## {}", endpoint.name.to_title_case());
println!("{}\n", endpoint.description);
}
}
fn main() {
let endpoints = [
ApiEndpoint {
name: "get_user_profile".to_string(),
description: "Retrieves the profile information for a specific user.".to_string(),
},
ApiEndpoint {
name: "update_account_settings".to_string(),
description: "Updates the account settings for the authenticated user.".to_string(),
},
ApiEndpoint {
name: "delete_user_session".to_string(),
description: "Terminates an active user session.".to_string(),
},
];
generate_documentation(&endpoints);
// Output:
// # API Documentation
//
// ## Get User Profile
// Retrieves the profile information for a specific user.
//
// ## Update Account Settings
// Updates the account settings for the authenticated user.
// ...
}Documentation tools use title case for section headers.
use heck::ToTitleCase;
enum ValidationError {
InvalidEmailAddress,
PhoneNumberTooShort,
DateOfBirthInvalid,
PasswordMismatch,
}
impl std::fmt::Display for ValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let variant_name = match self {
ValidationError::InvalidEmailAddress => "invalid_email_address",
ValidationError::PhoneNumberTooShort => "phone_number_too_short",
ValidationError::DateOfBirthInvalid => "date_of_birth_invalid",
ValidationError::PasswordMismatch => "password_mismatch",
};
// Convert enum variant to human-readable error
write!(f, "{}", variant_name.to_title_case())
}
}
fn main() {
let error = ValidationError::InvalidEmailAddress;
println!("Error: {}", error); // "Error: Invalid Email Address"
}Enum variants are converted to human-readable error messages.
use heck::ToTitleCase;
struct CliOption {
name: &'static str,
short: char,
description: &'static str,
}
fn print_help(options: &[CliOption]) {
println!("Usage: myapp [OPTIONS]\n");
println!("Options:\n");
for option in options {
let title = option.name.to_title_case();
println!(" -{}, --{:15} {}", option.short, option.name, option.description);
// Could use title for grouping or extended help
}
}
fn main() {
let options = [
CliOption { name: "input_file", short: 'i', description: "Input file path" },
CliOption { name: "output_directory", short: 'o', description: "Output directory path" },
CliOption { name: "max_threads", short: 't', description: "Maximum thread count" },
CliOption { name: "verbose_mode", short: 'v', description: "Enable verbose output" },
];
print_help(&options);
}CLI help text can use title case for option descriptions.
use heck::ToTitleCase;
// The trait is defined as:
// trait ToTitleCase {
// fn to_title_case(&self) -> String;
// }
// It's implemented for all types that implement AsRef<str>
// This includes &str, String, &String, etc.
fn main() {
// Works on &str
let s: &str = "hello_world";
println!("{}", s.to_title_case()); // "Hello World"
// Works on String
let s: String = String::from("hello_world");
println!("{}", s.to_title_case()); // "Hello World"
// Works on &String
let s: String = String::from("hello_world");
let ref_s: &String = &s;
println!("{}", ref_s.to_title_case()); // "Hello World"
// Works on any type implementing AsRef<str>
struct MyString(String);
impl AsRef<str> for MyString {
fn as_ref(&self) -> &str {
&self.0
}
}
let my_string = MyString("custom_type".to_string());
println!("{}", my_string.to_title_case()); // "Custom Type"
}The trait works on any type that can provide a string reference.
use heck::ToTitleCase;
fn main() {
// heck's ToTitleCase capitalizes every word
println!("{}", "the_quick_brown_fox".to_title_case()); // "The Quick Brown Fox"
// Some style guides don't capitalize articles/prepositions
// heck doesn't have special handling for these
println!("{}", "a_tale_of_two_cities".to_title_case());
// "A Tale Of Two Cities" (not "A Tale of Two Cities")
println!("{}", "lord_of_the_rings".to_title_case());
// "Lord Of The Rings" (not "Lord of the Rings")
// For publication-style title case, you'd need custom logic
// to handle articles, conjunctions, and prepositions
}ToTitleCase capitalizes every word, without special handling for articles/prepositions.
use heck::ToTitleCase;
fn main() {
// Empty string
println!("{}", "".to_title_case()); // ""
// Single word
println!("{}", "hello".to_title_case()); // "Hello"
// Already title case (preserved)
println!("{}", "Hello World".to_title_case()); // "Hello World"
// All uppercase (converted)
println!("{}", "HELLO_WORLD".to_title_case()); // "Hello World"
// Mixed separators
println!("{}", "user_name-full_name".to_title_case()); // "User Name Full Name"
// Numbers only
println!("{}", "123".to_title_case()); // "123"
// Numbers and letters
println!("{}", "user2fa".to_title_case()); // "User 2 Fa"
// Multiple consecutive separators
println!("{}", "user__name".to_title_case()); // "User Name"
println!("{}", "user--name".to_title_case()); // "User Name"
}The implementation handles various edge cases gracefully.
use heck::ToTitleCase;
fn main() {
// ToTitleCase allocates a new String
// The conversion involves:
// 1. Splitting on word boundaries (scanning the input)
// 2. Allocating output String with estimated capacity
// 3. For each word: capitalize first char, lowercase rest
let input = "very_long_snake_case_identifier_with_many_words";
let title = input.to_title_case();
// The output String is typically longer than input due to spaces
// Input: 46 chars
// Output: 50+ chars (spaces added)
// For repeated conversions of the same string, cache the result
// rather than calling to_title_case() multiple times
}The conversion allocates a new String with appropriate capacity.
use heck::{ToTitleCase, ToSnakeCase, ToKebabCase, ToUpperCamelCase};
fn demonstrate_conversions(input: &str) {
println!("Input: {}", input);
println!(" Title Case: {}", input.to_title_case());
println!(" Snake Case: {}", input.to_snake_case());
println!(" Kebab Case: {}", input.to_kebab_case());
println!(" Pascal Case: {}", input.to_upper_camel_case());
}
fn main() {
demonstrate_conversions("userAccountSettings");
demonstrate_conversions("background-color");
demonstrate_conversions("HttpRequestHandler");
// Output:
// Input: userAccountSettings
// Title Case: User Account Settings
// Snake Case: user_account_settings
// Kebab Case: user-account-settings
// Pascal Case: UserAccountSettings
//
// Input: background-color
// Title Case: Background Color
// Snake Case: background_color
// Kebab Case: background-color
// Pascal Case: BackgroundColor
}The heck crate provides complementary case conversion traits.
use heck::ToTitleCase;
// If you need publication-style title case (not capitalizing articles/prepositions)
fn publication_title_case(input: &str) -> String {
let lowercase_words = ["a", "an", "the", "and", "but", "or", "for", "nor",
"on", "at", "to", "from", "by", "of", "in"];
let words: Vec<String> = input.to_title_case()
.split(' ')
.map(|s| s.to_lowercase())
.collect();
words.iter().enumerate().map(|(i, word)| {
// Always capitalize first and last word
if i == 0 || i == words.len() - 1 {
// Capitalize first character
let mut chars = word.chars();
match chars.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
}
} else if lowercase_words.contains(&word.as_str()) {
word.to_string()
} else {
// Capitalize first character
let mut chars = word.chars();
match chars.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
}
}
}).collect::<Vec<_>>().join(" ")
}
fn main() {
let input = "a_tale_of_two_cities";
println!("heck: {}", input.to_title_case()); // "A Tale Of Two Cities"
println!("custom: {}", publication_title_case(input)); // "A Tale of Two Cities"
}Custom logic can extend ToTitleCase for specific style guide requirements.
Case conversion matrix:
| Input | to_title_case | to_upper_camel_case | to_lower_camel_case |
|-------|-----------------|----------------------|----------------------|
| user_name | "User Name" | "UserName" | "userName" |
| XMLParser | "Xml Parser" | "XmlParser" | "xmlParser" |
| HTTPResponse | "Http Response" | "HttpResponse" | "httpResponse" |
| model_3 | "Model 3" | "Model3" | "model3" |
When to use ToTitleCase:
| Use Case | Appropriate |
|----------|-------------|
| UI labels from field names | â |
| Error message formatting | â |
| Documentation section headers | â |
| Enum variant display | â |
| Publication titles | â (custom logic needed) |
| URLs/slugification | â (use to_snake_case or to_kebab_case) |
| Code identifiers | â (use camel case variants) |
Key insight: heck::ToTitleCase serves a specific niche in the ecosystem of case conversion: transforming machine-readable identifiers into human-readable titles. Its value proposition is that it handles the mechanical complexity of word boundary detection across multiple naming conventionsâunderscores, hyphens, camel case transitions, and number boundariesâand produces consistent output without requiring manual specification of where words split. This is particularly valuable in contexts where identifiers are defined in one place (like database schemas, API definitions, or enum variants) but displayed to users elsewhere. The trait's implementation is deterministic and consistent, making it reliable for automated use cases like documentation generators or CLI help text. However, it doesn't implement publication-style title case rules (like lowercasing articles and prepositions), so for content destined for publication or formal titles, custom logic is needed. The heck crate's design philosophyâproviding composable traits rather than functionsâfits Rust's trait system naturally, allowing to_title_case() to be called on any string-like type, and the various case conversion traits can be chained or selected based on the target format needed.