1mod archetype;
2mod code;
3mod component;
4mod ecs;
5mod state;
6mod system;
7mod system_scheduler;
8mod world;
9
10pub use crate::code::EcsCode;
11use serde::Serialize;
12use std::fmt::{Display, Formatter};
13
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
15pub struct Name {
16 #[serde(rename = "type")]
17 pub type_name: String,
18 #[serde(rename = "raw")]
19 pub type_name_raw: String,
20 #[serde(rename = "field")]
21 pub field_name: String,
22 #[serde(rename = "fields")]
23 pub field_name_plural: String,
24}
25
26impl Name {
27 pub fn new(type_name: String, type_suffix: &str) -> Self {
28 let field_name = pascal_to_snake(&type_name);
29 let field_name_plural = pluralize_name(field_name.clone());
30 let adjusted_type_name = if type_name.ends_with(type_suffix) {
31 type_name.clone()
32 } else {
33 format!("{type_name}{type_suffix}")
34 };
35 Self {
36 type_name: adjusted_type_name,
37 type_name_raw: type_name,
38 field_name,
39 field_name_plural,
40 }
41 }
42}
43
44impl Display for Name {
45 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46 f.write_str(&self.type_name)
47 }
48}
49
50fn pluralize_name(field_name: String) -> String {
51 let field_name = if let Some(prefix) = field_name.strip_suffix('y') {
52 format!("{prefix}ies")
53 } else if !field_name.ends_with('s') {
54 format!("{field_name}s")
55 } else {
56 field_name
57 };
58 field_name
59}
60
61fn snake_case_filter(value: String) -> String {
62 pascal_to_snake(value.trim())
63}
64
65fn pascal_to_snake(type_name: &str) -> String {
66 let field_name = type_name
67 .chars()
68 .flat_map(|c| {
69 if c.is_uppercase() {
70 vec!['_', c.to_ascii_lowercase()]
71 } else {
72 vec![c]
73 }
74 })
75 .skip_while(|&c| c == '_')
76 .collect::<String>();
77 field_name
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_pascal_to_snake() {
86 let cases = vec![
87 ("PascalCase", "pascal_case"),
88 ("SnakeCase", "snake_case"),
89 ("HTTPServer", "h_t_t_p_server"),
90 ("", ""),
91 ("lowercase", "lowercase"),
92 ("UPPERCASE", "u_p_p_e_r_c_a_s_e"),
93 ("Mixed123Case", "mixed123_case"),
94 ];
95
96 for (input, expected) in cases {
97 assert_eq!(pascal_to_snake(&input.to_string()), expected);
98 }
99 }
100}