Skip to content

Instantly share code, notes, and snippets.

@tondrej
Created December 26, 2025 19:15
Show Gist options
  • Select an option

  • Save tondrej/e9e9e77b23d462cf349abda01579baa5 to your computer and use it in GitHub Desktop.

Select an option

Save tondrej/e9e9e77b23d462cf349abda01579baa5 to your computer and use it in GitHub Desktop.
toggle_case(s: &str) -> String
use std::char::{ToLowercase, ToUppercase};
use std::iter::Once;
/// E0308 incompatible types
/// closure must return a single concrete iterator type
/*
pub fn toggle_case(s: &str) -> String {
s.chars()
.flat_map(|c| {
if c.is_lowercase() {
c.to_uppercase()
} else if c.is_uppercase() {
c.to_lowercase()
} else {
std::iter::once(c)
}
})
}
*/
/// solution 1: dynamic dispatch via Box<dyn Iterator<Item = char>>
pub fn toggle_case1(s: &str) -> String {
s.chars()
.flat_map(|c| {
if c.is_lowercase() {
Box::new(c.to_uppercase()) as Box<dyn Iterator<Item = char>>
} else if c.is_uppercase() {
Box::new(c.to_lowercase()) as Box<dyn Iterator<Item = char>>
} else {
Box::new(std::iter::once(c)) as Box<dyn Iterator<Item = char>>
}
})
.collect()
}
/// solution 2: heap String, extend
pub fn toggle_case2(s: &str) -> String {
let mut result = String::with_capacity(s.len());
for c in s.chars() {
if c.is_lowercase() {
result.extend(c.to_uppercase());
} else if c.is_uppercase() {
result.extend(c.to_lowercase());
} else {
result.push(c);
}
}
result
}
/// solution 3: wrap/implement IntoIterator
pub enum CharCaseToggle {
Upper(ToUppercase),
Lower(ToLowercase),
Same(Once<char>)
}
impl IntoIterator for CharCaseToggle {
type Item = char;
type IntoIter = CharCaseToggleIntoIterator;
fn into_iter(self) -> Self::IntoIter {
CharCaseToggleIntoIterator { toggle: self }
}
}
pub struct CharCaseToggleIntoIterator {
toggle: CharCaseToggle
}
impl Iterator for CharCaseToggleIntoIterator {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
let toggle = &mut self.toggle;
match toggle {
CharCaseToggle::Upper(upper) => upper.next(),
CharCaseToggle::Lower(lower) => lower.next(),
CharCaseToggle::Same(same) => same.next()
}
}
}
impl CharCaseToggle {
pub fn iter(c: char) -> impl Iterator<Item = char> {
if c.is_lowercase() {
CharCaseToggle::Upper(c.to_uppercase()).into_iter()
} else if c.is_uppercase() {
CharCaseToggle::Lower(c.to_lowercase()).into_iter()
} else {
CharCaseToggle::Same(std::iter::once(c)).into_iter()
}
}
}
pub fn toggle_case3(s: &str) -> String {
s.chars()
.flat_map(CharCaseToggle::iter)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_toggle_case1() {
let result = toggle_case1("Hello, World!");
assert_eq!(result, "hELLO, wORLD!");
}
#[test]
fn test_toggle_case2() {
let result = toggle_case2("Hello, World!");
assert_eq!(result, "hELLO, wORLD!");
}
#[test]
fn test_toggle_case3() {
let result = toggle_case3("Hello, World!");
assert_eq!(result, "hELLO, wORLD!");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment