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 fn connect<'connector, 'url, 'fut>(&'connector self, url: &'url Url) -> ConnectResult<'fut>
328 where
329 'connector: 'fut,
330 'url: 'fut,
331 Self: 'fut;
332 fn as_any(&self) -> &dyn Any;
333 fn as_mut_any(&mut self) -> &mut dyn Any;
334 fn runtime(&self) -> Runtime;
335
336 fn resolve<'connector, 'host, 'fut>(
337 &'connector self,
338 host: &'host str,
339 port: u16,
340 ) -> Pin<Box<dyn Future<Output = io::Result<Vec<SocketAddr>>> + Send + 'fut>>
341 where
342 'connector: 'fut,
343 'host: 'fut,
344 Self: 'fut;
345
346 fn connect_to<'connector, 'fut>(
347 &'connector self,
348 destination: Destination,
349 ) -> ConnectResult<'fut>
350 where
351 'connector: 'fut,
352 Self: 'fut;
353}
354
355impl<T: Connector> ObjectSafeConnector for T {
356 fn connect<'connector, 'url, 'fut>(
357 &'connector self,
358 url: &'url Url,
359 ) -> Pin<Box<dyn Future<Output = io::Result<Box<dyn Transport>>> + Send + 'fut>>
360 where
361 'connector: 'fut,
362 'url: 'fut,
363 Self: 'fut,
364 {
365 Box::pin(async move {
366 Connector::connect(self, url)
367 .await
368 .map(|t| Box::new(t) as Box<dyn Transport>)
369 })
370 }
371
372 fn as_any(&self) -> &dyn Any {
373 self
374 }
375
376 fn as_mut_any(&mut self) -> &mut dyn Any {
377 self
378 }
379
380 fn runtime(&self) -> Runtime {
381 Connector::runtime(self).into()
382 }
383
384 fn resolve<'connector, 'host, 'fut>(
385 &'connector self,
386 host: &'host str,
387 port: u16,
388 ) -> Pin<Box<dyn Future<Output = io::Result<Vec<SocketAddr>>> + Send + 'fut>>
389 where
390 'connector: 'fut,
391 'host: 'fut,
392 Self: 'fut,
393 {
394 Box::pin(async move { Connector::resolve(self, host, port).await })
395 }
396
397 fn connect_to<'connector, 'fut>(
398 &'connector self,
399 destination: Destination,
400 ) -> ConnectResult<'fut>
401 where
402 'connector: 'fut,
403 Self: 'fut,
404 {
405 Box::pin(async move {
406 Connector::connect_to(self, destination)
407 .await
408 .map(|t| Box::new(t) as Box<dyn Transport>)
409 })
410 }
411}
412
413impl Connector for ArcedConnector {
414 type Runtime = Runtime;
415 type Transport = Box<dyn Transport>;
416 type Udp = ();
417
418 async fn connect(&self, url: &Url) -> io::Result<Box<dyn Transport>> {
419 self.0.connect(url).await
420 }
421
422 fn arced(self) -> ArcedConnector {
423 self
424 }
425
426 fn runtime(&self) -> Self::Runtime {
427 self.0.runtime()
428 }
429
430 async fn resolve(&self, host: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
431 self.0.resolve(host, port).await
432 }
433
434 async fn connect_to(&self, destination: Destination) -> io::Result<Box<dyn Transport>> {
435 self.0.connect_to(destination).await
436 }
437}
438
439pub trait QuicClientConfig<C: Connector>: Send + Sync + 'static {
448 type Endpoint: crate::QuicEndpoint;
450
451 fn bind(&self, addr: SocketAddr, runtime: &C::Runtime) -> io::Result<Self::Endpoint>;
456}
457
458trait ObjectSafeQuicClientConfig: Send + Sync + 'static {
461 fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint>;
462}
463
464struct BoundQuicClientConfig<Q, C: Connector> {
466 config: Q,
467 runtime: C::Runtime,
468}
469
470impl<C: Connector, Q: QuicClientConfig<C>> ObjectSafeQuicClientConfig
471 for BoundQuicClientConfig<Q, C>
472{
473 fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint> {
474 let endpoint = self.config.bind(addr, &self.runtime)?;
475 Ok(crate::ArcedQuicEndpoint::from(endpoint))
476 }
477}
478
479#[derive(Clone)]
484pub struct ArcedQuicClientConfig(Arc<dyn ObjectSafeQuicClientConfig>);
485
486impl Debug for ArcedQuicClientConfig {
487 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
488 f.debug_tuple("ArcedQuicClientConfig").finish()
489 }
490}
491
492impl ArcedQuicClientConfig {
493 #[must_use]
495 pub fn new<C: Connector, Q: QuicClientConfig<C>>(connector: &C, config: Q) -> Self {
496 Self(Arc::new(BoundQuicClientConfig {
497 runtime: connector.runtime(),
498 config,
499 }))
500 }
501
502 pub fn bind(&self, addr: SocketAddr) -> io::Result<crate::ArcedQuicEndpoint> {
504 self.0.bind(addr)
505 }
506}