16fccd0a4Sopenharmony_ciuse std::fmt;
26fccd0a4Sopenharmony_ci
36fccd0a4Sopenharmony_ciuse crate::{lowercase, transform};
46fccd0a4Sopenharmony_ci
56fccd0a4Sopenharmony_ci/// This trait defines a snake case conversion.
66fccd0a4Sopenharmony_ci///
76fccd0a4Sopenharmony_ci/// In snake_case, word boundaries are indicated by underscores.
86fccd0a4Sopenharmony_ci///
96fccd0a4Sopenharmony_ci/// ## Example:
106fccd0a4Sopenharmony_ci///
116fccd0a4Sopenharmony_ci/// ```rust
126fccd0a4Sopenharmony_ci/// use heck::ToSnakeCase;
136fccd0a4Sopenharmony_ci///
146fccd0a4Sopenharmony_ci/// let sentence = "We carry a new world here, in our hearts.";
156fccd0a4Sopenharmony_ci/// assert_eq!(sentence.to_snake_case(), "we_carry_a_new_world_here_in_our_hearts");
166fccd0a4Sopenharmony_ci/// ```
176fccd0a4Sopenharmony_cipub trait ToSnakeCase: ToOwned {
186fccd0a4Sopenharmony_ci    /// Convert this type to snake case.
196fccd0a4Sopenharmony_ci    fn to_snake_case(&self) -> Self::Owned;
206fccd0a4Sopenharmony_ci}
216fccd0a4Sopenharmony_ci
226fccd0a4Sopenharmony_ci/// Oh heck, SnekCase is an alias for ToSnakeCase. See ToSnakeCase for
236fccd0a4Sopenharmony_ci/// more documentation.
246fccd0a4Sopenharmony_cipub trait ToSnekCase: ToOwned {
256fccd0a4Sopenharmony_ci    /// Convert this type to snek case.
266fccd0a4Sopenharmony_ci    fn to_snek_case(&self) -> Self::Owned;
276fccd0a4Sopenharmony_ci}
286fccd0a4Sopenharmony_ci
296fccd0a4Sopenharmony_ciimpl<T: ?Sized + ToSnakeCase> ToSnekCase for T {
306fccd0a4Sopenharmony_ci    fn to_snek_case(&self) -> Self::Owned {
316fccd0a4Sopenharmony_ci        self.to_snake_case()
326fccd0a4Sopenharmony_ci    }
336fccd0a4Sopenharmony_ci}
346fccd0a4Sopenharmony_ci
356fccd0a4Sopenharmony_ciimpl ToSnakeCase for str {
366fccd0a4Sopenharmony_ci    fn to_snake_case(&self) -> String {
376fccd0a4Sopenharmony_ci        AsSnakeCase(self).to_string()
386fccd0a4Sopenharmony_ci    }
396fccd0a4Sopenharmony_ci}
406fccd0a4Sopenharmony_ci
416fccd0a4Sopenharmony_ci/// This wrapper performs a snake case conversion in [`fmt::Display`].
426fccd0a4Sopenharmony_ci///
436fccd0a4Sopenharmony_ci/// ## Example:
446fccd0a4Sopenharmony_ci///
456fccd0a4Sopenharmony_ci/// ```
466fccd0a4Sopenharmony_ci/// use heck::AsSnakeCase;
476fccd0a4Sopenharmony_ci///
486fccd0a4Sopenharmony_ci/// let sentence = "We carry a new world here, in our hearts.";
496fccd0a4Sopenharmony_ci/// assert_eq!(format!("{}", AsSnakeCase(sentence)), "we_carry_a_new_world_here_in_our_hearts");
506fccd0a4Sopenharmony_ci/// ```
516fccd0a4Sopenharmony_cipub struct AsSnakeCase<T: AsRef<str>>(pub T);
526fccd0a4Sopenharmony_ci
536fccd0a4Sopenharmony_ciimpl<T: AsRef<str>> fmt::Display for AsSnakeCase<T> {
546fccd0a4Sopenharmony_ci    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
556fccd0a4Sopenharmony_ci        transform(self.0.as_ref(), lowercase, |f| write!(f, "_"), f)
566fccd0a4Sopenharmony_ci    }
576fccd0a4Sopenharmony_ci}
586fccd0a4Sopenharmony_ci
596fccd0a4Sopenharmony_ci#[cfg(test)]
606fccd0a4Sopenharmony_cimod tests {
616fccd0a4Sopenharmony_ci    use super::ToSnakeCase;
626fccd0a4Sopenharmony_ci
636fccd0a4Sopenharmony_ci    macro_rules! t {
646fccd0a4Sopenharmony_ci        ($t:ident : $s1:expr => $s2:expr) => {
656fccd0a4Sopenharmony_ci            #[test]
666fccd0a4Sopenharmony_ci            fn $t() {
676fccd0a4Sopenharmony_ci                assert_eq!($s1.to_snake_case(), $s2)
686fccd0a4Sopenharmony_ci            }
696fccd0a4Sopenharmony_ci        };
706fccd0a4Sopenharmony_ci    }
716fccd0a4Sopenharmony_ci
726fccd0a4Sopenharmony_ci    t!(test1: "CamelCase" => "camel_case");
736fccd0a4Sopenharmony_ci    t!(test2: "This is Human case." => "this_is_human_case");
746fccd0a4Sopenharmony_ci    t!(test3: "MixedUP CamelCase, with some Spaces" => "mixed_up_camel_case_with_some_spaces");
756fccd0a4Sopenharmony_ci    t!(test4: "mixed_up_ snake_case with some _spaces" => "mixed_up_snake_case_with_some_spaces");
766fccd0a4Sopenharmony_ci    t!(test5: "kebab-case" => "kebab_case");
776fccd0a4Sopenharmony_ci    t!(test6: "SHOUTY_SNAKE_CASE" => "shouty_snake_case");
786fccd0a4Sopenharmony_ci    t!(test7: "snake_case" => "snake_case");
796fccd0a4Sopenharmony_ci    t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "this_contains_all_kinds_of_word_boundaries");
806fccd0a4Sopenharmony_ci    #[cfg(feature = "unicode")]
816fccd0a4Sopenharmony_ci    t!(test9: "XΣXΣ baffle" => "xσxς_baffle");
826fccd0a4Sopenharmony_ci    t!(test10: "XMLHttpRequest" => "xml_http_request");
836fccd0a4Sopenharmony_ci    t!(test11: "FIELD_NAME11" => "field_name11");
846fccd0a4Sopenharmony_ci    t!(test12: "99BOTTLES" => "99bottles");
856fccd0a4Sopenharmony_ci    t!(test13: "FieldNamE11" => "field_nam_e11");
866fccd0a4Sopenharmony_ci
876fccd0a4Sopenharmony_ci    t!(test14: "abc123def456" => "abc123def456");
886fccd0a4Sopenharmony_ci    t!(test16: "abc123DEF456" => "abc123_def456");
896fccd0a4Sopenharmony_ci    t!(test17: "abc123Def456" => "abc123_def456");
906fccd0a4Sopenharmony_ci    t!(test18: "abc123DEf456" => "abc123_d_ef456");
916fccd0a4Sopenharmony_ci    t!(test19: "ABC123def456" => "abc123def456");
926fccd0a4Sopenharmony_ci    t!(test20: "ABC123DEF456" => "abc123def456");
936fccd0a4Sopenharmony_ci    t!(test21: "ABC123Def456" => "abc123_def456");
946fccd0a4Sopenharmony_ci    t!(test22: "ABC123DEf456" => "abc123d_ef456");
956fccd0a4Sopenharmony_ci    t!(test23: "ABC123dEEf456FOO" => "abc123d_e_ef456_foo");
966fccd0a4Sopenharmony_ci    t!(test24: "abcDEF" => "abc_def");
976fccd0a4Sopenharmony_ci    t!(test25: "ABcDE" => "a_bc_de");
986fccd0a4Sopenharmony_ci}
99