rsip_dns/resolvables/
mod.rs

1//! This module contains all the resolvable types that are necessary to implement the
2//! lazyness async nature of resolving the next (ip, port, transport) tuple of the
3//! [Lookup](super::Lookup).
4//!
5//! Probably shouldn't be used as is, instead look at the [Lookup](super::Lookup).
6//!
7
8mod resolvable;
9mod resolvable_addr_record;
10mod resolvable_enum;
11mod resolvable_ip_addr;
12mod resolvable_naptr_record;
13mod resolvable_srv_record;
14mod resolvable_vec;
15
16pub use resolvable::Resolvable;
17pub use resolvable_addr_record::ResolvableAddrRecord;
18pub use resolvable_enum::ResolvableEnum;
19pub use resolvable_ip_addr::ResolvableIpAddr;
20pub use resolvable_naptr_record::ResolvableNaptrRecord;
21pub use resolvable_srv_record::ResolvableSrvRecord;
22pub use resolvable_vec::ResolvableVec;
23
24use async_trait::async_trait;
25use std::collections::VecDeque;
26
27/// ResolvableState communicates whether a type that implements `ResolvableExt` entry has not been
28/// touched/opened yet ([ResolvableState::Unset]), it has been "opened" and has still
29/// remaining stuff in it ([ResolvableState::NonEmpty]) or it has been "opened" and possibly
30/// used but in any case it's empty ([ResolvableState::Empty]).
31#[derive(Debug, Clone)]
32pub enum ResolvableState {
33    Unset,
34    Empty,
35    NonEmpty,
36}
37
38/// Simple trait that sets the bounds of the item that can be returned by the
39/// [ResolvableExt::resolve_next] method. Usually the [Target](super::Target) is used here.
40pub trait ResolvableItem: Sized + Clone + std::marker::Send {}
41impl<T: Sized + Clone + std::marker::Send> ResolvableItem for T {}
42
43/// ResolvableExt is a trait that specifies which methods a resolvable type should implement.
44/// The main things are the [ResolvableExt::state] which specifies the state (and based on that
45/// [Lookup](super::Lookup) and other types take decisions) and [ResolvableExt::resolve_next] which is
46/// an async method that returns the next element (which implements the [ResolvableItem]) of
47/// the resolvable type or none if there is nothing.
48///
49/// Note that almost all resolvable types that can host other resolvable types internally and the
50/// whole thing becomes a nested tree kinda. But it's an important structure to resemble the
51/// lazyness async nature of resolving the next (ip, port, transport) tuple of the DNS results.
52#[async_trait]
53pub trait ResolvableExt<I>
54where
55    I: ResolvableItem,
56{
57    /// Returns the state of the resolvable type
58    fn state(&self) -> ResolvableState;
59
60    /// This method returns the next item from the resolvable type
61    /// Note that a resolvable type might host other resolvable types internally, and in any case
62    /// one or more DNS queries might be needed to get the next item.
63    /// If no item is found, None is returned.
64    ///
65    /// `[async_trait]` makes this method look a bit more complex that what it actually is,
66    /// (it's just an `async fn resolve_next(&mut self) -> Option<I>`).
67    async fn resolve_next(&mut self) -> Option<I>;
68
69    fn is_empty(&self) -> bool {
70        matches!(self.state(), ResolvableState::Empty)
71    }
72
73    fn is_unset(&self) -> bool {
74        matches!(self.state(), ResolvableState::Unset)
75    }
76
77    fn is_empty_or_unset(&self) -> bool {
78        self.is_empty() || self.is_unset()
79    }
80}
81
82#[async_trait]
83impl<T, I> ResolvableExt<I> for Option<T>
84where
85    T: ResolvableExt<I> + std::marker::Send,
86    I: ResolvableItem,
87{
88    fn state(&self) -> ResolvableState {
89        match self {
90            None => ResolvableState::Unset,
91            Some(inner) => inner.state(),
92        }
93    }
94
95    async fn resolve_next(&mut self) -> Option<I> {
96        match self {
97            Some(inner) => inner.resolve_next().await,
98            None => None,
99        }
100    }
101}
102
103#[async_trait]
104impl<I, T> ResolvableExt<T> for VecDeque<I>
105where
106    I: ResolvableExt<T> + std::marker::Send,
107    T: ResolvableItem,
108{
109    fn state(&self) -> ResolvableState {
110        match self.front() {
111            None => ResolvableState::Empty,
112            Some(inner) => inner.state(),
113        }
114    }
115
116    async fn resolve_next(&mut self) -> Option<T> {
117        match self.front_mut() {
118            Some(inner) => match inner.resolve_next().await {
119                Some(next) => Some(next),
120                None => {
121                    self.pop_front();
122                    self.resolve_next().await
123                }
124            },
125            None => None,
126        }
127    }
128}