use super::{
AsValue, ConcreteValueType, IrTypeContext, IrValueContext, SizedValueType, Value, ValueType,
};
use crate::value::{
AddressableType, AddressableTypeValue, AsBytesAndPtrs, AsValueInto, BytesOrPtr, HasConstValue,
};
use inkwell::{
module::Linkage,
values::{BasicValueEnum, UnnamedAddress},
AddressSpace,
};
use std::marker::PhantomData;
pub struct Global<'ink, T: ?Sized> {
pub value: inkwell::values::GlobalValue<'ink>,
data: PhantomData<T>,
}
impl<'ink, T: ?Sized> Clone for Global<'ink, T> {
fn clone(&self) -> Self {
Global {
value: self.value,
data: self.data,
}
}
}
impl<'ink, T: ?Sized> Copy for Global<'ink, T> {}
impl<'ink, T: ?Sized> Global<'ink, T> {
pub unsafe fn from_raw(value: inkwell::values::GlobalValue<'ink>) -> Self {
Global {
value,
data: Default::default(),
}
}
}
impl<'ink, T: ?Sized, I> AsValue<'ink, *const I> for Global<'ink, T>
where
*const I: ConcreteValueType<'ink, Value = inkwell::values::PointerValue<'ink>>,
T: AddressableType<'ink, I>,
{
fn as_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, *const I> {
Value::from_raw(T::ptr_cast(self.value.as_pointer_value(), context))
}
}
impl<'ink, T: ConcreteValueType<'ink> + ?Sized> Value<'ink, T>
where
T::Value: Into<BasicValueEnum<'ink>>,
{
pub fn into_global<S: AsRef<str>>(
self,
name: S,
context: &IrValueContext<'ink, '_, '_>,
is_const: bool,
linkage: Linkage,
unnamed_addr: Option<UnnamedAddress>,
) -> Global<'ink, T> {
let address_space = None;
let initializer = self.value.into();
let global =
context
.module
.add_global(initializer.get_type(), address_space, name.as_ref());
global.set_linkage(linkage);
global.set_constant(is_const);
global.set_initializer(&initializer);
if let Some(addr) = unnamed_addr {
global.set_unnamed_address(addr);
}
Global {
value: global,
data: Default::default(),
}
}
pub fn into_const_private_global<S: AsRef<str>>(
self,
name: S,
context: &IrValueContext<'ink, '_, '_>,
) -> Global<'ink, T> {
self.into_global(
name,
context,
true,
Linkage::Private,
Some(UnnamedAddress::Global),
)
}
}
impl<'ink, T: ?Sized> From<Global<'ink, T>> for inkwell::values::PointerValue<'ink> {
fn from(global: Global<'ink, T>) -> Self {
global.value.as_pointer_value()
}
}
impl<'ink, T> ConcreteValueType<'ink> for Global<'ink, T> {
type Value = inkwell::values::PointerValue<'ink>;
}
impl<'ink, T: SizedValueType<'ink>> SizedValueType<'ink> for Global<'ink, T>
where
<<T as ConcreteValueType<'ink>>::Value as ValueType<'ink>>::Type: AddressableTypeValue<'ink>,
{
fn get_ir_type(
context: &IrTypeContext<'ink, '_>,
) -> <<Self as ConcreteValueType<'ink>>::Value as ValueType<'ink>>::Type {
<T as SizedValueType>::get_ir_type(context).ptr_type(AddressSpace::Generic)
}
}
impl<'ink, T> HasConstValue for Global<'ink, T> {
fn has_const_value() -> bool {
false
}
}
impl<'ink, T> AsBytesAndPtrs<'ink> for Global<'ink, T> {
fn as_bytes_and_ptrs(&self, _context: &IrTypeContext<'ink, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![BytesOrPtr::UntypedPtr(self.value.as_pointer_value())]
}
}
impl<'ink, T> AsValueInto<'ink, BasicValueEnum<'ink>> for Global<'ink, T> {
fn as_value_into(
&self,
_context: &IrValueContext<'ink, '_, '_>,
) -> inkwell::values::BasicValueEnum<'ink> {
self.value.as_pointer_value().into()
}
}
impl<'ink, T> AsValueInto<'ink, inkwell::values::PointerValue<'ink>> for Global<'ink, T> {
fn as_value_into(
&self,
_context: &IrValueContext<'ink, '_, '_>,
) -> inkwell::values::PointerValue<'ink> {
self.value.as_pointer_value()
}
}