Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bindings for QtMsgType, QMessageLogContext and qt_message_output #814

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add cxx-qt-lib-extras crate which contains: `QCommandLineOption`, `QCommandLineParser`, `QElapsedTimer`, `QApplication`
- Serde support for `QString` (requires "serde" feature on cxx-qt-lib)
- A new QuickControls module, which exposes `QQuickStyle`. This module is enabled by default and is behind the `qt_quickcontrols` feature.
- Support for `QMessageLogContext` and sending log messages to the Qt message handler.

### Changed

Expand Down
2 changes: 2 additions & 0 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ fn main() {
"core/qstringlist",
"core/qt",
"core/qtime",
"core/qtlogging",
"core/qurl",
"core/qvariant/mod",
"core/qvariant/qvariant_bool",
Expand Down Expand Up @@ -254,6 +255,7 @@ fn main() {
"core/qstring",
"core/qstringlist",
"core/qtime",
"core/qtlogging",
"core/qurl",
"core/qvariant/qvariant",
"core/qvector/qvector",
Expand Down
48 changes: 48 additions & 0 deletions crates/cxx-qt-lib/include/core/qtlogging.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// clang-format off
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Joshua Goins <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include "rust/cxx.h"
#include <QDebug>
#include <QtCore/qlogging.h>

int
qmessagelogcontext_line(const QMessageLogContext& context);

void
qmessagelogcontext_set_line(QMessageLogContext& context, const int line);

const char*
qmessagelogcontext_file(const QMessageLogContext& context);

void
qmessagelogcontext_set_file(QMessageLogContext& context, const char* file);

const char*
qmessagelogcontext_function(const QMessageLogContext& context);

void
qmessagelogcontext_set_function(QMessageLogContext& context,
const char* function);

const char*
qmessagelogcontext_category(const QMessageLogContext& context);

void
qmessagelogcontext_set_category(QMessageLogContext& context,
const char* category);

// Define namespace otherwise we hit a GCC bug
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480
namespace rust {

template<>
struct IsRelocatable<QMessageLogContext> : ::std::true_type
{
};

} // namespace rust
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ pub use qvariant::{QVariant, QVariantValue};
mod qvector;
pub use qvector::{QVector, QVectorElement};

mod qtlogging;
pub use qtlogging::{qt_message_output, QMessageLogContext, QtMsgType};

#[cxx::bridge]
mod ffi {
#[namespace = "rust::cxxqtlib1"]
Expand Down
72 changes: 72 additions & 0 deletions crates/cxx-qt-lib/src/core/qtlogging.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// clang-format off
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Joshua Goins <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#include "cxx-qt-lib/qtlogging.h"
redstrate marked this conversation as resolved.
Show resolved Hide resolved

#include "../assertion_utils.h"

// QMessageLogContext has three "const char*" members for line, category, etc
// https://codebrowser.dev/qt5/qtbase/src/corelib/global/qlogging.h.html#QMessageLogContext
assert_alignment_and_size(QMessageLogContext,
alignof(intptr_t),
sizeof(intptr_t) * 4);

static_assert(!::std::is_trivially_copy_assignable<QMessageLogContext>::value);
static_assert(
!::std::is_trivially_copy_constructible<QMessageLogContext>::value);
static_assert(::std::is_trivially_destructible<QMessageLogContext>::value);

static_assert(QTypeInfo<QMessageLogContext>::isRelocatable);

int
qmessagelogcontext_line(const QMessageLogContext& context)
{
return context.line;
}

void
qmessagelogcontext_set_line(QMessageLogContext& context, const int line)
{
context.line = line;
}

const char*
qmessagelogcontext_file(const QMessageLogContext& context)
{
return context.file;
}

void
qmessagelogcontext_set_file(QMessageLogContext& context, const char* file)
{
context.file = file;
}

const char*
qmessagelogcontext_function(const QMessageLogContext& context)
{
return context.function;
}

void
qmessagelogcontext_set_function(QMessageLogContext& context,
const char* function)
{
context.function = function;
}

const char*
qmessagelogcontext_category(const QMessageLogContext& context)
{
return context.category;
}

void
qmessagelogcontext_set_category(QMessageLogContext& context,
const char* category)
{
context.category = category;
}
145 changes: 145 additions & 0 deletions crates/cxx-qt-lib/src/core/qtlogging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Joshua Goins <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use cxx::{type_id, ExternType};
use std::ffi::c_char;
use std::ffi::CStr;
use std::marker::PhantomData;

#[cxx::bridge]
mod ffi {
/// The level the message is sent to the message handler at.
#[repr(i32)]
enum QtMsgType {
redstrate marked this conversation as resolved.
Show resolved Hide resolved
/// A debug message.
QtDebugMsg = 0,
/// An info message.
QtInfoMsg = 4,
/// A warning message.
QtWarningMsg = 1,
/// A fatal message.
QtFatalMsg = 3,
/// A critical message.
QtCriticalMsg = 2,
}

unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = crate::QString;

include!("cxx-qt-lib/qtlogging.h");
type QMessageLogContext<'a> = crate::QMessageLogContext<'a>;
type QtMsgType;

/// Outputs a message in the Qt message handler.
fn qt_message_output(msgType: QtMsgType, context: &QMessageLogContext, string: &QString);
redstrate marked this conversation as resolved.
Show resolved Hide resolved

#[cxx_name = "qmessagelogcontext_line"]
redstrate marked this conversation as resolved.
Show resolved Hide resolved
#[doc(hidden)]
fn line(context: &QMessageLogContext) -> i32;
redstrate marked this conversation as resolved.
Show resolved Hide resolved

#[cxx_name = "qmessagelogcontext_set_line"]
#[doc(hidden)]
fn set_line(context: &mut QMessageLogContext, line: i32);
redstrate marked this conversation as resolved.
Show resolved Hide resolved

#[cxx_name = "qmessagelogcontext_file"]
#[doc(hidden)]
unsafe fn file(context: &QMessageLogContext) -> *const c_char;

#[cxx_name = "qmessagelogcontext_set_file"]
#[doc(hidden)]
unsafe fn set_file(context: &mut QMessageLogContext, file: *const c_char);
redstrate marked this conversation as resolved.
Show resolved Hide resolved

#[cxx_name = "qmessagelogcontext_function"]
#[doc(hidden)]
unsafe fn function(context: &QMessageLogContext) -> *const c_char;

#[cxx_name = "qmessagelogcontext_set_function"]
#[doc(hidden)]
unsafe fn set_function(context: &mut QMessageLogContext, function: *const c_char);

#[cxx_name = "qmessagelogcontext_category"]
#[doc(hidden)]
unsafe fn category(context: &QMessageLogContext) -> *const c_char;

#[cxx_name = "qmessagelogcontext_set_category"]
#[doc(hidden)]
unsafe fn set_category(context: &mut QMessageLogContext, category: *const c_char);
}

#[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
include!("cxx-qt-lib/common.h");

#[doc(hidden)]
#[rust_name = "qmessagelogcontext_default"]
fn construct() -> QMessageLogContext<'static>;
}
}

/// The QMessageLogContext struct defines the context passed to the Qt message handler.
#[repr(C)]
pub struct QMessageLogContext<'a> {
redstrate marked this conversation as resolved.
Show resolved Hide resolved
version: i32,
line: i32,
file: *const c_char,
function: *const c_char,
category: *const c_char,
_phantom: PhantomData<&'a c_char>,
}

