Skip to main content

unsafe_libyaml/
lib.rs

1//! [![github]](https://github.com/dtolnay/unsafe-libyaml) [![crates-io]](https://crates.io/crates/unsafe-libyaml) [![docs-rs]](https://docs.rs/unsafe-libyaml)
2//!
3//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
4//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
5//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
6
7#![no_std]
8#![doc(html_root_url = "https://docs.rs/unsafe-libyaml/0.2.11")]
9#![allow(non_camel_case_types, non_snake_case, unsafe_op_in_unsafe_fn)]
10#![warn(clippy::pedantic)]
11#![allow(
12    clippy::bool_to_int_with_if,
13    clippy::cast_lossless,
14    clippy::cast_possible_truncation,
15    clippy::cast_possible_wrap,
16    clippy::cast_ptr_alignment,
17    clippy::cast_sign_loss,
18    clippy::collapsible_if,
19    clippy::doc_markdown,
20    clippy::fn_params_excessive_bools,
21    clippy::if_not_else,
22    clippy::items_after_statements,
23    clippy::let_underscore_untyped,
24    clippy::manual_range_contains,
25    clippy::manual_swap,
26    clippy::missing_panics_doc,
27    clippy::missing_safety_doc,
28    clippy::module_name_repetitions,
29    clippy::must_use_candidate,
30    clippy::nonminimal_bool,
31    clippy::ptr_as_ptr,
32    clippy::redundant_else,
33    clippy::similar_names,
34    clippy::single_match,
35    clippy::single_match_else,
36    clippy::too_many_arguments,
37    clippy::too_many_lines,
38    clippy::uninlined_format_args,
39    clippy::unnecessary_cast,
40    clippy::unreadable_literal,
41    clippy::while_immutable_condition, // https://github.com/rust-lang/rust-clippy/issues/3548
42)]
43
44extern crate alloc;
45
46use core::mem::size_of;
47
48mod libc {
49    pub use core::{
50        ffi::c_void,
51        primitive::{i8 as c_char, i32 as c_int, i64 as c_long, u8 as c_uchar, u32 as c_uint, u64 as c_ulong},
52    };
53}
54
55#[macro_use]
56mod externs {
57    use alloc::alloc::{self as rust, Layout};
58    use core::{
59        mem::{self, MaybeUninit},
60        ptr, slice,
61    };
62
63    use crate::{
64        libc,
65        ops::{ForceAdd as _, ForceInto as _, die},
66    };
67
68    const HEADER: usize = {
69        let need_len = mem::size_of::<usize>();
70        // Round up to multiple of MALLOC_ALIGN.
71        (need_len + MALLOC_ALIGN - 1) & !(MALLOC_ALIGN - 1)
72    };
73
74    // `max_align_t` may be bigger than this, but libyaml does not use `long
75    // double` or u128.
76    const MALLOC_ALIGN: usize = {
77        let int_align = mem::align_of::<libc::c_ulong>();
78        let ptr_align = mem::align_of::<usize>();
79        if int_align >= ptr_align { int_align } else { ptr_align }
80    };
81
82    pub unsafe fn malloc(size: libc::c_ulong) -> *mut libc::c_void {
83        let size = HEADER.force_add(size.force_into());
84        let layout = Layout::from_size_align(size, MALLOC_ALIGN).ok().unwrap_or_else(die);
85        let memory = rust::alloc(layout);
86        if memory.is_null() {
87            rust::handle_alloc_error(layout);
88        }
89        memory.cast::<usize>().write(size);
90        memory.add(HEADER).cast()
91    }
92
93    pub unsafe fn realloc(ptr: *mut libc::c_void, new_size: libc::c_ulong) -> *mut libc::c_void {
94        let mut memory = ptr.cast::<u8>().sub(HEADER);
95        let size = memory.cast::<usize>().read();
96        let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN);
97        let new_size = HEADER.force_add(new_size.force_into());
98        let new_layout = Layout::from_size_align(new_size, MALLOC_ALIGN).ok().unwrap_or_else(die);
99        memory = rust::realloc(memory, layout, new_size);
100        if memory.is_null() {
101            rust::handle_alloc_error(new_layout);
102        }
103        memory.cast::<usize>().write(new_size);
104        memory.add(HEADER).cast()
105    }
106
107    pub unsafe fn free(ptr: *mut libc::c_void) {
108        let memory = ptr.cast::<u8>().sub(HEADER);
109        let size = memory.cast::<usize>().read();
110        let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN);
111        rust::dealloc(memory, layout);
112    }
113
114    pub unsafe fn memcmp(lhs: *const libc::c_void, rhs: *const libc::c_void, count: libc::c_ulong) -> libc::c_int {
115        let lhs = slice::from_raw_parts(lhs.cast::<u8>(), count as usize);
116        let rhs = slice::from_raw_parts(rhs.cast::<u8>(), count as usize);
117        lhs.cmp(rhs) as libc::c_int
118    }
119
120    pub unsafe fn memcpy(dest: *mut libc::c_void, src: *const libc::c_void, count: libc::c_ulong) -> *mut libc::c_void {
121        ptr::copy_nonoverlapping(src.cast::<MaybeUninit<u8>>(), dest.cast::<MaybeUninit<u8>>(), count as usize);
122        dest
123    }
124
125    pub unsafe fn memmove(
126        dest: *mut libc::c_void,
127        src: *const libc::c_void,
128        count: libc::c_ulong,
129    ) -> *mut libc::c_void {
130        ptr::copy(src.cast::<MaybeUninit<u8>>(), dest.cast::<MaybeUninit<u8>>(), count as usize);
131        dest
132    }
133
134    pub unsafe fn memset(dest: *mut libc::c_void, ch: libc::c_int, count: libc::c_ulong) -> *mut libc::c_void {
135        ptr::write_bytes(dest.cast::<u8>(), ch as u8, count as usize);
136        dest
137    }
138
139    pub unsafe fn strcmp(lhs: *const libc::c_char, rhs: *const libc::c_char) -> libc::c_int {
140        let lhs = slice::from_raw_parts(lhs.cast::<u8>(), strlen(lhs) as usize);
141        let rhs = slice::from_raw_parts(rhs.cast::<u8>(), strlen(rhs) as usize);
142        lhs.cmp(rhs) as libc::c_int
143    }
144
145    pub unsafe fn strdup(src: *const libc::c_char) -> *mut libc::c_char {
146        let len = strlen(src);
147        let dest = malloc(len + 1);
148        memcpy(dest, src.cast(), len + 1);
149        dest.cast()
150    }
151
152    pub unsafe fn strlen(str: *const libc::c_char) -> libc::c_ulong {
153        let mut end = str;
154        while *end != 0 {
155            end = end.add(1);
156        }
157        end.offset_from(str) as libc::c_ulong
158    }
159
160    pub unsafe fn strncmp(lhs: *const libc::c_char, rhs: *const libc::c_char, mut count: libc::c_ulong) -> libc::c_int {
161        let mut lhs = lhs.cast::<u8>();
162        let mut rhs = rhs.cast::<u8>();
163        while count > 0 && *lhs != 0 && *lhs == *rhs {
164            lhs = lhs.add(1);
165            rhs = rhs.add(1);
166            count -= 1;
167        }
168        if count == 0 {
169            0
170        } else {
171            (*lhs).cmp(&*rhs) as libc::c_int
172        }
173    }
174
175    macro_rules! __assert {
176        (false $(,)?) => {
177            $crate::externs::__assert_fail(stringify!(false), file!(), line!())
178        };
179        ($assertion:expr $(,)?) => {
180            if !$assertion {
181                $crate::externs::__assert_fail(stringify!($assertion), file!(), line!());
182            }
183        };
184    }
185
186    pub(crate) unsafe fn __assert_fail(__assertion: &'static str, __file: &'static str, __line: u32) -> ! {
187        struct Abort;
188        impl Drop for Abort {
189            fn drop(&mut self) {
190                panic!();
191            }
192        }
193        let _abort_on_panic = Abort;
194        panic!("{}:{}: Assertion `{}` failed.", __file, __line, __assertion);
195    }
196}
197
198mod fmt {
199    use core::{
200        fmt::{self, Write},
201        ptr,
202    };
203
204    use crate::yaml::yaml_char_t;
205
206    pub struct WriteToPtr {
207        ptr: *mut yaml_char_t,
208    }
209
210    impl WriteToPtr {
211        pub unsafe fn new(ptr: *mut yaml_char_t) -> Self {
212            WriteToPtr {
213                ptr,
214            }
215        }
216
217        pub fn write_fmt(&mut self, args: fmt::Arguments) {
218            let _ = Write::write_fmt(self, args);
219        }
220    }
221
222    impl Write for WriteToPtr {
223        fn write_str(&mut self, s: &str) -> fmt::Result {
224            unsafe {
225                ptr::copy_nonoverlapping(s.as_ptr(), self.ptr, s.len());
226                self.ptr = self.ptr.add(s.len());
227            }
228            Ok(())
229        }
230    }
231}
232
233trait PointerExt: Sized {
234    fn c_offset_from(self, origin: Self) -> isize;
235}
236
237impl<T> PointerExt for *const T {
238    fn c_offset_from(self, origin: *const T) -> isize {
239        (self as isize - origin as isize) / size_of::<T>() as isize
240    }
241}
242
243impl<T> PointerExt for *mut T {
244    fn c_offset_from(self, origin: *mut T) -> isize {
245        (self as isize - origin as isize) / size_of::<T>() as isize
246    }
247}
248
249#[macro_use]
250mod macros;
251
252mod api;
253mod dumper;
254mod emitter;
255mod loader;
256mod ops;
257mod parser;
258mod reader;
259mod scanner;
260mod success;
261mod writer;
262mod yaml;
263
264#[doc(hidden)]
265pub use crate::yaml::{
266    yaml_break_t::*, yaml_emitter_state_t::*, yaml_encoding_t::*, yaml_error_type_t::*, yaml_event_type_t::*,
267    yaml_mapping_style_t::*, yaml_node_type_t::*, yaml_parser_state_t::*, yaml_scalar_style_t::*,
268    yaml_sequence_style_t::*, yaml_token_type_t::*,
269};
270pub use crate::{
271    api::{
272        yaml_alias_event_initialize, yaml_document_add_mapping, yaml_document_add_scalar, yaml_document_add_sequence,
273        yaml_document_append_mapping_pair, yaml_document_append_sequence_item, yaml_document_delete,
274        yaml_document_end_event_initialize, yaml_document_get_node, yaml_document_get_root_node,
275        yaml_document_initialize, yaml_document_start_event_initialize, yaml_emitter_delete, yaml_emitter_initialize,
276        yaml_emitter_set_break, yaml_emitter_set_canonical, yaml_emitter_set_encoding, yaml_emitter_set_indent,
277        yaml_emitter_set_output, yaml_emitter_set_output_string, yaml_emitter_set_unicode, yaml_emitter_set_width,
278        yaml_event_delete, yaml_mapping_end_event_initialize, yaml_mapping_start_event_initialize, yaml_parser_delete,
279        yaml_parser_initialize, yaml_parser_set_encoding, yaml_parser_set_input, yaml_parser_set_input_string,
280        yaml_scalar_event_initialize, yaml_sequence_end_event_initialize, yaml_sequence_start_event_initialize,
281        yaml_stream_end_event_initialize, yaml_stream_start_event_initialize, yaml_token_delete,
282    },
283    dumper::{yaml_emitter_close, yaml_emitter_dump, yaml_emitter_open},
284    emitter::yaml_emitter_emit,
285    loader::yaml_parser_load,
286    parser::yaml_parser_parse,
287    scanner::yaml_parser_scan,
288    writer::yaml_emitter_flush,
289    yaml::{
290        yaml_alias_data_t, yaml_break_t, yaml_document_t, yaml_emitter_state_t, yaml_emitter_t, yaml_encoding_t,
291        yaml_error_type_t, yaml_event_t, yaml_event_type_t, yaml_mapping_style_t, yaml_mark_t, yaml_node_item_t,
292        yaml_node_pair_t, yaml_node_t, yaml_node_type_t, yaml_parser_state_t, yaml_parser_t, yaml_read_handler_t,
293        yaml_scalar_style_t, yaml_sequence_style_t, yaml_simple_key_t, yaml_stack_t, yaml_tag_directive_t,
294        yaml_token_t, yaml_token_type_t, yaml_version_directive_t, yaml_write_handler_t,
295    },
296};