Skip to main content

melior/
string_ref.rs

1use mlir_sys::{MlirStringRef, mlirStringRefEqual};
2use std::{
3    ffi::CStr,
4    marker::PhantomData,
5    slice,
6    str::{self, Utf8Error},
7};
8
9/// A string reference.
10#[derive(Clone, Copy, Debug)]
11pub struct StringRef<'a> {
12    raw: MlirStringRef,
13    _parent: PhantomData<&'a str>,
14}
15
16impl<'a> StringRef<'a> {
17    /// Creates a string reference.
18    pub fn new(string: &'a str) -> Self {
19        let string = MlirStringRef {
20            data: string.as_bytes().as_ptr() as *const _,
21            length: string.len(),
22        };
23
24        unsafe { Self::from_raw(string) }
25    }
26
27    /// Converts a C-style string into a string reference.
28    pub fn from_c_str(string: &'a CStr) -> Self {
29        let string = MlirStringRef {
30            data: string.as_ptr(),
31            length: string.to_bytes_with_nul().len() - 1,
32        };
33
34        unsafe { Self::from_raw(string) }
35    }
36
37    /// Converts a string reference into a `str`.
38    pub fn as_str(&self) -> Result<&'a str, Utf8Error> {
39        unsafe {
40            let bytes = slice::from_raw_parts(self.raw.data as *mut u8, self.raw.length);
41
42            str::from_utf8(if bytes[bytes.len() - 1] == 0 {
43                &bytes[..bytes.len() - 1]
44            } else {
45                bytes
46            })
47        }
48    }
49
50    /// Converts a string reference into a raw object.
51    pub const fn to_raw(self) -> MlirStringRef {
52        self.raw
53    }
54
55    /// Creates a string reference from a raw object.
56    ///
57    /// # Safety
58    ///
59    /// A raw object must be valid.
60    pub unsafe fn from_raw(string: MlirStringRef) -> Self {
61        Self {
62            raw: string,
63            _parent: Default::default(),
64        }
65    }
66}
67
68impl PartialEq for StringRef<'_> {
69    fn eq(&self, other: &Self) -> bool {
70        unsafe { mlirStringRefEqual(self.raw, other.raw) }
71    }
72}
73
74impl Eq for StringRef<'_> {}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn equal() {
82        assert_eq!(StringRef::new("foo"), StringRef::new("foo"));
83    }
84
85    #[test]
86    fn equal_str() {
87        assert_eq!(StringRef::new("foo").as_str().unwrap(), "foo");
88    }
89
90    #[test]
91    fn not_equal() {
92        assert_ne!(StringRef::new("foo"), StringRef::new("bar"));
93    }
94}