Skip to main content

cxx_qt_lib/core/
qtlogging.rs

1// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Joshua Goins <joshua.goins@kdab.com>
3//
4// SPDX-License-Identifier: MIT OR Apache-2.0
5use cxx::{type_id, ExternType};
6use std::ffi::c_char;
7use std::ffi::CStr;
8use std::marker::PhantomData;
9use std::mem::size_of;
10
11#[cxx::bridge]
12mod ffi {
13    /// The level the message is sent to the message handler at.
14    #[repr(i32)]
15    enum QtMsgType {
16        /// A debug message.
17        QtDebugMsg = 0,
18        /// An info message.
19        QtInfoMsg = 4,
20        /// A warning message.
21        QtWarningMsg = 1,
22        /// A fatal message.
23        QtFatalMsg = 3,
24        /// A critical message.
25        QtCriticalMsg = 2,
26    }
27
28    unsafe extern "C++" {
29        include!("cxx-qt-lib/qstring.h");
30        type QString = crate::QString;
31
32        include!("cxx-qt-lib/qtlogging.h");
33        type QMessageLogContext<'a> = crate::QMessageLogContext<'a>;
34        type QtMsgType;
35
36        /// Outputs a message in the Qt message handler.
37        ///
38        /// **Warning:** This function is an undocumented internal utility in the Qt library.
39        fn qt_message_output(msg_type: QtMsgType, context: &QMessageLogContext, string: &QString);
40
41        /// Generates a formatted string out of the `msg_type`, `context`, `str` arguments.
42        ///
43        /// This function returns a `QString` that is formatted according to the current message pattern. It can be used by custom message handlers to format output similar to Qt's default message handler.
44        ///
45        /// The function is thread-safe.
46        #[cxx_name = "qFormatLogMessage"]
47        fn q_format_log_message(
48            msg_type: QtMsgType,
49            context: &QMessageLogContext,
50            str: &QString,
51        ) -> QString;
52
53        /// Changes the output of the default message handler.
54        /// See the [Qt documentation](https://doc.qt.io/qt/qtlogging.html#qSetMessagePattern) for full details.
55        ///
56        /// # Safety
57        /// This function is marked as unsafe because it is not guaranteed to be thread-safe.
58        #[allow(clippy::missing_safety_doc)]
59        #[cxx_name = "qSetMessagePattern"]
60        unsafe fn q_set_message_pattern(pattern: &QString);
61
62        #[cxx_name = "qmessagelogcontext_line"]
63        #[doc(hidden)]
64        fn line(context: &QMessageLogContext) -> i32;
65
66        #[cxx_name = "qmessagelogcontext_file"]
67        #[doc(hidden)]
68        unsafe fn file(context: &QMessageLogContext) -> *const c_char;
69
70        #[cxx_name = "qmessagelogcontext_function"]
71        #[doc(hidden)]
72        unsafe fn function(context: &QMessageLogContext) -> *const c_char;
73
74        #[cxx_name = "qmessagelogcontext_category"]
75        #[doc(hidden)]
76        unsafe fn category(context: &QMessageLogContext) -> *const c_char;
77    }
78
79    #[namespace = "rust::cxxqtlib1"]
80    unsafe extern "C++" {
81        include!("cxx-qt-lib/common.h");
82
83        #[doc(hidden)]
84        #[rust_name = "construct_qmessagelogcontext"]
85        unsafe fn construct<'a>(
86            file_name: *const c_char,
87            line_number: i32,
88            function_name: *const c_char,
89            category_name: *const c_char,
90        ) -> QMessageLogContext<'a>;
91    }
92}
93
94/// The `QMessageLogContext` class defines the context passed to the Qt message handler.
95///
96/// Qt Documentation: [QMessageLogContext](https://doc.qt.io/qt/qmessagelogcontext.html#details)
97#[repr(C)]
98#[derive(Clone, Copy)]
99pub struct QMessageLogContext<'a> {
100    version: i32,
101    line: i32,
102    file: *const c_char,
103    function: *const c_char,
104    category: *const c_char,
105    _phantom: PhantomData<&'a c_char>,
106}
107
108const_assert!(
109    size_of::<QMessageLogContext>() == (size_of::<i32>() * 2) + (size_of::<*const c_char>() * 3)
110);
111
112impl<'a> QMessageLogContext<'a> {
113    pub fn new(
114        file: &'a CStr,
115        line: i32,
116        function: &'a CStr,
117        category: &'a CStr,
118    ) -> QMessageLogContext<'a> {
119        unsafe {
120            ffi::construct_qmessagelogcontext(
121                file.as_ptr(),
122                line,
123                function.as_ptr(),
124                category.as_ptr(),
125            )
126        }
127    }
128
129    /// The line number given to the message handler.
130    pub fn line(&self) -> i32 {
131        ffi::line(self)
132    }
133
134    /// The file path given to the message handler.
135    pub fn file(&self) -> &'a CStr {
136        unsafe { CStr::from_ptr(ffi::file(self)) }
137    }
138
139    /// The name of the function given to the message handler.
140    pub fn function(&self) -> &'a CStr {
141        unsafe { CStr::from_ptr(ffi::function(self)) }
142    }
143
144    /// The category given to the message handler.
145    pub fn category(&self) -> &'a CStr {
146        unsafe { CStr::from_ptr(ffi::category(self)) }
147    }
148}
149
150// Safety:
151//
152// Static checks on the C++ side ensure that QMessageLogContext is trivial.
153unsafe impl ExternType for QMessageLogContext<'_> {
154    type Id = type_id!("QMessageLogContext");
155    type Kind = cxx::kind::Trivial;
156}
157
158use crate::const_assert;
159pub use ffi::{q_format_log_message, q_set_message_pattern, qt_message_output, QtMsgType};