use std::io;
use crate::{Initializer, QmlUri};
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum PluginType {
Static,
Dynamic,
}
pub struct QmlPluginCppBuilder {
plugin_class_name: String,
qml_cache: bool,
uri: QmlUri,
plugin_type: PluginType,
}
impl QmlPluginCppBuilder {
pub fn new(uri: QmlUri, plugin_class_name: impl Into<String>) -> Self {
Self {
plugin_class_name: plugin_class_name.into(),
qml_cache: false,
plugin_type: PluginType::Static,
uri,
}
}
pub fn qml_cache(mut self, enabled: bool) -> Self {
self.qml_cache = enabled;
self
}
pub fn plugin_type(mut self, plugin_type: PluginType) -> Self {
self.plugin_type = plugin_type;
self
}
pub fn write(self, writer: &mut impl io::Write) -> io::Result<Initializer> {
let plugin_class_name = self.plugin_class_name;
let qml_uri_underscores = self.uri.as_underscores();
let mut declarations = Vec::default();
let mut usages = Vec::default();
let mut generate_usage = |return_type: &str, function_name: &str| {
declarations.push(format!("extern {return_type} {function_name}();"));
usages.push(format!("volatile auto {function_name}_usage = &{function_name};\nQ_UNUSED({function_name}_usage);"));
};
generate_usage("void", &format!("qml_register_types_{qml_uri_underscores}"));
generate_usage(
"int",
&format!("qInitResources_qml_module_resources_{qml_uri_underscores}_qrc"),
);
if self.qml_cache {
generate_usage(
"int",
&format!("qInitResources_qmlcache_{qml_uri_underscores}"),
);
}
let declarations = declarations.join("\n");
let usages = usages.join("\n");
let init_fn_name = format!("init_cxx_qt_qml_module_{plugin_class_name}");
write!(
writer,
r#"
#include <QtQml/qqmlextensionplugin.h>
// TODO: Add missing handling for GHS (Green Hills Software compiler) that is in
// https://code.qt.io/cgit/qt/qtbase.git/plain/src/corelib/global/qtsymbolmacros.h
{declarations}
class {plugin_class_name} : public QQmlEngineExtensionPlugin
{{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlEngineExtensionInterface")
public:
{plugin_class_name}(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent)
{{
{usages}
}}
}};
extern "C" {{
// "drive-by initialization" causes the plugin class to be included in static linking scenarios
// Any function that is called from within this file causes the entire object file to be linked in.
// Therefore we provide an empty function that can be called at any point to ensure this file is linked in.
bool {init_fn_name}() {{
return true;
}}
}}
// The moc-generated cpp file doesn't compile on its own; it needs to be #included here.
#include "moc_{plugin_class_name}.cpp.cpp"
"#
)?;
let initializer = match self.plugin_type {
PluginType::Static => Initializer {
file: None,
init_call: None,
init_declaration: Some(format!(
"#include <QtPlugin>\nQ_IMPORT_PLUGIN({plugin_class_name});"
)),
},
PluginType::Dynamic => Initializer::default_signature(&init_fn_name),
};
Ok(initializer)
}
}