1use std::{
2 ffi::{CStr, CString, NulError},
3 fmt::{Display, Formatter},
4};
5
6use crate::{
7 ffi::{
8 CLAP_LOG_DEBUG, CLAP_LOG_ERROR, CLAP_LOG_FATAL, CLAP_LOG_HOST_MISBEHAVING, CLAP_LOG_INFO,
9 CLAP_LOG_PLUGIN_MISBEHAVING, CLAP_LOG_WARNING, clap_host_log, clap_log_severity,
10 },
11 host::Host,
12};
13
14#[derive(Debug)]
15pub struct HostLog<'a> {
16 host: &'a Host,
17 clap_host_log: &'a clap_host_log,
18}
19
20impl<'a> HostLog<'a> {
21 pub(crate) const unsafe fn new_unchecked(
26 host: &'a Host,
27 clap_host_log: &'a clap_host_log,
28 ) -> Self {
29 Self {
30 host,
31 clap_host_log,
32 }
33 }
34
35 pub fn log_cstr(&self, severity: Severity, msg: &CStr) {
40 let callback = self.clap_host_log.log.unwrap();
43 unsafe { callback(self.host.clap_host(), severity.into(), msg.as_ptr()) }
44 }
45
46 pub fn log(&self, severity: Severity, msg: &str) -> Result<(), Error> {
47 self.log_cstr(severity, &CString::new(msg)?);
48 Ok(())
49 }
50}
51
52macro_rules! impl_log_severity {
53 ($(($method:tt, $severity:ident)),*) => {
54 impl<'a> HostLog<'a> {
55 $(
56 pub fn $method(&self, msg: &str) -> Result<(), Error> {
57 self.log(Severity::$severity, msg)
58 }
59 )*
60 }
61 };
62}
63
64impl_log_severity!(
65 (debug, Debug),
66 (info, Info),
67 (warning, Warning),
68 (error, Error),
69 (fatal, Fatal)
70);
71
72#[derive(Debug, Copy, Clone, PartialEq)]
73pub enum Severity {
74 Debug,
75 Info,
76 Warning,
77 Error,
78 Fatal,
79 HostMisbehaving,
80 PluginMisbehaving,
81}
82
83impl From<Severity> for clap_log_severity {
84 fn from(value: Severity) -> Self {
85 use Severity::*;
86
87 match value {
88 Debug => CLAP_LOG_DEBUG,
89 Info => CLAP_LOG_INFO,
90 Warning => CLAP_LOG_WARNING,
91 Error => CLAP_LOG_ERROR,
92 Fatal => CLAP_LOG_FATAL,
93 HostMisbehaving => CLAP_LOG_HOST_MISBEHAVING,
94 PluginMisbehaving => CLAP_LOG_PLUGIN_MISBEHAVING,
95 }
96 }
97}
98
99#[derive(Debug, Clone, PartialEq)]
100pub enum Error {
101 NulError(NulError),
102}
103
104impl Display for Error {
105 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106 match self {
107 Error::NulError(e) => write!(f, "error converting to C string: {e}"),
108 }
109 }
110}
111
112impl std::error::Error for Error {}
113
114impl From<NulError> for Error {
115 fn from(value: NulError) -> Self {
116 Self::NulError(value)
117 }
118}
119
120impl From<Error> for crate::Error {
121 fn from(value: Error) -> Self {
122 crate::ext::Error::Log(value).into()
123 }
124}