use core::cell::Cell;
use std::rc::Rc;
use mdns_proto::{CollectedAnswer, QueryHandle, QueryUpdate};
use crate::driver::EndpointInner;
#[derive(Debug, Clone)]
pub enum QueryEvent {
Answer(CollectedAnswer),
Terminal(QueryUpdate),
}
pub struct Query {
pub(crate) inner: Rc<EndpointInner>,
pub(crate) handle: QueryHandle,
pub(crate) terminal_delivered: Cell<bool>,
}
impl Query {
#[inline]
pub const fn handle(&self) -> QueryHandle {
self.handle
}
pub async fn next(&self) -> Option<QueryEvent> {
loop {
if self.terminal_delivered.get() {
return None;
}
{
let mut st = self.inner.state.borrow_mut();
let ctx = st.queries.get(&self.handle)?;
let last = ctx.last_seq;
let cancelled = ctx.cancelled;
let errored = ctx.errored;
let next_answer = next_answer_by_seq(st.endpoint.collected_answers(self.handle), last);
if let Some(a) = next_answer {
let new_last = a.seq().saturating_add(1);
if let Some(ctx) = st.queries.get_mut(&self.handle) {
ctx.last_seq = new_last;
}
return Some(QueryEvent::Answer(a));
}
if let Some(t) = st.endpoint.poll_query(self.handle) {
self.terminal_delivered.set(true);
st.queries.remove(&self.handle);
let _ = st.endpoint.cancel_query(self.handle);
return Some(QueryEvent::Terminal(t));
}
if cancelled || errored {
self.terminal_delivered.set(true);
st.queries.remove(&self.handle);
let _ = st.endpoint.cancel_query(self.handle);
return None;
}
}
self.inner.notify.listen().await;
}
}
}
#[allow(single_use_lifetimes)]
fn next_answer_by_seq<'a>(
answers: impl Iterator<Item = &'a CollectedAnswer>,
last: u64,
) -> Option<CollectedAnswer> {
answers
.filter(|a| a.seq() >= last)
.min_by_key(|a| a.seq())
.cloned()
}
impl Drop for Query {
fn drop(&mut self) {
{
let mut st = self.inner.state.borrow_mut();
st.flag_query_cancelled(self.handle);
let _ = st.endpoint.cancel_query(self.handle);
st.queries.remove(&self.handle);
}
self.inner.mark_dirty();
}
}
#[cfg(test)]
mod tests;