cxx_qt_gen/generator/cpp/
mod.rs

1// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
3//
4// SPDX-License-Identifier: MIT OR Apache-2.0
5
6mod constructor;
7pub mod cxxqttype;
8pub mod externcxxqt;
9pub mod fragment;
10pub mod inherit;
11pub mod method;
12pub mod property;
13pub mod qenum;
14pub mod qnamespace;
15pub mod qobject;
16pub mod signal;
17pub mod threading;
18
19mod utils;
20
21use std::collections::BTreeSet;
22
23use crate::generator::cpp::fragment::CppNamedType;
24use crate::naming::cpp::syn_type_to_cpp_type;
25use crate::naming::TypeNames;
26use crate::{generator::structuring, parser::Parser};
27use externcxxqt::GeneratedCppExternCxxQtBlocks;
28use qobject::GeneratedCppQObject;
29use syn::{FnArg, ForeignItemFn, Pat, PatIdent, PatType, Result};
30
31/// Representation of the generated C++ code for a group of QObjects
32pub struct GeneratedCppBlocks {
33    /// Forward declarations that aren't associated with any QObjects (e.g. "free" qenums).
34    pub forward_declares: Vec<String>,
35    /// Additional includes for the CXX bridge
36    pub includes: BTreeSet<String>,
37    /// Generated QObjects
38    pub qobjects: Vec<GeneratedCppQObject>,
39    /// Generated extern C++Qt blocks
40    pub extern_cxx_qt: Vec<GeneratedCppExternCxxQtBlocks>,
41}
42
43impl GeneratedCppBlocks {
44    /// Create a [GeneratedCppBlocks] from the given [Parser] object
45    pub fn from(parser: &Parser) -> Result<GeneratedCppBlocks> {
46        let structures = structuring::Structures::new(&parser.cxx_qt_data)?;
47
48        let mut includes = BTreeSet::new();
49
50        let mut forward_declares: Vec<_> = parser
51            .cxx_qt_data
52            .qnamespaces
53            .iter()
54            .map(|parsed_qnamespace| qnamespace::generate(parsed_qnamespace, &mut includes))
55            .collect();
56        forward_declares.extend(
57            parser
58                .cxx_qt_data
59                .qenums
60                .iter()
61                .map(|parsed_qenum| qenum::generate_declaration(parsed_qenum, &mut includes)),
62        );
63        Ok(GeneratedCppBlocks {
64            forward_declares,
65            includes,
66            qobjects: structures
67                .qobjects
68                .iter()
69                .map(|qobject| GeneratedCppQObject::from(qobject, &parser.type_names))
70                .collect::<Result<Vec<GeneratedCppQObject>>>()?,
71            extern_cxx_qt: externcxxqt::generate(
72                &parser.cxx_qt_data.extern_cxxqt_blocks,
73                &parser.type_names,
74            )?,
75        })
76    }
77}
78
79/// Returns a vector of the names and types ([CppNamedType] of the parameters of this method, used in cpp generation step
80pub fn get_cpp_params(method: &ForeignItemFn, type_names: &TypeNames) -> Result<Vec<CppNamedType>> {
81    method
82        .sig
83        .inputs
84        .iter()
85        .map(|input| {
86            // Match parameters to extract their idents
87            if let FnArg::Typed(PatType { pat, ty, .. }) = input {
88                let ident = if let Pat::Ident(PatIdent { ident, .. }) = &**pat {
89                    ident
90                } else {
91                    // CODECOV_EXCLUDE_START
92                    unreachable!("Unknown pattern for type, FnArg can only have Pat::Ident")
93                    // CODECOV_EXCLUDE_STOP
94                };
95
96                Ok(Some(CppNamedType {
97                    ident: ident.to_string(),
98                    ty: syn_type_to_cpp_type(ty, type_names)?,
99                }))
100            } else {
101                Ok(None)
102            }
103        })
104        .filter_map(|result| result.map_or_else(|e| Some(Err(e)), |v| v.map(Ok)))
105        .collect()
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    use crate::parser::Parser;
113    use syn::{parse_quote, ItemMod};
114
115    #[test]
116    fn test_generated_cpp_blocks() {
117        let module: ItemMod = parse_quote! {
118            #[cxx_qt::bridge]
119            mod ffi {
120                extern "RustQt" {
121                    #[qobject]
122                    type MyObject = super::MyObjectRust;
123                }
124            }
125        };
126        let parser = Parser::from(module).unwrap();
127
128        let cpp = GeneratedCppBlocks::from(&parser).unwrap();
129        assert_eq!(cpp.qobjects.len(), 1);
130        assert_eq!(cpp.qobjects[0].name.namespace(), None);
131    }
132
133    #[test]
134    fn test_generated_cpp_blocks_namespace() {
135        let module: ItemMod = parse_quote! {
136            #[cxx_qt::bridge(namespace = "cxx_qt")]
137            mod ffi {
138                extern "RustQt" {
139                    #[qobject]
140                    type MyObject = super::MyObjectRust;
141                }
142            }
143        };
144        let parser = Parser::from(module).unwrap();
145
146        let cpp = GeneratedCppBlocks::from(&parser).unwrap();
147        assert_eq!(cpp.qobjects[0].name.namespace(), Some("cxx_qt"));
148    }
149}