Skip to main content

milo_parser/
native.rs

1#![allow(clippy::not_unsafe_ptr_arg_deref)]
2
3use core::ptr;
4use core::str;
5use core::{slice, slice::from_raw_parts};
6use std::ffi::{CString, c_char, c_uchar};
7
8use crate::Parser;
9use crate::parse;
10
11#[repr(C)]
12pub struct CStringWithLength {
13  pub ptr: *const c_uchar,
14  pub len: usize,
15}
16
17impl CStringWithLength {
18  fn new(value: &str) -> CStringWithLength {
19    let cstring = CString::new(value).unwrap();
20
21    CStringWithLength {
22      ptr: cstring.into_raw() as *const c_uchar,
23      len: value.len(),
24    }
25  }
26}
27
28impl From<&str> for CStringWithLength {
29  fn from(value: &str) -> Self { CStringWithLength::new(value) }
30}
31
32impl From<CStringWithLength> for &str {
33  fn from(value: CStringWithLength) -> Self {
34    unsafe { str::from_utf8_unchecked(slice::from_raw_parts(value.ptr, value.len)) }
35  }
36}
37
38/// Returns if debug informations are available in this build.
39#[unsafe(no_mangle)]
40pub extern "C" fn milo_has_debug() -> bool { cfg!(any(debug_assertions, feature = "debug")) }
41
42/// A callback that simply returns `0`.
43///
44/// Use this callback as pointer when you want to remove a callback from the
45/// parser.
46#[unsafe(no_mangle)]
47pub extern "C" fn milo_noop(_parser: &mut Parser, _at: usize, _len: usize) {}
48
49/// Cleans up memory used by a string previously returned by one of the milo's C
50/// public interface.
51#[unsafe(no_mangle)]
52pub extern "C" fn milo_free_string(s: CStringWithLength) {
53  unsafe {
54    let _ = CString::from_raw(s.ptr as *mut c_char);
55  }
56}
57
58/// Creates a new parser.
59#[unsafe(no_mangle)]
60pub extern "C" fn milo_create() -> *mut Parser { Box::into_raw(Box::new(Parser::new())) }
61
62/// Destroys a parser.
63#[unsafe(no_mangle)]
64pub extern "C" fn milo_destroy(parser: *mut Parser) {
65  if parser.is_null() {
66    return;
67  }
68
69  unsafe {
70    let _ = Box::from_raw(parser);
71  }
72}
73
74/// Parses a slice of characters. It returns the number of consumed characters.
75#[unsafe(no_mangle)]
76pub extern "C" fn milo_parse(parser: *mut Parser, data: *const c_uchar, limit: usize) -> usize {
77  unsafe { (*parser).parse(data, limit) }
78}
79
80/// Resets a parser. The second parameters specifies if to also reset the
81/// parsed counter.
82///
83/// The following fields are not modified:
84///   * position
85///   * context
86///   * autodetect
87///   * is_request
88///   * manage_unconsumed
89///   * continue_without_data
90///   * context
91#[unsafe(no_mangle)]
92pub extern "C" fn milo_reset(parser: *mut Parser, keep_parsed: bool) { unsafe { (*parser).reset(keep_parsed) } }
93
94/// Clears all values about the message in the parser.
95///
96/// The autodetect and is_request fields are not cleared.
97#[unsafe(no_mangle)]
98pub extern "C" fn milo_clear(parser: *mut Parser) { unsafe { (*parser).clear() } }
99
100/// Pauses the parser. It will have to be resumed via `milo_resume`.
101#[unsafe(no_mangle)]
102pub extern "C" fn milo_pause(parser: *mut Parser) { unsafe { (*parser).pause() } }
103
104/// Resumes the parser.
105#[unsafe(no_mangle)]
106pub extern "C" fn milo_resume(parser: *mut Parser) { unsafe { (*parser).resume() } }
107
108/// Marks the parser as finished. Any new data received via `milo_parse` will
109/// put the parser in the error state.
110#[unsafe(no_mangle)]
111pub extern "C" fn milo_finish(parser: *mut Parser) { unsafe { (*parser).finish() } }
112
113/// Marks the parsing a failed, setting a error code and and error message.
114#[unsafe(no_mangle)]
115pub extern "C" fn milo_fail(parser: *mut Parser, code: u8, description: CStringWithLength) {
116  unsafe { (*parser).fail(code, description.into()) };
117}
118
119/// Returns the current parser's state as string.
120///
121/// The returned value must be freed using `free_string`.
122#[unsafe(no_mangle)]
123pub extern "C" fn milo_state_string(parser: *mut Parser) -> CStringWithLength {
124  unsafe { (*parser).state_str().into() }
125}
126
127/// Returns the current parser's error state as string.
128///
129/// The returned value must be freed using `free_string`.
130#[unsafe(no_mangle)]
131pub extern "C" fn milo_error_code_string(parser: *mut Parser) -> CStringWithLength {
132  unsafe { (*parser).error_code_str().into() }
133}
134
135/// Returns the current parser's error descrition.
136///
137/// The returned value must be freed using `free_string`.
138#[unsafe(no_mangle)]
139pub extern "C" fn milo_error_description_string(parser: *mut Parser) -> CStringWithLength {
140  unsafe { (*parser).error_description_str().into() }
141}