use std::marker::PhantomData;
use llvm_sys::{
core::{
LLVMGetFirstBasicBlock, LLVMGetFirstFunction, LLVMGetFirstGlobal, LLVMGetFirstGlobalAlias,
LLVMGetFirstInstruction, LLVMGetLastBasicBlock, LLVMGetLastFunction, LLVMGetLastGlobal,
LLVMGetLastGlobalAlias, LLVMGetLastInstruction, LLVMGetNextBasicBlock, LLVMGetNextFunction,
LLVMGetNextGlobal, LLVMGetNextGlobalAlias, LLVMGetNextInstruction,
},
prelude::{LLVMBasicBlockRef, LLVMModuleRef, LLVMValueRef},
};
macro_rules! llvm_iterator {
($trait_name:ident, $iterator_name:ident, $iterable:ty, $method_name:ident, $item_ty:ty, $first:expr, $last:expr, $next:expr $(,)?) => {
pub(crate) trait $trait_name {
fn $method_name(&self) -> $iterator_name<'_>;
}
pub(crate) struct $iterator_name<'a> {
lifetime: PhantomData<&'a $iterable>,
next: $item_ty,
last: $item_ty,
}
impl $trait_name for $iterable {
fn $method_name(&self) -> $iterator_name<'_> {
let first = unsafe { $first(*self) };
let last = unsafe { $last(*self) };
assert_eq!(first.is_null(), last.is_null());
$iterator_name {
lifetime: PhantomData,
next: first,
last,
}
}
}
impl Iterator for $iterator_name<'_> {
type Item = $item_ty;
fn next(&mut self) -> Option<Self::Item> {
let Self {
lifetime: _,
next,
last,
} = self;
if next.is_null() {
return None;
}
let last = *next == *last;
let item = *next;
*next = unsafe { $next(*next) };
assert_eq!(next.is_null(), last);
Some(item)
}
}
};
}
llvm_iterator! {
IterModuleGlobals,
GlobalsIter,
LLVMModuleRef,
globals_iter,
LLVMValueRef,
LLVMGetFirstGlobal,
LLVMGetLastGlobal,
LLVMGetNextGlobal,
}
llvm_iterator! {
IterModuleGlobalAliases,
GlobalAliasesIter,
LLVMModuleRef,
global_aliases_iter,
LLVMValueRef,
LLVMGetFirstGlobalAlias,
LLVMGetLastGlobalAlias,
LLVMGetNextGlobalAlias,
}
llvm_iterator! {
IterModuleFunctions,
FunctionsIter,
LLVMModuleRef,
functions_iter,
LLVMValueRef,
LLVMGetFirstFunction,
LLVMGetLastFunction,
LLVMGetNextFunction,
}
llvm_iterator!(
IterBasicBlocks,
BasicBlockIter,
LLVMValueRef,
basic_blocks_iter,
LLVMBasicBlockRef,
LLVMGetFirstBasicBlock,
LLVMGetLastBasicBlock,
LLVMGetNextBasicBlock
);
llvm_iterator!(
IterInstructions,
InstructionsIter,
LLVMBasicBlockRef,
instructions_iter,
LLVMValueRef,
LLVMGetFirstInstruction,
LLVMGetLastInstruction,
LLVMGetNextInstruction
);