use crate::ir::reference::RuntimeReferenceValue;
use inkwell::builder::Builder;
use inkwell::types::{BasicTypeEnum, IntType, StructType};
use inkwell::values::{BasicValueEnum, IntValue, PointerValue};
use std::ffi::CStr;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct RuntimeArrayValue<'ink>(RuntimeReferenceValue<'ink>);
impl<'ink> RuntimeArrayValue<'ink> {
pub fn from_ptr(ptr: PointerValue<'ink>, array_type: StructType<'ink>) -> Result<Self, String> {
RuntimeReferenceValue::from_ptr(ptr, array_type).map(Self)
}
pub unsafe fn from_ptr_unchecked(ptr: PointerValue<'ink>) -> Self {
Self(RuntimeReferenceValue::from_ptr_unchecked(ptr))
}
pub fn get_name(&self) -> &CStr {
self.0.get_name()
}
fn get_array_ptr(&self, builder: &Builder<'ink>) -> PointerValue<'ink> {
self.0.get_data_ptr(builder)
}
pub fn get_length_ptr(&self, builder: &Builder<'ink>) -> PointerValue<'ink> {
let array_ptr = self.get_array_ptr(builder);
let value_name = array_ptr.get_name().to_string_lossy();
builder
.build_struct_gep(array_ptr, 0, &format!("{}->length", &value_name))
.expect("could not get `length` from array struct")
}
pub fn get_capacity(&self, builder: &Builder<'ink>) -> IntValue<'ink> {
let array_ptr = self.get_array_ptr(builder);
let value_name = array_ptr.get_name().to_string_lossy();
let length_ptr = builder
.build_struct_gep(array_ptr, 1, &format!("{}->capacity", &value_name))
.expect("could not get `length` from array struct");
builder
.build_load(length_ptr, &format!("{}.capacity", &value_name))
.into_int_value()
}
pub fn get_elements(&self, builder: &Builder<'ink>) -> PointerValue<'ink> {
let array_ptr = self.get_array_ptr(builder);
let value_name = array_ptr.get_name().to_string_lossy();
builder
.build_struct_gep(array_ptr, 2, &format!("{}->elements", &value_name))
.expect("could not get `elements` from array struct")
}
pub fn length_ty(&self) -> IntType {
self.array_data_ty()
.get_field_type_at_index(0)
.expect("an array must have a second field")
.into_int_type()
}
pub fn capacity_ty(&self) -> IntType {
self.array_data_ty()
.get_field_type_at_index(1)
.expect("an array must have a second field")
.into_int_type()
}
pub fn element_ty(&self) -> BasicTypeEnum<'ink> {
self.array_data_ty()
.get_field_type_at_index(2)
.expect("an array must have a second field")
}
fn array_data_ty(&self) -> StructType<'ink> {
self.0.get_type().into_struct_type()
}
}
impl<'ink> From<RuntimeArrayValue<'ink>> for BasicValueEnum<'ink> {
fn from(value: RuntimeArrayValue<'ink>) -> Self {
value.0.into()
}
}
impl<'ink> From<RuntimeArrayValue<'ink>> for PointerValue<'ink> {
fn from(value: RuntimeArrayValue<'ink>) -> Self {
value.0.into()
}
}