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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//! Macros for memory management operations.
//!
//! This module provides a set of macros that wrap the unsafe memory management
//! functions, providing a slightly safer interface while still allowing
//! for low-level memory operations in a no_std environment.

/// Allocates memory using the system's `malloc` function.
///
/// This macro wraps the `yaml_malloc` function, providing a more Rust-like interface.
///
/// # Arguments
///
/// * `size` - The number of bytes to allocate.
///
/// # Returns
///
/// Returns a `*mut T` pointer to the allocated memory, or `None` if the allocation failed.
///
/// # Safety
///
/// While this macro provides a safer interface than direct use of `yaml_malloc`,
/// it is still unsafe because:
/// - It allocates uninitialized memory.
/// - The caller is responsible for properly freeing the allocated memory using `yaml_free!`.
/// - The caller must ensure the allocated memory is properly initialized before use.
///
/// # Examples
///
/// ```
/// use libyml::{yaml_malloc,yaml_free};
///
/// let size = 1024;
/// unsafe {
///     if let Some(ptr) = yaml_malloc!(u8, size) {
///         // Use the allocated memory
///         // ...
///         yaml_free!(ptr);
///     }
/// }
/// ```
#[macro_export]
macro_rules! yaml_malloc {
    ($t:ty, $size:expr) => {{
        let ptr = unsafe { $crate::memory::yaml_malloc($size) };
        if ptr.is_null() {
            None
        } else {
            Some(ptr as *mut $t)
        }
    }};
}

/// Reallocates memory using the system's `realloc` function.
///
/// This macro wraps the `yaml_realloc` function, providing a more Rust-like interface.
///
/// # Arguments
///
/// * `ptr` - A pointer to the memory block to reallocate.
/// * `size` - The new size of the memory block in bytes.
///
/// # Returns
///
/// Returns a `*mut T` pointer to the reallocated memory, or `None` if the reallocation failed.
///
/// # Safety
///
/// While this macro provides a safer interface than direct use of `yaml_realloc`,
/// it is still unsafe because:
/// - It may move the memory to a new location.
/// - The caller must ensure that `ptr` was previously allocated by `yaml_malloc!` or `yaml_realloc!`.
/// - The caller is responsible for properly freeing the reallocated memory using `yaml_free!`.
/// - The contents of the reallocated memory beyond the original size are undefined.
///
/// # Examples
///
/// ```
/// use libyml::{yaml_malloc, yaml_realloc, yaml_free};
///
/// unsafe {
///     let mut size = 1024;
///     if let Some(mut ptr) = yaml_malloc!(u8, size) {
///         // Use the allocated memory
///         // ...
///         size = 2048;
///         if let Some(new_ptr) = yaml_realloc!(ptr, u8, size) {
///             ptr = new_ptr;
///             // Use the reallocated memory
///             // ...
///             yaml_free!(ptr);
///         }
///     }
/// }
/// ```
#[macro_export]
macro_rules! yaml_realloc {
    ($ptr:expr, $t:ty, $size:expr) => {{
        let new_ptr = unsafe {
            $crate::memory::yaml_realloc($ptr as *mut _, $size)
        };
        if new_ptr.is_null() {
            None
        } else {
            Some(new_ptr as *mut $t)
        }
    }};
}

/// Frees memory allocated by `yaml_malloc!` or `yaml_realloc!`.
///
/// This macro wraps the `yaml_free` function, providing a more Rust-like interface.
///
/// # Arguments
///
/// * `ptr` - A pointer to the memory block to free.
///
/// # Safety
///
/// While this macro provides a safer interface than direct use of `yaml_free`,
/// it is still unsafe because:
/// - The caller must ensure that `ptr` was allocated by `yaml_malloc!` or `yaml_realloc!`.
/// - After calling this macro, `ptr` becomes invalid and must not be used.
///
/// # Examples
///
/// ```
/// use libyml::{yaml_malloc, yaml_free};
///
/// unsafe {
///     let size = 1024;
///     if let Some(ptr) = yaml_malloc!(u8, size) {
///         // Use the allocated memory
///         // ...
///         yaml_free!(ptr);
///         // ptr is now invalid and must not be used
///     }
/// }
/// ```
#[macro_export]
macro_rules! yaml_free {
    ($ptr:expr) => {
        unsafe { $crate::memory::yaml_free($ptr as *mut _) }
    };
}

/// Duplicates a string using the system's `malloc` function and manual copy.
///
/// This macro wraps the `yaml_strdup` function, providing a more Rust-like interface.
///
/// # Arguments
///
/// * `str` - A pointer to the null-terminated string to duplicate.
///
/// # Returns
///
/// Returns a `*mut yaml_char_t` pointer to the newly allocated string, or `None` if the allocation failed or the input was null.
///
/// # Safety
///
/// While this macro provides a safer interface than direct use of `yaml_strdup`,
/// it is still unsafe because:
/// - It involves memory allocation and raw pointer manipulation.
/// - The caller must ensure that `str` is a valid, null-terminated string.
/// - The caller is responsible for freeing the returned pointer using `yaml_free!`.
///
/// # Examples
///
/// ```
/// use libyml::yaml::yaml_char_t;
/// use libyml::{yaml_strdup, yaml_free};
///
/// unsafe {
///     let original = b"Hello, world!\0".as_ptr() as *const yaml_char_t;
///     if let Some(copy) = yaml_strdup!(original) {
///         // Use the duplicated string
///         // ...
///         yaml_free!(copy);
///     }
/// }
/// ```
#[macro_export]
macro_rules! yaml_strdup {
    ($str:expr) => {{
        let new_str = unsafe { $crate::memory::yaml_strdup($str) };
        if new_str.is_null() {
            None
        } else {
            Some(new_str)
        }
    }};
}