use alloc::sync::Arc;
use core::marker::PhantomData;
use core::ops::ControlFlow;
pub struct SplitDwarfLoad<R> {
pub dwo_id: gimli::DwoId,
pub comp_dir: Option<R>,
pub path: Option<R>,
pub parent: Arc<gimli::Dwarf<R>>,
}
pub enum LookupResult<L: LookupContinuation> {
Load {
load: SplitDwarfLoad<<L as LookupContinuation>::Buf>,
continuation: L,
},
Output(<L as LookupContinuation>::Output),
}
pub trait LookupContinuation: Sized {
type Output;
type Buf: gimli::Reader;
fn resume(self, input: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self>;
}
impl<L: LookupContinuation> LookupResult<L> {
pub fn skip_all_loads(mut self) -> L::Output {
loop {
self = match self {
LookupResult::Output(t) => return t,
LookupResult::Load { continuation, .. } => continuation.resume(None),
};
}
}
pub(crate) fn map<T, F: FnOnce(L::Output) -> T>(
self,
f: F,
) -> LookupResult<MappedLookup<T, L, F>> {
match self {
LookupResult::Output(t) => LookupResult::Output(f(t)),
LookupResult::Load { load, continuation } => LookupResult::Load {
load,
continuation: MappedLookup {
original: continuation,
mutator: f,
},
},
}
}
pub(crate) fn unwrap(self) -> L::Output {
match self {
LookupResult::Output(t) => t,
LookupResult::Load { .. } => unreachable!("Internal API misuse"),
}
}
}
pub(crate) struct SimpleLookup<T, R, F>
where
F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
R: gimli::Reader,
{
f: F,
phantom: PhantomData<(T, R)>,
}
impl<T, R, F> SimpleLookup<T, R, F>
where
F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
R: gimli::Reader,
{
pub(crate) fn new_complete(t: F::Output) -> LookupResult<SimpleLookup<T, R, F>> {
LookupResult::Output(t)
}
pub(crate) fn new_needs_load(
load: SplitDwarfLoad<R>,
f: F,
) -> LookupResult<SimpleLookup<T, R, F>> {
LookupResult::Load {
load,
continuation: SimpleLookup {
f,
phantom: PhantomData,
},
}
}
}
impl<T, R, F> LookupContinuation for SimpleLookup<T, R, F>
where
F: FnOnce(Option<Arc<gimli::Dwarf<R>>>) -> T,
R: gimli::Reader,
{
type Output = T;
type Buf = R;
fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
LookupResult::Output((self.f)(v))
}
}
pub(crate) struct MappedLookup<T, L, F>
where
L: LookupContinuation,
F: FnOnce(L::Output) -> T,
{
original: L,
mutator: F,
}
impl<T, L, F> LookupContinuation for MappedLookup<T, L, F>
where
L: LookupContinuation,
F: FnOnce(L::Output) -> T,
{
type Output = T;
type Buf = L::Buf;
fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
match self.original.resume(v) {
LookupResult::Output(t) => LookupResult::Output((self.mutator)(t)),
LookupResult::Load { load, continuation } => LookupResult::Load {
load,
continuation: MappedLookup {
original: continuation,
mutator: self.mutator,
},
},
}
}
}
pub(crate) struct LoopingLookup<T, L, F>
where
L: LookupContinuation,
F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
{
continuation: L,
mutator: F,
}
impl<T, L, F> LoopingLookup<T, L, F>
where
L: LookupContinuation,
F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
{
pub(crate) fn new_complete(t: T) -> LookupResult<Self> {
LookupResult::Output(t)
}
pub(crate) fn new_lookup(mut r: LookupResult<L>, mut mutator: F) -> LookupResult<Self> {
loop {
match r {
LookupResult::Output(l) => match mutator(l) {
ControlFlow::Break(t) => return LookupResult::Output(t),
ControlFlow::Continue(r2) => {
r = r2;
}
},
LookupResult::Load { load, continuation } => {
return LookupResult::Load {
load,
continuation: LoopingLookup {
continuation,
mutator,
},
};
}
}
}
}
}
impl<T, L, F> LookupContinuation for LoopingLookup<T, L, F>
where
L: LookupContinuation,
F: FnMut(L::Output) -> ControlFlow<T, LookupResult<L>>,
{
type Output = T;
type Buf = L::Buf;
fn resume(self, v: Option<Arc<gimli::Dwarf<Self::Buf>>>) -> LookupResult<Self> {
let r = self.continuation.resume(v);
LoopingLookup::new_lookup(r, self.mutator)
}
}