use super::{
AsValue, ConcreteValueType, IrTypeContext, IrValueContext, PointerValueType, SizedValueType,
Value, ValueType,
};
use crate::value::AddressableType;
use inkwell::{
module::Linkage,
types::PointerType,
values::{BasicValueEnum, PointerValue, 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> ConcreteValueType<'ink> for *const Global<'ink, T> {
type Value = inkwell::values::PointerValue<'ink>;
}
impl<'ink, T: PointerValueType<'ink> + ?Sized> SizedValueType<'ink> for *const Global<'ink, T> {
fn get_ir_type(context: &IrTypeContext<'ink, '_>) -> <Self::Value as ValueType<'ink>>::Type {
T::get_ptr_type(context, None)
}
}
impl<'ink, T: PointerValueType<'ink> + ?Sized> PointerValueType<'ink> for *const Global<'ink, T> {
fn get_ptr_type(
context: &IrTypeContext<'ink, '_>,
address_space: Option<AddressSpace>,
) -> PointerType<'ink> {
debug_assert!(
address_space.is_none() || address_space == Some(AddressSpace::Generic),
"Globals can only live in generic address space"
);
T::get_ptr_type(context, None)
}
}
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> Into<inkwell::values::PointerValue<'ink>> for Global<'ink, T> {
fn into(self) -> PointerValue<'ink> {
self.value.as_pointer_value()
}
}