cdns_rs/a_sync/
log.rs

1/*-
2 * cdns-rs - a simple sync/async DNS query library
3 * 
4 * Copyright (C) 2020  Aleksandr Morozov
5 * 
6 * Copyright 2025 Aleksandr Morozov
7 * 
8 * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
9 * the European Commission - subsequent versions of the EUPL (the "Licence").
10 * 
11 * You may not use this work except in compliance with the Licence.
12 * 
13 * You may obtain a copy of the Licence at:
14 * 
15 *    https://joinup.ec.europa.eu/software/page/eupl
16 * 
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
19 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
20 * Licence for the specific language governing permissions and limitations
21 * under the Licence.
22 */
23
24pub mod cdns_custom_output
25{
26    use std::{fmt::{self, Write}, str, sync::{LazyLock, OnceLock}};
27
28    use tokio::sync::Mutex;
29
30
31    struct DummyOutputAdapter{}
32
33    unsafe impl Send for DummyOutputAdapter {}
34
35    impl Write for DummyOutputAdapter
36    {
37        fn write_str(&mut self, _s: &str) -> fmt::Result 
38        {
39            return Ok(());
40        }
41    }
42
43    impl DummyOutputAdapter
44    {
45        fn new() -> Self
46        {
47            return Self{};
48        }
49    }
50
51    static IS_INITIALIZED: OnceLock<bool> = OnceLock::new();
52
53
54     /// An instance which implements the io::Write + Send
55     static WRITABLE_BUFFER: LazyLock<Mutex<Box<dyn Write + Send>>> = LazyLock::new(|| { Mutex::new(Box::new(DummyOutputAdapter::new())) });
56     static LAST_ERROR: LazyLock<Mutex<Option<String>>> = LazyLock::new(|| { Mutex::new(None) });
57 
58
59    /// Initializes the output to the custom buffer.
60    /// This function does not check if you set the output twice and panics!
61    /// 
62    /// # Arguments
63    /// 
64    /// * `w` - a dynamic instance in [Box] which implements [Write] and [Send]
65    /// 
66    /// # Panics
67    /// 
68    /// If the mutex was poisoned, may panic. Also will panic, if it will be 
69    /// attempted to reinitialize the instance. If this is a problem, use 
70    /// [initialize_safe]
71    pub async 
72    fn initialize(w: Box<dyn Write + Send>)
73    {
74        // occure the lock
75        let mut lock = WRITABLE_BUFFER.lock().await;
76
77        // set new instance
78        (*lock) = w;
79
80        // lock the status
81        IS_INITIALIZED.get_or_init(|| true);
82
83        return;
84    }
85
86    /// Initializes the output to the custom buffer.
87    /// This function does not check if you set the output twice.
88    /// 
89    /// # Arguments
90    /// 
91    /// * `w` - a dynamic instance in [Box] which implements [Write] and [Send]
92    /// 
93    /// # Returns
94    /// 
95    /// * [bool] true if mutex is not poisoned
96    /// 
97    /// * [bool] false if mutex was poisoned
98    /// 
99    /// # Panics
100    /// 
101    /// Does not panic!
102    pub async 
103    fn initialize_safe(w: Box<dyn Write + Send>) -> bool
104    {
105        // check if instance is initialized
106        if let None = IS_INITIALIZED.get()
107        {
108            // lock
109            let mut mutx = WRITABLE_BUFFER.lock().await;
110            // set instance
111            *mutx = w;
112
113            // lock
114            IS_INITIALIZED.get_or_init(|| true);
115
116            return true;
117        }
118        else
119        {
120            return false;
121        }
122    }
123
124    /// Returns the status. Once initialized, can not be deinitialized.
125    /// 
126    /// # Returns
127    /// 
128    /// * [bool] true, if initialized
129    /// 
130    /// * [bool] false, if not initialized
131    /// 
132    /// # Panics
133    /// 
134    /// May panic is mutex is poisoned!
135    pub 
136    fn is_initialized() -> bool
137    {
138        return IS_INITIALIZED.get().is_some();
139    }
140
141    /// Returns the status of the mutex answering the quiestion if
142    /// the mutex which guards the access is poisoned.
143    /// 
144    /// # Returns
145    /// 
146    /// * [bool] true, if poisoned
147    /// 
148    /// * [bool] false, if not poisoned
149    /// 
150    /// # Panics
151    /// 
152    /// Never panics!
153    pub 
154    fn is_poisoned() -> bool
155    {
156        return false;
157    }
158
159    /// Moves the last error from storage.
160    pub async
161    fn last_error() -> Option<String>
162    {
163        let mut mutx = LAST_ERROR.lock().await;
164        
165        return (*mutx).take();
166    }
167
168    #[inline]
169    pub async
170    fn cdns_custom_output_write(s: &str)
171    {
172        if IS_INITIALIZED.get().is_some() == false
173        {
174            // just ignore
175            return;
176        }
177
178        let mut mutx = WRITABLE_BUFFER.lock().await;
179        
180        let err = mutx.write_str(s);
181
182        if let Err(e) = err
183        {
184            let mut err_mutx = LAST_ERROR.lock().await;
185            *err_mutx = Some(e.to_string());
186        }
187
188        return;
189    }
190}
191
192use crate::error::Writer;
193
194/*
195n = force_none
196c = force_custom
197d = debug_assertions
198t = test
199
200V - set
201X - not allowed
202O - does not care, ignored
203     n c d t
204none V X O O
205std  X X O O
206cus  X V O O
207*/
208
209#[cfg(
210    all(
211        feature = "no_error_output",
212        feature = "custom_error_output",
213    )
214)]
215compile_error!("It is not allowed to use features 
216    'no_error_output' and 'custom_error_output' simultaniously");
217
218
219// ------ OUTPUT to stdout and stderr ------ FEAUTE: no + any(debug_assertions, test)
220
221/// A macro for printing error to stderror all error messages generated by
222/// the library.
223#[cfg(
224    all(
225        not(feature = "no_error_output"),
226        not(feature = "custom_error_output"),
227        any( debug_assertions, test)
228    )
229)]
230#[macro_export]
231macro_rules! async_write_error 
232{
233    ($($arg:tt)*) => (
234        eprintln!($($arg)*)
235    )
236}
237
238#[cfg(
239    all(
240        not(feature = "no_error_output"),
241        not(feature = "custom_error_output"),
242        any( debug_assertions, test)
243    )
244)]
245pub async
246fn async_log_writer(w: Writer)
247{
248    eprintln!("{}", s);
249}
250
251
252// ------ OUTPUT to custom ----- FEATURE: custom_error_output
253
254#[cfg(
255    all(
256        not(feature = "no_error_output"),
257        feature = "custom_error_output",
258        any(debug_assertions, test)
259    )
260)]
261pub use cdns_custom_output::*;
262
263
264/// A macro for printing to progrmas buffer all error messages generated by
265/// the library.
266#[cfg(
267    all(
268        not(feature = "no_error_output"),
269        feature = "custom_error_output",
270        any(debug_assertions, test)
271    )
272)]
273#[macro_export]
274macro_rules! async_write_error 
275{
276    ($($arg:tt)*) => (
277        $crate::sync::log::cdns_custom_output::cdns_custom_output_write(format!($($arg)*).as_str())
278    )
279}
280
281#[cfg(
282    all(
283        not(feature = "no_error_output"),
284        feature = "custom_error_output",
285        any(debug_assertions, test)
286    )
287)]
288pub async 
289fn async_log_writer(w: Writer)
290{
291    if w.is_some() == true
292    {
293        cdns_custom_output_write(unsafe { w.get_str() }).await;
294    }
295}
296
297// ----- OUTPUT to null ----- FEATURE: no_error_output
298
299/*#[cfg(
300    all(
301        not(feature = "custom_error_output"),
302        feature = "no_error_output",
303    )
304)]
305#[inline]
306pub 
307fn empty_func() { return; }*/
308
309/// A macro for printing to nowhere all error messages generated by
310/// the library.
311#[cfg(
312    all(
313        not(feature = "custom_error_output"),
314        feature = "no_error_output",
315    )
316)]
317#[macro_export]
318macro_rules! async_write_error 
319{
320    ($($arg:tt)*) => (
321        {}
322    )
323}
324
325#[cfg(
326    all(
327        not(feature = "custom_error_output"),
328        feature = "no_error_output",
329    )
330)]
331pub async 
332fn async_log_writer(_w: Writer)
333{
334    return;
335}
336