use std::sync::OnceLock;
use std::{ops::Deref, sync::Arc};
use crate::{ChannelBuilder, Encode, LazyContext, Schema};
use super::{Channel, RawChannel};
pub struct LazyChannel<T: Encode> {
topic: &'static str,
context: &'static LazyContext,
inner: OnceLock<Channel<T>>,
}
impl<T: Encode> LazyChannel<T> {
#[must_use]
pub const fn new(topic: &'static str) -> Self {
Self {
topic,
context: LazyContext::get_default(),
inner: OnceLock::new(),
}
}
#[must_use]
pub const fn context(mut self, context: &'static LazyContext) -> Self {
self.context = context;
self
}
pub fn init(&self) {
self.get_or_init();
}
fn get_or_init(&self) -> &Channel<T> {
self.inner.get_or_init(|| {
ChannelBuilder::new(self.topic)
.context(self.context)
.build()
})
}
}
impl<T: Encode> Deref for LazyChannel<T> {
type Target = Channel<T>;
fn deref(&self) -> &Self::Target {
self.get_or_init()
}
}
pub struct LazyRawChannel {
topic: &'static str,
context: &'static LazyContext,
message_encoding: &'static str,
schema: Option<(&'static str, &'static str, &'static [u8])>,
inner: OnceLock<Arc<RawChannel>>,
}
impl LazyRawChannel {
pub const fn new(topic: &'static str, message_encoding: &'static str) -> Self {
Self {
topic,
context: LazyContext::get_default(),
message_encoding,
schema: None,
inner: OnceLock::new(),
}
}
#[must_use]
pub const fn context(mut self, context: &'static LazyContext) -> Self {
self.context = context;
self
}
#[must_use]
pub const fn schema(
mut self,
name: &'static str,
encoding: &'static str,
data: &'static [u8],
) -> Self {
self.schema = Some((name, encoding, data));
self
}
pub fn init(&self) {
self.get_or_init();
}
fn get_or_init(&self) -> &Arc<RawChannel> {
self.inner.get_or_init(|| {
let schema = self
.schema
.map(|(name, encoding, data)| Schema::new(name, encoding, data));
ChannelBuilder::new(self.topic)
.message_encoding(self.message_encoding)
.schema(schema)
.context(self.context)
.build_raw()
.unwrap_or_else(|e| {
panic!(
"Failed to lazily initialize channel for {}: {e:?}",
self.topic
)
})
})
}
}
impl Deref for LazyRawChannel {
type Target = Arc<RawChannel>;
fn deref(&self) -> &Self::Target {
self.get_or_init()
}
}