nimbus_fml/backends/kotlin/gen_structs/
common.rs

1// /* This Source Code Form is subject to the terms of the Mozilla Public
2//  * License, v. 2.0. If a copy of the MPL was not distributed with this
3//  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4use heck::{CamelCase, MixedCase, ShoutySnakeCase};
5use std::fmt::Display;
6
7/// Get the idiomatic Kotlin rendering of a class name (for enums, records, errors, etc).
8pub fn class_name(nm: &dyn Display) -> String {
9    nm.to_string().to_camel_case()
10}
11
12/// Get the idiomatic Kotlin rendering of a variable name.
13pub fn var_name(nm: &dyn Display) -> String {
14    nm.to_string().to_mixed_case()
15}
16
17/// Get the idiomatic Kotlin rendering of an individual enum variant.
18pub fn enum_variant_name(nm: &dyn Display) -> String {
19    nm.to_string().to_shouty_snake_case()
20}
21
22/// Surrounds a string with quotes.
23/// In Kotlin, you can """triple quote""" multi-line strings
24/// so you don't have to escape " and \n characters.
25pub fn quoted(string: &dyn Display) -> String {
26    let string = string.to_string();
27    if string.contains('"') || string.contains('\n') {
28        format!(r#""""{}""""#, string)
29    } else {
30        format!(r#""{}""#, string)
31    }
32}
33
34pub(crate) mod code_type {
35    use std::fmt::Display;
36
37    use crate::backends::{CodeOracle, CodeType};
38
39    /// The language specific expression that gets a value of the `prop` from the `vars` object.
40    pub(crate) fn property_getter(
41        ct: &dyn CodeType,
42        oracle: &dyn CodeOracle,
43        vars: &dyn Display,
44        prop: &dyn Display,
45        default: &dyn Display,
46    ) -> String {
47        let getter = ct.value_getter(oracle, vars, prop);
48        let mapper = ct.value_mapper(oracle);
49        let default = ct
50            .defaults_mapper(oracle, &default, vars)
51            .unwrap_or_else(|| default.to_string());
52        let merger = ct.value_merger(oracle, &default);
53
54        // We need to be quite careful about option chaining.
55        // Kotlin takes the `?` as an indicator to that the preceeding expression
56        // is optional to continue processing, but be aware that the
57        // expression returns an optional.
58        // Only the value_getter returns an optional, yet the optionality propagates.
59        // https://kotlinlang.org/docs/null-safety.html#safe-calls
60        let getter = match (mapper, merger) {
61            (Some(mapper), Some(merger)) => format!("{}?.{}?.{}", getter, mapper, merger),
62            (Some(mapper), None) => format!("{}?.{}", getter, mapper),
63            (None, Some(merger)) => format!("{}?.{}", getter, merger),
64            (None, None) => getter,
65        };
66
67        format!(
68            "{getter} ?: {fallback}",
69            getter = getter,
70            fallback = default
71        )
72    }
73
74    pub(crate) fn value_getter(
75        ct: &dyn CodeType,
76        oracle: &dyn CodeOracle,
77        vars: &dyn Display,
78        prop: &dyn Display,
79    ) -> String {
80        let vt = ct.variables_type(oracle);
81        format!(
82            "{vars}.get{vt}(\"{prop}\")",
83            vars = vars,
84            vt = vt,
85            prop = prop
86        )
87    }
88
89    pub(crate) fn value_mapper(ct: &dyn CodeType, oracle: &dyn CodeOracle) -> Option<String> {
90        let transform = ct.create_transform(oracle)?;
91        Some(format!("let({})", transform))
92    }
93}
94
95#[cfg(test)]
96mod unit_tests {
97    use super::*;
98
99    #[test]
100    fn test_quoted() {
101        assert_eq!(
102            quoted(&"no-quotes".to_string()),
103            "\"no-quotes\"".to_string()
104        );
105        assert_eq!(
106            quoted(&"a \"quoted\" string".to_string()),
107            "\"\"\"a \"quoted\" string\"\"\"".to_string()
108        );
109    }
110}