llvm_plugin_inkwell/support/
mod.rs1#[deny(missing_docs)]
2pub mod error_handling;
3
4use libc::c_char;
5#[llvm_versions(16.0)]
6use llvm_sys::core::LLVMGetVersion;
7use llvm_sys::core::{LLVMCreateMessage, LLVMDisposeMessage};
8use llvm_sys::error_handling::LLVMEnablePrettyStackTrace;
9use llvm_sys::support::LLVMLoadLibraryPermanently;
10
11use std::borrow::Cow;
12use std::error::Error;
13use std::ffi::{CStr, CString};
14use std::fmt::{self, Debug, Display, Formatter};
15use std::ops::Deref;
16
17#[derive(Eq)]
19pub struct LLVMString {
20 pub(crate) ptr: *const c_char,
21}
22
23impl LLVMString {
24 pub(crate) unsafe fn new(ptr: *const c_char) -> Self {
25 LLVMString { ptr }
26 }
27
28 pub fn to_string(&self) -> String {
34 (*self).to_string_lossy().into_owned()
35 }
36
37 pub(crate) fn create_from_c_str(string: &CStr) -> LLVMString {
39 unsafe { LLVMString::new(LLVMCreateMessage(string.as_ptr() as *const _)) }
40 }
41
42 pub(crate) fn create_from_str(string: &str) -> LLVMString {
44 debug_assert_eq!(string.as_bytes()[string.as_bytes().len() - 1], 0);
45
46 unsafe { LLVMString::new(LLVMCreateMessage(string.as_ptr() as *const _)) }
47 }
48}
49
50impl Deref for LLVMString {
51 type Target = CStr;
52
53 fn deref(&self) -> &Self::Target {
54 unsafe { CStr::from_ptr(self.ptr) }
55 }
56}
57
58impl Debug for LLVMString {
59 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
60 write!(f, "{:?}", self.deref())
61 }
62}
63
64impl Display for LLVMString {
65 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
66 write!(f, "{:?}", self.deref())
67 }
68}
69
70impl PartialEq for LLVMString {
71 fn eq(&self, other: &LLVMString) -> bool {
72 **self == **other
73 }
74}
75
76impl Error for LLVMString {
77 fn description(&self) -> &str {
78 self.to_str()
79 .expect("Could not convert LLVMString to str (likely invalid unicode)")
80 }
81
82 fn cause(&self) -> Option<&dyn Error> {
83 None
84 }
85}
86
87impl Drop for LLVMString {
88 fn drop(&mut self) {
89 unsafe {
90 LLVMDisposeMessage(self.ptr as *mut _);
91 }
92 }
93}
94
95#[derive(Eq)]
100pub(crate) enum LLVMStringOrRaw {
101 Owned(LLVMString),
102 Borrowed(*const c_char),
103}
104
105impl LLVMStringOrRaw {
106 pub fn as_str(&self) -> &CStr {
107 match self {
108 LLVMStringOrRaw::Owned(llvm_string) => llvm_string.deref(),
109 LLVMStringOrRaw::Borrowed(ptr) => unsafe { CStr::from_ptr(*ptr) },
110 }
111 }
112}
113
114impl PartialEq for LLVMStringOrRaw {
115 fn eq(&self, other: &LLVMStringOrRaw) -> bool {
116 self.as_str() == other.as_str()
117 }
118}
119
120pub unsafe fn shutdown_llvm() {
123 use llvm_sys::core::LLVMShutdown;
124
125 LLVMShutdown()
126}
127
128#[llvm_versions(16.0..=latest)]
130pub fn get_llvm_version() -> (u32, u32, u32) {
131 let mut major: u32 = 0;
132 let mut minor: u32 = 0;
133 let mut patch: u32 = 0;
134
135 unsafe { LLVMGetVersion(&mut major, &mut minor, &mut patch) };
136
137 return (major, minor, patch);
138}
139
140pub fn load_library_permanently(filename: &str) -> bool {
141 let filename = to_c_str(filename);
142
143 unsafe { LLVMLoadLibraryPermanently(filename.as_ptr()) == 1 }
144}
145
146pub fn is_multithreaded() -> bool {
149 use llvm_sys::core::LLVMIsMultithreaded;
150
151 unsafe { LLVMIsMultithreaded() == 1 }
152}
153
154pub fn enable_llvm_pretty_stack_trace() {
155 unsafe { LLVMEnablePrettyStackTrace() }
156}
157
158pub(crate) fn to_c_str<'s>(mut s: &'s str) -> Cow<'s, CStr> {
164 if s.is_empty() {
165 s = "\0";
166 }
167
168 if !s.chars().rev().any(|ch| ch == '\0') {
170 return Cow::from(CString::new(s).expect("unreachable since null bytes are checked"));
171 }
172
173 unsafe { Cow::from(CStr::from_ptr(s.as_ptr() as *const _)) }
174}
175
176#[test]
177fn test_to_c_str() {
178 assert!(matches!(to_c_str("my string"), Cow::Owned(_)));
179 assert!(matches!(to_c_str("my string\0"), Cow::Borrowed(_)));
180}