impl Default for QMessageLogContext<'_> {
fn default() -> Self {
ffi::qmessagelogcontext_default()
}
}

impl<'a> QMessageLogContext<'a> {
pub fn new(
line: i32,
file: &'a *const c_char,
function: &'a *const c_char,
category: &'a *const c_char,
) -> QMessageLogContext<'a> {
let mut context = QMessageLogContext::default();
unsafe {
ffi::set_line(&mut context, line);
ffi::set_file(&mut context, *file);
ffi::set_function(&mut context, *function);
ffi::set_category(&mut context, *category);
}

context
}

/// The line number given to the message handler.
pub fn line(&self) -> i32 {
ffi::line(self)
}

/// The file path given to the message handler.
pub fn file(&self) -> &CStr {
unsafe { CStr::from_ptr(ffi::file(self)) }
}

/// The name of the function given to the message handler.
pub fn function(&self) -> &CStr {
unsafe { CStr::from_ptr(ffi::function(self)) }
}

/// The category given to the message handler.
pub fn category(&self) -> &CStr {
unsafe { CStr::from_ptr(ffi::category(self)) }
}
}

// Safety:
//
// Static checks on the C++ side ensure that QMessageLogContext is trivial.
unsafe impl ExternType for QMessageLogContext<'_> {
type Id = type_id!("QMessageLogContext");
type Kind = cxx::kind::Trivial;
}

pub use ffi::{qt_message_output, QtMsgType};
Loading