nimbus_fml/backends/swift/gen_structs/
enum_.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/. */
4
5use std::fmt::Display;
6
7use askama::Template;
8
9use super::common;
10use super::common::code_type;
11use super::filters;
12use crate::backends::{CodeDeclaration, CodeOracle, CodeType, LiteralRenderer, VariablesType};
13use crate::intermediate_representation::{EnumDef, FeatureManifest, Literal};
14
15pub(crate) struct EnumCodeType {
16    id: String,
17}
18
19impl EnumCodeType {
20    pub(crate) fn new(id: String) -> Self {
21        Self { id }
22    }
23}
24
25impl CodeType for EnumCodeType {
26    /// The language specific label used to reference this type. This will be used in
27    /// method signatures and property declarations.
28    fn type_label(&self, _oracle: &dyn CodeOracle) -> String {
29        common::class_name(&self.id)
30    }
31
32    fn property_getter(
33        &self,
34        oracle: &dyn CodeOracle,
35        vars: &dyn Display,
36        prop: &dyn Display,
37        default: &dyn Display,
38    ) -> String {
39        code_type::property_getter(self, oracle, vars, prop, default)
40    }
41
42    fn value_getter(
43        &self,
44        oracle: &dyn CodeOracle,
45        vars: &dyn Display,
46        prop: &dyn Display,
47    ) -> String {
48        code_type::value_getter(self, oracle, vars, prop)
49    }
50
51    fn value_mapper(&self, oracle: &dyn CodeOracle) -> Option<String> {
52        code_type::value_mapper(self, oracle)
53    }
54
55    /// The name of the type as it's represented in the `Variables` object.
56    /// The string return may be used to combine with an identifier, e.g. a `Variables` method name.
57    fn variables_type(&self, _oracle: &dyn CodeOracle) -> VariablesType {
58        VariablesType::String
59    }
60
61    /// A function handle that is capable of turning the variables type to the TypeRef type.
62    fn create_transform(&self, oracle: &dyn CodeOracle) -> Option<String> {
63        Some(format!(
64            "{enum_type}.enumValue",
65            enum_type = self.type_label(oracle)
66        ))
67    }
68
69    fn as_json_transform(&self, _oracle: &dyn CodeOracle, prop: &dyn Display) -> Option<String> {
70        Some(format!("{prop}.rawValue"))
71    }
72
73    /// A representation of the given literal for this type.
74    /// N.B. `Literal` is aliased from `serde_json::Value`.
75    fn literal(
76        &self,
77        _oracle: &dyn CodeOracle,
78        _ctx: &dyn Display,
79        _renderer: &dyn LiteralRenderer,
80        literal: &Literal,
81    ) -> String {
82        let variant = match literal {
83            serde_json::Value::String(v) => v,
84            _ => unreachable!(),
85        };
86
87        format!(".{}", common::enum_variant_name(variant))
88    }
89}
90#[derive(Template)]
91#[template(syntax = "swift", escape = "none", path = "EnumTemplate.swift")]
92pub(crate) struct EnumCodeDeclaration {
93    inner: EnumDef,
94}
95
96impl EnumCodeDeclaration {
97    pub fn new(_fm: &FeatureManifest, inner: &EnumDef) -> Self {
98        Self {
99            inner: inner.clone(),
100        }
101    }
102    fn inner(&self) -> EnumDef {
103        self.inner.clone()
104    }
105}
106
107impl CodeDeclaration for EnumCodeDeclaration {
108    fn definition_code(&self, _oracle: &dyn CodeOracle) -> Option<String> {
109        Some(self.render().unwrap())
110    }
111}
112
113#[cfg(test)]
114mod unit_tests {
115
116    use serde_json::json;
117
118    use super::*;
119    use crate::backends::TypeIdentifier;
120    struct TestCodeOracle;
121    impl CodeOracle for TestCodeOracle {
122        fn find(&self, _type_: &TypeIdentifier) -> Box<dyn CodeType> {
123            unreachable!()
124        }
125    }
126
127    struct TestRenderer;
128    impl LiteralRenderer for TestRenderer {
129        fn literal(
130            &self,
131            _oracle: &dyn CodeOracle,
132            _typ: &TypeIdentifier,
133            _value: &Literal,
134            _ctx: &dyn Display,
135        ) -> String {
136            unreachable!()
137        }
138    }
139
140    fn oracle() -> Box<dyn CodeOracle> {
141        Box::new(TestCodeOracle) as Box<dyn CodeOracle>
142    }
143
144    fn code_type(name: &str) -> Box<dyn CodeType> {
145        Box::new(EnumCodeType::new(name.to_string())) as Box<dyn CodeType>
146    }
147
148    #[test]
149    fn test_type_label() {
150        let ct = code_type("AEnum");
151        let oracle = &*oracle();
152        assert_eq!("AEnum".to_string(), ct.type_label(oracle))
153    }
154
155    #[test]
156    fn test_literal() {
157        let ct = code_type("AEnum");
158        let oracle = &*oracle();
159        let finder = &TestRenderer;
160        let ctx = String::from("ctx");
161        assert_eq!(
162            ".foo".to_string(),
163            ct.literal(oracle, &ctx, finder, &json!("foo"))
164        );
165        assert_eq!(
166            ".barBaz".to_string(),
167            ct.literal(oracle, &ctx, finder, &json!("barBaz"))
168        );
169        assert_eq!(
170            ".aBC".to_string(),
171            ct.literal(oracle, &ctx, finder, &json!("a-b-c"))
172        );
173    }
174
175    #[test]
176    fn test_get_value() {
177        let ct = code_type("AEnum");
178        let oracle = &*oracle();
179
180        assert_eq!(
181            r#"v.getString("the-property")"#.to_string(),
182            ct.value_getter(oracle, &"v", &"the-property")
183        );
184    }
185
186    #[test]
187    fn test_getter_with_fallback() {
188        let ct = code_type("AEnum");
189        let oracle = &*oracle();
190
191        assert_eq!(
192            r#"v.getString("the-property")?.map(AEnum.enumValue) ?? def"#.to_string(),
193            ct.property_getter(oracle, &"v", &"the-property", &"def")
194        );
195    }
196}