pgdog_plugin/
string.rs

1//! Wrapper around Rust's [`str`], a UTF-8 encoded slice.
2//!
3//! This is used to pass strings back and forth between the plugin and
4//! PgDog, without allocating memory as required by [`std::ffi::CString`].
5//!
6//! ### Example
7//!
8//! ```
9//! use pgdog_plugin::PdStr;
10//! use std::ops::Deref;
11//!
12//! let string = PdStr::from("hello world");
13//! assert_eq!(string.deref(), "hello world");
14//!
15//! let string = string.to_string(); // Owned version.
16//! ```
17//!
18use crate::bindings::PdStr;
19use std::{ops::Deref, os::raw::c_void, slice::from_raw_parts, str::from_utf8_unchecked};
20
21impl From<&str> for PdStr {
22    fn from(value: &str) -> Self {
23        PdStr {
24            data: value.as_ptr() as *mut c_void,
25            len: value.len(),
26        }
27    }
28}
29
30impl From<&String> for PdStr {
31    fn from(value: &String) -> Self {
32        PdStr {
33            data: value.as_ptr() as *mut c_void,
34            len: value.len(),
35        }
36    }
37}
38
39impl Deref for PdStr {
40    type Target = str;
41
42    fn deref(&self) -> &Self::Target {
43        unsafe {
44            let slice = from_raw_parts::<u8>(self.data as *mut u8, self.len);
45            from_utf8_unchecked(slice)
46        }
47    }
48}
49
50impl PartialEq for PdStr {
51    fn eq(&self, other: &Self) -> bool {
52        **self == **other
53    }
54}
55
56impl Default for PdStr {
57    fn default() -> Self {
58        Self {
59            len: 0,
60            data: "".as_ptr() as *mut c_void,
61        }
62    }
63}
64
65#[cfg(test)]
66mod test {
67    use super::*;
68
69    #[test]
70    fn test_pd_str() {
71        let s = "one_two_three";
72        let pd = PdStr::from(s);
73        assert_eq!(pd.deref(), "one_two_three");
74
75        let s = String::from("one_two");
76        let pd = PdStr::from(&s);
77        assert_eq!(pd.deref(), "one_two");
78        assert_eq!(&*pd, "one_two");
79    }
80}