///|
fn convert_args(args : String) -> Map[String, String] {
let params : Map[String, String] = Map([])
let parts = args.split(",")
let mut current_key = None
for part in parts {
let key_value = part.split("=").collect()
if key_value.length() == 2 {
let key = key_value[0].trim()
let value = key_value[1].trim()
if key.is_empty() || value.is_empty() {
current_key = None
continue
}
params[key.to_owned()] = value.to_owned()
current_key = Some(key.to_owned())
} else if key_value.length() == 1 {
let value = part.trim()
if !value.is_empty() {
if current_key is Some(key) {
params[key] = "\{params.get(key).unwrap()},\{value}"
}
}
}
}
return params
}
///|
test "convert_args preserves comma-separated derive values" {
let args = convert_args(
"json=true,derive=Debug,Eq,Hash,Compare,Arbitrary,username=moon",
)
inspect(
args.get("derive").unwrap(),
content="Debug,Eq,Hash,Compare,Arbitrary",
)
inspect(args.get("username").unwrap(), content="moon")
}
///|
fn title(s : String) -> String {
let sb = StringBuilder()
let mut is_word_start = true
for c in s {
if c == ' ' {
sb.write_char(' ')
is_word_start = true
} else if is_word_start {
sb.write_char(c.to_ascii_uppercase())
is_word_start = false
} else {
sb.write_char(c)
}
}
sb.to_string()
}
///|
test "title" {
inspect(title("hello world"), content="Hello World")
inspect(title("the quick brown fox"), content="The Quick Brown Fox")
inspect(title("a b c"), content="A B C")
}
///|
test "title/edge_cases" {
inspect(title(""), content="")
inspect(title(" "), content=" ")
inspect(title(" "), content=" ")
inspect(title("hello"), content="Hello")
}
///|
test "title/special_characters" {
inspect(title("hello world UK"), content="Hello World UK")
inspect(title(" hello world"), content=" Hello World")
inspect(title("hello world "), content="Hello World ")
inspect(title("123 abc"), content="123 Abc")
}
///|
fn to_camel_case(s : String) -> String {
let b = StringBuilder()
let chars = s.to_array()
let len = chars.length()
let mut i = 0
while i < len {
let c = chars[i]
if (c == '.' || c == '_') &&
i + 1 < len &&
chars[i + 1].is_ascii_lowercase() {
i += 1
continue
} else if c == '.' {
b.write_char('_')
} else if c == '_' && (i == 0 || chars[i - 1] == '.') {
b.write_char('X')
} else if c.is_ascii_digit() {
b.write_char(c)
} else {
let upper_c = c.to_ascii_uppercase()
b.write_char(upper_c)
while i + 1 < len && chars[i + 1].is_ascii_lowercase() {
i += 1
b.write_char(chars[i])
}
}
i += 1
}
return b.to_string()
}
///|
test "to_camel_case" {
inspect(to_camel_case("hello_world"), content="HelloWorld")
inspect(to_camel_case("test.proto"), content="TestProto")
inspect(to_camel_case("_start"), content="Start")
inspect(to_camel_case("simple"), content="Simple")
inspect(to_camel_case("test123"), content="Test123")
inspect(to_camel_case("xml_http_request"), content="XmlHttpRequest")
}
///|
fn pascal_to_snake(name : String) -> String {
let keywords = [
"as", "else", "extern", "fn", "fnalias", "if", "let", "const", "match", "using",
"mut", "type", "typealias", "struct", "enum", "trait", "traitalias", "derive",
"while", "break", "continue", "import", "return", "throw", "raise", "try", "catch",
"pub", "priv", "readonly", "true", "false", "_", "test", "loop", "for", "in",
"impl", "with", "guard", "async", "is", "suberror", "and", "letrec", "enumview",
"noraise", "defer", "module", "move", "ref", "static", "super", "unsafe", "use",
"where", "await", "dyn", "abstract", "do", "final", "macro", "override", "typeof",
"virtual", "yield", "local", "method", "alias", "assert", "package", "recur",
"using", "enumview", "isnot", "define", "downcast", "inherit", "member", "namespace",
"static", "upcast", "use", "void", "lazy", "include", "mixin", "protected", "sealed",
"constructor", "atomic", "volatile", "anyframe", "anytype", "asm", "await", "comptime",
"errdefer", "export", "opaque", "orelse", "resume", "threadlocal", "unreachable",
"dynclass", "dynobj", "dynrec", "var", "finally", "noasync", "init", "main",
]
let new_name = StringBuilder()
let upper = StringBuilder()
let prev = '_'
for rest = name[:], prev = prev {
match (rest, prev) {
(['A'..='Z' as c, .. rest], prev) => {
if upper.is_empty() && prev != '_' {
upper.write_char('_')
}
upper.write_char(c.to_ascii_lowercase())
continue rest, c
}
([c, .. rest], _) => {
if !upper.is_empty() {
new_name.write_string(upper.to_string())
upper.reset()
}
new_name.write_char(c)
continue rest, c
}
([], _) => {
if !upper.is_empty() {
new_name.write_string(upper.to_string())
}
break
}
}
}
if keywords.contains(new_name.to_string()) {
new_name.write_char('_')
}
return new_name.to_string()
}
///|
fn sizeFixed32() -> UInt {
return 4U
}
///|
fn sizeFixed64() -> UInt {
return 8U
}
///|
fn encode_tag(num : Int, typ : Int) -> UInt64 {
(num.to_uint64() << 3) | (typ & 7).to_uint64()
}
///|
test "pascal_to_snake" {
inspect(pascal_to_snake("PascalCase"), content="pascal_case")
inspect(pascal_to_snake("SimpleWord"), content="simple_word")
inspect(pascal_to_snake("XMLHttpRequest"), content="xmlhttp_request")
inspect(pascal_to_snake("HTTPSConnection"), content="httpsconnection")
}
///|
test "pascal_to_snake/edge_cases" {
inspect(pascal_to_snake(""), content="")
inspect(pascal_to_snake("A"), content="a")
inspect(pascal_to_snake("ABC"), content="abc")
inspect(pascal_to_snake("lowercase"), content="lowercase")
}
///|
test "pascal_to_snake/keywords" {
inspect(pascal_to_snake("Type"), content="type_")
inspect(pascal_to_snake("Match"), content="match_")
inspect(pascal_to_snake("New"), content="new")
}