1use crate::{Runtime, RuntimeTrait, Transport, UdpTransport, Url};
2use smallvec::SmallVec;
3use std::{
4 any::Any,
5 borrow::Cow,
6 fmt::{self, Debug, Formatter},
7 future::Future,
8 io,
9 net::SocketAddr,
10 pin::Pin,
11 sync::Arc,
12};
13
14#[derive(Debug, Clone)]
23pub struct Destination {
24 secure: bool,
25 host: Option<String>,
26 port: u16,
27 addrs: SmallVec<[SocketAddr; 4]>,
28 alpn: Option<SmallVec<[Cow<'static, [u8]>; 4]>>,
31}
32
33impl Destination {
34 pub fn new_with_host(secure: bool, host: impl Into<String>, port: u16) -> Self {
40 Self {
41 secure,
42 host: Some(host.into()),
43 port,
44 addrs: SmallVec::new(),
45 alpn: None,
46 }
47 }
48
49 pub fn new_with_socket_addrs(
53 secure: bool,
54 addrs: impl IntoIterator<Item = SocketAddr>,
55 ) -> Self {
56 let addrs = addrs.into_iter().collect::<SmallVec<[SocketAddr; 4]>>();
57 let port = addrs.first().map_or(0, SocketAddr::port);
58 Self {
59 secure,
60 host: None,
61 port,
62 addrs,
63 alpn: None,
64 }
65 }
66
67 pub fn from_url(url: &Url) -> io::Result<Self> {
78 let secure = match url.scheme() {
79 "http" => false,
80 "https" => true,
81 other => {
82 return Err(io::Error::new(
83 io::ErrorKind::InvalidInput,
84 format!("unknown scheme {other}"),
85 ));
86 }
87 };
88 let port = url.port_or_known_default().ok_or_else(|| {
89 io::Error::new(io::ErrorKind::InvalidInput, format!("{url} missing port"))
90 })?;
91 match url.host() {
92 Some(url::Host::Domain(domain)) => Ok(Self::new_with_host(secure, domain, port)),
93 Some(url::Host::Ipv4(ip)) => Ok(Self::new_with_socket_addrs(
94 secure,
95 [SocketAddr::from((ip, port))],
96 )),
97 Some(url::Host::Ipv6(ip)) => Ok(Self::new_with_socket_addrs(
98 secure,
99 [SocketAddr::from((ip, port))],
100 )),
101 None => Err(io::Error::new(
102 io::ErrorKind::InvalidInput,
103 format!("{url} missing host"),
104 )),
105 }
106 }
107
108 pub fn to_url(&self) -> io::Result<Url> {
117 let scheme = if self.secure { "https" } else { "http" };
118 let authority = match &self.host {
119 Some(host) => format!("{host}:{}", self.port),
120 None => self
121 .addrs
122 .first()
123 .ok_or_else(|| {
124 io::Error::new(
125 io::ErrorKind::InvalidInput,
126 "destination has neither host nor addresses",
127 )
128 })?
129 .to_string(),
130 };
131 Url::parse(&format!("{scheme}://{authority}"))
132 .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
133 }
134
135 #[must_use]
137 pub fn secure(&self) -> bool {
138 self.secure
139 }
140
141 #[must_use]
144 pub fn host(&self) -> Option<&str> {
145 self.host.as_deref()
146 }
147
148 #[must_use]
151 pub fn port(&self) -> u16 {
152 self.port
153 }
154
155 #[must_use]
157 pub fn addrs(&self) -> &[SocketAddr] {
158 &self.addrs
159 }
160
161 #[must_use]
165 pub fn alpn(&self) -> Option<&[Cow<'static, [u8]>]> {
166 self.alpn.as_deref()
167 }
168
169 #[must_use]
171 pub fn with_addrs(mut self, addrs: impl IntoIterator<Item = SocketAddr>) -> Self {
172 self.set_addrs(addrs);
173 self
174 }
175
176 pub fn set_addrs(&mut self, addrs: impl IntoIterator<Item = SocketAddr>) -> &mut Self {
178 self.addrs = addrs.into_iter().collect();
179 self
180 }
181
182 #[must_use]
186 pub fn with_alpn(mut self, alpn: impl IntoIterator<Item = Cow<'static, [u8]>>) -> Self {
187 self.set_alpn(alpn);
188 self
189 }
190
191 pub fn set_alpn(&mut self, alpn: impl IntoIterator<Item = Cow<'static, [u8]>>) -> &mut Self {
195 self.alpn = Some(alpn.into_iter().collect());
196 self
197 }
198
199 #[must_use]
202 pub fn without_alpn(mut self) -> Self {
203 self.clear_alpn();
204 self
205 }
206
207 pub fn clear_alpn(&mut self) -> &mut Self {
210 self.alpn = None;
211 self
212 }
213
214 #[must_use]
216 pub fn with_secure(mut self, secure: bool) -> Self {
217 self.secure = secure;
218 self
219 }
220}
221
222pub trait Connector: Send + Sync + 'static {
228 type Transport: Transport;
230
231 type Runtime: RuntimeTrait;
233
234 type Udp: UdpTransport;
238
239 fn connect(&self, url: &Url) -> impl Future<Output = io::Result<Self::Transport>> + Send;
241
242 fn connect_to(
257 &self,
258 destination: Destination,
259 ) -> impl Future<Output = io::Result<Self::Transport>> + Send {
260 async move { self.connect(&destination.to_url()?).await }
261 }
262
263 fn arced(self) -> ArcedConnector
265 where
266 Self: Sized,
267 {
268 ArcedConnector(Arc::new(self))
269 }
270
271 fn resolve(
273 &self,
274 host: &str,
275 port: u16,
276 ) -> impl Future<Output = io::Result<Vec<SocketAddr>>> + Send;
277
278 fn runtime(&self) -> Self::Runtime;
280}
281
282#[derive(Clone)]
284pub struct ArcedConnector(Arc<dyn ObjectSafeConnector>);
285
286impl Debug for ArcedConnector {
287 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
288 f.debug_tuple("ArcedConnector").finish()
289 }
290}
291
292impl ArcedConnector {
293 #[must_use]
295 pub fn new(connector: impl Connector) -> Self {
296 connector.arced()
297 }
298
299 pub fn is<T: Any + 'static>(&self) -> bool {
301 self.as_any().is::<T>()
302 }
303
304 pub fn downcast_ref<T: Any + 'static>(&self) -> Option<&T> {
307 self.0.as_any().downcast_ref()
308 }
309
310 pub fn downcast_mut<T: Any + 'static>(&mut self) -> Option<&mut T> {
313 Arc::get_mut(&mut self.0)?.as_mut_any().downcast_mut()
314 }
315
316 pub fn runtime(&self) -> Runtime {
318 self.0.runtime()
319 }
320}
321
322type ConnectResult<'fut> =
324 Pin<Box<dyn Future<Output = io::Result<Box<dyn Transport>>> + Send + 'fut>>;
325
326trait ObjectSafeConnector: Send + Sync + 'static {
327 #[must_use]
328 fn connect<'connector, 'url, 'fut>(&'connector self, url: &'url Url) -> ConnectResult<'fut>
329 where
330 'connector: 'fut,
331 'url: 'fut,
332 Self: 'fut;
333 fn as_any(&self) -> &dyn Any;
334 fn as_mut_any(&mut self) -> &mut dyn Any;
335 fn runtime(&self) -> Runtime;
336
337 fn resolve<'connector, 'host, 'fut>(
338 &'connector self,
339 host: &'host str,
340 port: u16,
341 ) -> Pin<Box<dyn Future<Output = io::Result<Vec<SocketAddr>>> + Send + 'fut>>
342 where
343 'connector: 'fut,
344 'host: 'fut,
345 Self: 'fut;
346
347 #[must_use]
348 fn connect_to<'connector, 'fut>(
349 &'connector self,
350 destination: Destination,
351 ) -> ConnectResult<'fut>
352 where
353 'connector: 'fut,
354 Self: 'fut;
355}
356
357impl<T: Connector> ObjectSafeConnector for T {
358 fn connect<'connector, 'url, 'fut>(
359 &'connector self,
360 url: &'url Url,
361 ) -> Pin<Box<dyn Future<Output = io::Result<Box<dyn Transport>>> + Send + 'fut>>
362 where
363 'connector: 'fut,
364 'url: 'fut,
365 Self: 'fut,
366 {
367 Box::pin(async move {
368 Connector::connect(self, url)
369 .await
370 .map(|t| Box::new(t) as Box<dyn Transport>)
371 })
372 }
373
374 fn as_any(&self) -> &dyn Any {
375 self
376 }
377
378 fn as_mut_any(&mut self) -> &mut dyn Any {
379 self
380 }
381
382 fn runtime(&self) -> Runtime {
383 Connector::runtime(self).into()
384 }
385
386 fn resolve<'connector, 'host, 'fut>(
387 &'connector self,
388 host: &'host str,
389 port: u16,
390 ) -> Pin<Box<dyn Future<Output = io::Result<Vec<SocketAddr>>> + Send + 'fut>>
391 where
392 'connector: 'fut,
393 'host: 'fut,
394 Self: 'fut,
395 {
396 Box::pin(async move { Connector::resolve(self, host, port).await })
397 }
398
399 fn connect_to<'connector, 'fut>(
400 &'connector self,
401 destination: Destination,
402 ) -> ConnectResult<'fut>
403 where
404 'connector: 'fut,
405 Self: 'fut,
406 {
407 Box::pin(async move {
408 Connector::connect_to(self, destination)
409 .await
410 .map(|t| Box::new(t) as Box<dyn Transport>)
411 })
412 }
413}
414
415impl Connector for ArcedConnector {
416 type Runtime = Runtime;
417 type Transport = Box<dyn Transport>;
418 type Udp = ();
419
420 async fn connect(&self, url: &Url) -> io::Result<Box<dyn Transport>> {
421 self.0.connect(url).await
422 }
423
424 fn arced(self) -> ArcedConnector {
425 self
426 }
427
428 fn runtime(&self) -> Self::Runtime {
429 self.0.runtime()
430 }
431
432 async fn resolve(&self, host: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
433 self.0.resolve(host, port).await
434 }
435
436 async fn connect_to(&self, destination: Destination) -> io::Result<Box<dyn Transport>> {
437 self.0.connect_to(destination).await
438 }
439}
440
441pub trait QuicClientConfig<C: Connector>: Send + Sync + 'static {
450 type Endpoint: crate::QuicEndpoint;
452
453 fn bind(&self, addr: SocketAddr, runtime: &C::Runtime) -> io::Result<Self::Endpoint>;
458}
459
460trait ObjectSafeQuicClientConfig: Send + Sync + 'static {
463 fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint>;
464}
465
466struct BoundQuicClientConfig<Q, C: Connector> {
468 config: Q,
469 runtime: C::Runtime,
470}
471
472impl<C: Connector, Q: QuicClientConfig<C>> ObjectSafeQuicClientConfig
473 for BoundQuicClientConfig<Q, C>
474{
475 fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint> {
476 let endpoint = self.config.bind(addr, &self.runtime)?;
477 Ok(crate::ArcedQuicEndpoint::from(endpoint))
478 }
479}
480
481#[derive(Clone)]
486pub struct ArcedQuicClientConfig(Arc<dyn ObjectSafeQuicClientConfig>);
487
488impl Debug for ArcedQuicClientConfig {
489 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
490 f.debug_tuple("ArcedQuicClientConfig").finish()
491 }
492}
493
494impl ArcedQuicClientConfig {
495 #[must_use]
497 pub fn new<C: Connector, Q: QuicClientConfig<C>>(connector: &C, config: Q) -> Self {
498 Self(Arc::new(BoundQuicClientConfig {
499 runtime: connector.runtime(),
500 config,
501 }))
502 }
503
504 pub fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint> {
506 self.0.bind(addr)
507 }
508}