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}