use llvm_sys::core::{
LLVMCreateMemoryBufferWithContentsOfFile, LLVMCreateMemoryBufferWithMemoryRange,
LLVMCreateMemoryBufferWithMemoryRangeCopy, LLVMCreateMemoryBufferWithSTDIN, LLVMDisposeMemoryBuffer,
LLVMGetBufferSize, LLVMGetBufferStart,
};
use llvm_sys::object::LLVMCreateBinary;
use llvm_sys::prelude::LLVMMemoryBufferRef;
use crate::context::Context;
use crate::object_file::BinaryFile;
use crate::support::{LLVMString, to_c_str};
use std::marker::PhantomData;
use std::path::Path;
use std::ptr;
use std::slice;
#[derive(Debug)]
pub struct MemoryBuffer<'a> {
pub(crate) memory_buffer: LLVMMemoryBufferRef,
_phantom: PhantomData<&'a [u8]>,
}
impl MemoryBuffer<'static> {
pub fn create_from_file(path: &Path) -> Result<Self, LLVMString> {
let path = to_c_str(path.to_str().expect("Did not find a valid Unicode path string"));
let mut memory_buffer = ptr::null_mut();
let mut err_string = ptr::null_mut();
let is_err = unsafe {
LLVMCreateMemoryBufferWithContentsOfFile(path.as_ptr(), &mut memory_buffer, &mut err_string) == 1
};
if is_err {
unsafe {
return Err(LLVMString::new(err_string));
}
}
unsafe { Ok(Self::new(memory_buffer)) }
}
pub fn create_from_stdin() -> Result<Self, LLVMString> {
let mut memory_buffer = ptr::null_mut();
let mut err_string = ptr::null_mut();
let is_err = unsafe { LLVMCreateMemoryBufferWithSTDIN(&mut memory_buffer, &mut err_string) == 1 };
if is_err {
unsafe {
return Err(LLVMString::new(err_string));
}
}
unsafe { Ok(Self::new(memory_buffer)) }
}
pub fn create_from_memory_range_copy(input: &[u8], name: &str) -> Self {
assert_eq!(
input[input.len() - 1],
b'\0',
"input byte slice must terminate with a nul byte"
);
let name_c_string = to_c_str(name);
let memory_buffer = unsafe {
LLVMCreateMemoryBufferWithMemoryRangeCopy(
input.as_ptr() as *const libc::c_char,
input.len() - 1,
name_c_string.as_ptr(),
)
};
unsafe { Self::new(memory_buffer) }
}
}
impl<'a> MemoryBuffer<'a> {
pub unsafe fn new(memory_buffer: LLVMMemoryBufferRef) -> Self {
assert!(!memory_buffer.is_null());
Self {
memory_buffer,
_phantom: PhantomData,
}
}
pub fn as_mut_ptr(&self) -> LLVMMemoryBufferRef {
self.memory_buffer
}
pub fn create_from_memory_range(input: &'a [u8], name: &str) -> Self {
assert_eq!(
input[input.len() - 1],
b'\0',
"input byte slice must terminate with a nul byte"
);
let name_c_string = to_c_str(name);
let memory_buffer = unsafe {
LLVMCreateMemoryBufferWithMemoryRange(
input.as_ptr() as *const libc::c_char,
input.len() - 1,
name_c_string.as_ptr(),
false as i32, )
};
unsafe { MemoryBuffer::new(memory_buffer) }
}
pub fn as_slice(&self) -> &[u8] {
unsafe {
let start = LLVMGetBufferStart(self.memory_buffer);
slice::from_raw_parts(start as *const _, self.get_size())
}
}
pub fn get_size(&self) -> usize {
unsafe { LLVMGetBufferSize(self.memory_buffer) + 1 }
}
pub fn create_binary_file(&self, context: Option<&Context>) -> Result<BinaryFile<'_>, LLVMString> {
let context = context.map_or(ptr::null_mut(), |c| c.raw());
let mut err_string = ptr::null_mut();
let binary_file = unsafe { LLVMCreateBinary(self.memory_buffer, context, &mut err_string) };
if binary_file.is_null() {
unsafe {
return Err(LLVMString::new(err_string));
}
}
unsafe { Ok(BinaryFile::new(binary_file)) }
}
}
impl<'a> Drop for MemoryBuffer<'a> {
fn drop(&mut self) {
unsafe {
LLVMDisposeMemoryBuffer(self.memory_buffer);
}
}
}