Skip to main content

vpp_plugin/vppinfra/
unformat.rs

1//! Generalised string parsing
2
3use std::ffi::c_int;
4
5use crate::bindings::{
6    unformat_init_string, unformat_input_t, uword, vlib_helper_unformat_free,
7    vlib_helper_unformat_get_input,
8};
9
10const UNFORMAT_END_OF_INPUT: uword = !0;
11
12/// Parse a line ending with a newline and return it
13///
14/// This is similar to the VPP C `unformat_line` function, but without use of varargs and
15/// returning a native Rust String.
16///
17/// This is useful for ensuring debug CLI command functions do not accidentally consume input
18/// belonging to other debug CLI commands when invoked as part of a script.
19///
20/// # Safety
21///
22/// - The pointer must be valid and point to a properly initialised `unformat_input_t`.
23/// - The pointer must stay valid and the contents must not be mutated for the duration of the
24///   call.
25pub unsafe fn raw_unformat_line_input_to_string(i: *mut unformat_input_t) -> String {
26    // SAFETY: The safety requirements are documented in the function's safety comment.
27    unsafe {
28        let mut line = vec![];
29        loop {
30            let b = vlib_helper_unformat_get_input(i);
31            if b == b'\n'.into() || b == UNFORMAT_END_OF_INPUT {
32                break;
33            }
34            line.push(b as u8);
35        }
36        String::from_utf8_lossy(&line).to_string()
37    }
38}
39
40/// Input to an unformat operation
41///
42/// This corresponds to the VPP C type of `unformat_input_t`.
43pub struct UnformatInput(unformat_input_t);
44
45impl UnformatInput {
46    /// Returns a raw pointer to the underlying `unformat_input_t`
47    pub fn as_ptr(&mut self) -> *mut unformat_input_t {
48        &mut self.0
49    }
50}
51
52impl From<&str> for UnformatInput {
53    fn from(value: &str) -> Self {
54        let mut me = Self(Default::default());
55        // SAFETY: the string pointer is valid and the length passed in is consistent.
56        // unformat_init_string copies the contents of the string into a vec no restrictions are
57        // needed on the lifetime of value.
58        unsafe {
59            unformat_init_string(&mut me.0, value.as_ptr().cast(), value.len() as c_int);
60        }
61        me
62    }
63}
64
65impl From<String> for UnformatInput {
66    fn from(value: String) -> Self {
67        value.as_str().into()
68    }
69}
70
71impl Drop for UnformatInput {
72    fn drop(&mut self) {
73        // SAFETY: this is a valid unformat_input_t which hasn't been previously freed
74        unsafe {
75            vlib_helper_unformat_free(self.as_ptr());
76        }
77    }
78}