diff --git a/src/core/utils/string.rs b/src/core/utils/string.rs index 106d0cb77d387631366b2eb5d9a9db26d109099d..fc3891dfb0f7c0afb3fb0b391d6f41126fbf42d9 100644 --- a/src/core/utils/string.rs +++ b/src/core/utils/string.rs @@ -1,4 +1,4 @@ -use crate::Result; +use crate::{utils::exchange, Result}; pub const EMPTY: &str = ""; @@ -26,6 +26,41 @@ macro_rules! is_format { }; } +#[inline] +#[must_use] +pub fn camel_to_snake_string(s: &str) -> String { + let est_len = s + .chars() + .fold(s.len(), |est, c| est.saturating_add(usize::from(c.is_ascii_uppercase()))); + + let mut ret = String::with_capacity(est_len); + camel_to_snake_case(&mut ret, s.as_bytes()).expect("string-to-string stream error"); + ret +} + +#[inline] +pub fn camel_to_snake_case<I, O>(output: &mut O, input: I) -> Result<()> +where + I: std::io::Read, + O: std::fmt::Write, +{ + let mut state = false; + input + .bytes() + .take_while(Result::is_ok) + .map(Result::unwrap) + .map(char::from) + .try_for_each(|ch| { + let m = ch.is_ascii_uppercase(); + let s = exchange(&mut state, !m); + if m && s { + output.write_char('_')?; + } + output.write_char(ch.to_ascii_lowercase())?; + Result::<()>::Ok(()) + }) +} + /// Find the common prefix from a collection of strings and return a slice /// ``` /// use conduit_core::utils::string::common_prefix; diff --git a/src/core/utils/tests.rs b/src/core/utils/tests.rs index 4396894704a909fad8e3e02a7891b32147565e3f..e91accdf49fcc77c3910177ce5a5e68892964e79 100644 --- a/src/core/utils/tests.rs +++ b/src/core/utils/tests.rs @@ -134,3 +134,19 @@ async fn mutex_map_contend() { tokio::try_join!(join_b, join_a).expect("joined"); assert!(map.is_empty(), "Must be empty"); } + +#[test] +fn camel_to_snake_case_0() { + use utils::string::camel_to_snake_string; + + let res = camel_to_snake_string("CamelToSnakeCase"); + assert_eq!(res, "camel_to_snake_case"); +} + +#[test] +fn camel_to_snake_case_1() { + use utils::string::camel_to_snake_string; + + let res = camel_to_snake_string("CAmelTOSnakeCase"); + assert_eq!(res, "camel_tosnake_case"); +}