use std::{
hash::{BuildHasher, Hash, Hasher},
num::NonZeroU64,
sync::{
Arc, LazyLock,
atomic::{AtomicU64, Ordering},
},
};
use http::{Uri, Version};
use lru::DefaultHasher;
use crate::{conn::net::SocketBindOptions, group::Group, proxy::Matcher, tls::TlsOptions};
#[derive(Debug, Clone)]
pub(crate) struct ConnectionId(Arc<(Group, AtomicU64)>);
#[must_use]
#[derive(Clone)]
pub(crate) struct ConnectionDescriptor {
uri: Uri,
version: Option<Version>,
proxy: Option<Matcher>,
tls_options: Option<TlsOptions>,
socket_bind: Option<SocketBindOptions>,
connection_id: ConnectionId,
}
impl Hash for ConnectionId {
fn hash<H: Hasher>(&self, state: &mut H) {
let hash = self.0.1.load(Ordering::Relaxed);
if hash != 0 {
state.write_u64(hash);
return;
}
static HASHER: LazyLock<DefaultHasher> = LazyLock::new(DefaultHasher::default);
let computed_hash = NonZeroU64::new(HASHER.hash_one(&self.0.0))
.map(NonZeroU64::get)
.unwrap_or(1);
let _ = self.0.1.compare_exchange(
u64::MIN,
computed_hash,
Ordering::Relaxed,
Ordering::Relaxed,
);
state.write_u64(computed_hash);
}
}
impl PartialEq for ConnectionId {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0.0.eq(&other.0.0)
}
}
impl Eq for ConnectionId {}
impl ConnectionDescriptor {
pub(crate) fn new(
uri: Uri,
mut group: Group,
proxy: Option<Matcher>,
version: Option<Version>,
tls_options: Option<TlsOptions>,
socket_bind: Option<SocketBindOptions>,
) -> ConnectionDescriptor {
let connection_id = {
group
.uri(uri.clone())
.version(version)
.proxy(proxy.clone())
.socket_bind(socket_bind.clone());
ConnectionId(Arc::new((group, AtomicU64::new(u64::MIN))))
};
ConnectionDescriptor {
uri,
proxy,
version,
tls_options,
socket_bind,
connection_id,
}
}
#[inline]
pub(crate) fn id(&self) -> ConnectionId {
self.connection_id.clone()
}
#[inline]
pub(crate) fn uri(&self) -> &Uri {
&self.uri
}
#[inline]
pub(crate) fn uri_mut(&mut self) -> &mut Uri {
&mut self.uri
}
pub(crate) fn version(&self) -> Option<Version> {
self.version
}
#[inline]
pub(crate) fn tls_options(&self) -> Option<&TlsOptions> {
self.tls_options.as_ref()
}
#[inline]
pub(crate) fn proxy(&self) -> Option<&Matcher> {
self.proxy.as_ref()
}
#[inline]
pub(crate) fn socket_bind_options(&self) -> Option<&SocketBindOptions> {
self.socket_bind.as_ref()
}
}