blob: ec45776599162f3aaa1717255a7930af52510732 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use parking_lot::RwLock;
use std::sync::Arc;
use thiserror::Error;
use tokio::sync::Notify;
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub type BatchWriteResult = Result<(), Error>;
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum Error {
#[error("BroadcastOnce dropped")]
Dropped,
#[error("Write failed: {message} (code {code})")]
WriteFailed { code: i32, message: String },
#[error("Write failed before request was sent: {message}")]
Client { message: String },
}
#[derive(Debug, Clone)]
pub struct BroadcastOnceReceiver<T> {
shared: Arc<Shared<T>>,
}
impl<T: Clone + Send + Sync> BroadcastOnceReceiver<T> {
/// Returns `Some(_)` if data has been produced
pub fn peek(&self) -> Option<Result<T>> {
self.shared.data.read().clone()
}
/// Waits for [`BroadcastOnce::broadcast`] to be called or returns an error
/// if the [`BroadcastOnce`] is dropped without a value being published
pub async fn receive(&self) -> Result<T> {
let notified = self.shared.notify.notified();
if let Some(v) = self.peek() {
return v;
}
notified.await;
self.peek().expect("just got notified")
}
}
#[derive(Debug)]
struct Shared<T> {
data: RwLock<Option<Result<T>>>,
notify: Notify,
}
#[derive(Debug)]
pub struct BroadcastOnce<T>
where
T: Send + Sync,
{
shared: Arc<Shared<T>>,
}
impl<T> Default for BroadcastOnce<T>
where
T: Send + Sync,
{
fn default() -> Self {
Self {
shared: Arc::new(Shared {
data: Default::default(),
notify: Default::default(),
}),
}
}
}
impl<T: Clone + Send + Sync> BroadcastOnce<T> {
/// Returns a [`BroadcastOnceReceiver`] that can be used to wait on
/// a call to [`BroadcastOnce::broadcast`] on this instance
pub fn receiver(&self) -> BroadcastOnceReceiver<T> {
BroadcastOnceReceiver {
shared: Arc::clone(&self.shared),
}
}
/// Broadcast a value to all [`BroadcastOnceReceiver`] handles
pub fn broadcast(&self, r: T) {
let mut locked = self.shared.data.write();
assert!(locked.is_none(), "double publish");
*locked = Some(Ok(r));
self.shared.notify.notify_waiters();
}
}
impl<T> Drop for BroadcastOnce<T>
where
T: Send + Sync,
{
fn drop(&mut self) {
let mut data = self.shared.data.write();
if data.is_none() {
log::warn!("BroadcastOnce dropped without producing");
*data = Some(Err(Error::Dropped));
self.shared.notify.notify_waiters();
}
}
}