nimbus_fml/backends/swift/gen_structs/
mod.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 askama::Template;
5use std::collections::HashSet;
6
7use crate::{
8    backends::{CodeDeclaration, CodeOracle, CodeType, TypeIdentifier},
9    intermediate_representation::{FeatureDef, FeatureManifest, TypeFinder},
10};
11mod bundled;
12mod common;
13mod enum_;
14mod feature;
15mod filters;
16mod imports;
17mod object;
18mod primitives;
19mod structural;
20
21#[derive(Template)]
22#[template(
23    syntax = "swift",
24    escape = "none",
25    path = "FeatureManifestTemplate.swift"
26)]
27pub struct FeatureManifestDeclaration<'a> {
28    fm: &'a FeatureManifest,
29    oracle: ConcreteCodeOracle,
30}
31
32impl<'a> FeatureManifestDeclaration<'a> {
33    pub fn new(fm: &'a FeatureManifest) -> Self {
34        Self {
35            fm,
36            oracle: Default::default(),
37        }
38    }
39
40    pub fn members(&self) -> Vec<Box<dyn CodeDeclaration + 'a>> {
41        let fm = self.fm;
42
43        fm.iter_feature_defs()
44            .map(|inner| {
45                Box::new(feature::FeatureCodeDeclaration::new(fm, inner))
46                    as Box<dyn CodeDeclaration>
47            })
48            .chain(fm.iter_enum_defs().map(|inner| {
49                Box::new(enum_::EnumCodeDeclaration::new(fm, inner)) as Box<dyn CodeDeclaration>
50            }))
51            .chain(fm.iter_object_defs().map(|inner| {
52                Box::new(object::ObjectCodeDeclaration::new(fm, inner)) as Box<dyn CodeDeclaration>
53            }))
54            .chain(fm.iter_imported_files().iter().map(|inner| {
55                Box::new(imports::ImportedModuleInitialization::new(inner))
56                    as Box<dyn CodeDeclaration>
57            }))
58            .collect()
59    }
60
61    pub fn iter_feature_defs(&self) -> Vec<&FeatureDef> {
62        self.fm.iter_feature_defs().collect::<_>()
63    }
64
65    pub fn initialization_code(&self) -> Vec<String> {
66        let oracle = &self.oracle;
67        self.members()
68            .into_iter()
69            .filter_map(|member| member.initialization_code(oracle))
70            .collect()
71    }
72
73    pub fn declaration_code(&self) -> Vec<String> {
74        let oracle = &self.oracle;
75        self.members()
76            .into_iter()
77            .filter_map(|member| member.definition_code(oracle))
78            .collect()
79    }
80
81    pub fn imports(&self) -> Vec<String> {
82        let oracle = &self.oracle;
83        // Filter out our own module.
84        let my_module = &self.fm.about.nimbus_module_name();
85        // Get the app-services module from an environment variable.
86        // If it doesn't exist, then we don't add it.
87        let as_module = std::env::var("MOZ_APPSERVICES_MODULE")
88            .map(|s| vec![s])
89            .unwrap_or_else(|_| vec![]);
90        let mut imports: Vec<String> = self
91            .members()
92            .into_iter()
93            .filter_map(|member| member.imports(oracle))
94            .flatten()
95            .chain(
96                self.fm
97                    .all_types()
98                    .into_iter()
99                    .filter_map(|type_| self.oracle.find(&type_).imports(oracle))
100                    .flatten(),
101            )
102            .chain(as_module)
103            .chain(vec!["Foundation".to_string()])
104            .filter(|i| i != my_module)
105            .collect::<HashSet<String>>()
106            .into_iter()
107            .collect();
108
109        imports.sort();
110        imports
111    }
112}
113
114#[derive(Default, Clone)]
115pub struct ConcreteCodeOracle;
116
117impl ConcreteCodeOracle {
118    fn create_code_type(&self, type_: TypeIdentifier) -> Box<dyn CodeType> {
119        match type_ {
120            TypeIdentifier::Boolean => Box::new(primitives::BooleanCodeType),
121            TypeIdentifier::String | TypeIdentifier::StringAlias(_) => {
122                Box::new(primitives::StringCodeType)
123            }
124            TypeIdentifier::Int => Box::new(primitives::IntCodeType),
125
126            TypeIdentifier::BundleText => Box::new(bundled::TextCodeType),
127            TypeIdentifier::BundleImage => Box::new(bundled::ImageCodeType),
128
129            TypeIdentifier::Enum(id) => Box::new(enum_::EnumCodeType::new(id)),
130            TypeIdentifier::Object(id) => Box::new(object::ObjectCodeType::new(id)),
131
132            TypeIdentifier::Option(ref inner) => Box::new(structural::OptionalCodeType::new(inner)),
133            TypeIdentifier::List(ref inner) => Box::new(structural::ListCodeType::new(inner)),
134            TypeIdentifier::StringMap(ref v_type) => {
135                let k_type = &TypeIdentifier::String;
136                Box::new(structural::MapCodeType::new(k_type, v_type))
137            }
138            TypeIdentifier::EnumMap(ref k_type, ref v_type) => {
139                Box::new(structural::MapCodeType::new(k_type, v_type))
140            }
141        }
142    }
143}
144
145impl CodeOracle for ConcreteCodeOracle {
146    fn find(&self, type_: &TypeIdentifier) -> Box<dyn CodeType> {
147        self.create_code_type(type_.clone())
148    }
149}