1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use core::fmt::Arguments;

pub static DL_DEBUG: bool = cfg!(feature = "debug");
pub static DL_CHECKS: bool = cfg!(feature = "checks");
pub static DL_VERBOSE: bool = cfg!(feature = "verbose");
pub static VERBOSE_DEL: &str = "====================================";

#[cfg(unix)]
mod ext {
    pub fn debug(s: &str, _size: usize) {
        libc_print::libc_println!("{}", s);
    }
}

#[cfg(windows)]
mod ext {
    pub fn debug(_s: &str, _size: usize) {
        unreachable!("Windows is unsupported");
    }
}

#[cfg(target_arch = "wasm32")]
mod ext {
    mod sys {
        extern "C" {
            pub fn gr_debug(msg_ptr: *const u8, msg_len: u32);
        }
    }
    pub fn debug(s: &str, size: usize) {
        unsafe { sys::gr_debug(s.as_ptr(), size as _) }
    }
}

/// Static out buffer type
type StaticStr = str_buf::StrBuf<200>;
/// Static out buffer - we use it to avoid memory allocations,
/// when something is printed inside allocator code.
static mut OUT_BUFFER: StaticStr = StaticStr::new();

/// Prints string with args.
/// What is the out stream defines in @ext module.
#[inline(never)]
pub fn dlprint_fn(args: Arguments<'_>) {
    unsafe {
        core::fmt::write(&mut OUT_BUFFER, args).unwrap();
        ext::debug(&OUT_BUFFER, OUT_BUFFER.len());
        OUT_BUFFER.set_len(0);
    }
}

/// Prints string with args.
/// What is the out stream defines in @ext module.
#[inline(never)]
pub fn dlwrite_fn(args: Arguments<'_>) {
    unsafe {
        core::fmt::write(&mut OUT_BUFFER, args).unwrap();
    }
}

/// Prints string with args if @DL_VERBOSE is set.
/// What is the out stream defines in @ext module.
#[macro_export]
macro_rules! dlverbose {
    ($($arg:tt)*) => {
        if crate::dlverbose::DL_VERBOSE {
            crate::dlverbose::dlprint_fn(format_args!($($arg)*))
        }
    }
}

/// Prints string with args if @DL_VERBOSE is set.
/// What is the out stream defines in @ext module.
#[macro_export]
macro_rules! dlverbose_no_flush {
    ($($arg:tt)*) => {
        if crate::dlverbose::DL_VERBOSE {
            crate::dlverbose::dlwrite_fn(format_args!($($arg)*))
        }
    }
}

extern crate alloc;
use self::alloc::alloc::handle_alloc_error;

/// Prints current line and throw error using @handle_alloc_error.
#[inline(never)]
pub fn dlassert_fn(line: u32) {
    dlprint_fn(format_args!("ALLOC ASSERT: {}", line));
    handle_alloc_error(self::alloc::alloc::Layout::new::<u32>());
}

/// Acts like assert using handle_alloc_error if @DL_CHECKS is set, else does nothing.
#[macro_export]
macro_rules! dlassert {
    ($check:expr) => {
        if crate::dlverbose::DL_DEBUG && !($check) {
            crate::dlverbose::dlassert_fn(line!());
        }
    };
}