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}