#![warn(missing_docs)]
use std::ops::Deref;
use std::{any::Any, fmt::Debug, hash::Hash, sync::Arc, thread};
use error::{ArcResult, Error, TryInnerError};
use lazy_static::lazy_static;
use once_cell::sync::OnceCell;
use regex::Regex;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use sha2::{Digest, Sha256};
pub mod error;
pub mod mem;
pub mod multi;
pub mod persistent;
#[doc(hidden)]
pub mod rpc;
#[cfg(test)]
pub(crate) mod tests;
lazy_static! {
pub static ref NAMESPACE_REGEX: Regex =
Regex::new(r"^([A-Za-z_][A-Za-z0-9_]*\.)*[A-Za-z_][A-Za-z0-9_]*$").unwrap();
}
pub trait RawGenerateFn<V>: FnOnce() -> V + Send + Any {}
impl<V, T: FnOnce() -> V + Send + Any> RawGenerateFn<V> for T {}
pub trait GenerateFn<K, V>: FnOnce(&K) -> V + Send + Any {}
impl<K, V, T: FnOnce(&K) -> V + Send + Any> GenerateFn<K, V> for T {}
pub trait GenerateWithStateFn<K, S, V>: FnOnce(&K, S) -> V + Send + Any {}
impl<K, S, V, T: FnOnce(&K, S) -> V + Send + Any> GenerateWithStateFn<K, S, V> for T {}
pub trait GenerateResultFn<K, V, E>: FnOnce(&K) -> Result<V, E> + Send + Any {}
impl<K, V, E, T: FnOnce(&K) -> Result<V, E> + Send + Any> GenerateResultFn<K, V, E> for T {}
pub trait GenerateResultWithStateFn<K, S, V, E>:
FnOnce(&K, S) -> Result<V, E> + Send + Any
{
}
impl<K, S, V, E, T: FnOnce(&K, S) -> Result<V, E> + Send + Any>
GenerateResultWithStateFn<K, S, V, E> for T
{
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Namespace(String);
impl Namespace {
pub fn new(namespace: impl Into<String>) -> Self {
let namespace: String = namespace.into();
if !Namespace::validate(&namespace) {
panic!(
"invalid namespace, does not match regex {:?}",
NAMESPACE_REGEX.as_str(),
);
}
Self(namespace)
}
pub fn validate(namespace: &str) -> bool {
NAMESPACE_REGEX.is_match(namespace)
}
pub fn into_inner(self) -> String {
self.0
}
}
impl<T: Into<String>> From<T> for Namespace {
fn from(value: T) -> Self {
Self::new(value)
}
}
impl Deref for Namespace {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AsRef<str> for Namespace {
fn as_ref(&self) -> &str {
&self.0
}
}
pub trait Cacheable: Serialize + DeserializeOwned + Hash + Eq + Send + Sync + Any {
type Output: Send + Sync + Serialize + DeserializeOwned;
type Error: Send + Sync;
fn generate(&self) -> std::result::Result<Self::Output, Self::Error>;
}
impl<T: Cacheable> Cacheable for Arc<T> {
type Output = T::Output;
type Error = T::Error;
fn generate(&self) -> std::result::Result<Self::Output, Self::Error> {
<T as Cacheable>::generate(self)
}
}
pub trait CacheableWithState<S: Send + Sync + Any>:
Serialize + DeserializeOwned + Hash + Eq + Send + Sync + Any
{
type Output: Send + Sync + Serialize + DeserializeOwned;
type Error: Send + Sync;
fn generate_with_state(&self, state: S) -> std::result::Result<Self::Output, Self::Error>;
}
impl<S: Send + Sync + Any, T: CacheableWithState<S>> CacheableWithState<S> for Arc<T> {
type Output = T::Output;
type Error = T::Error;
fn generate_with_state(&self, state: S) -> std::result::Result<Self::Output, Self::Error> {
<T as CacheableWithState<S>>::generate_with_state(self, state)
}
}
#[derive(Debug)]
pub struct CacheHandle<V>(Arc<OnceCell<ArcResult<V>>>);
impl<V> Clone for CacheHandle<V> {
fn clone(&self) -> Self {
CacheHandle(self.0.clone())
}
}
impl<V> CacheHandle<V> {
pub(crate) fn empty() -> Self {
Self(Arc::new(OnceCell::new()))
}
}
impl<V: Send + Sync + Any> CacheHandle<V> {
pub(crate) fn new(generate_fn: impl RawGenerateFn<V>) -> Self {
let handle = Self(Arc::new(OnceCell::new()));
let handle_clone = handle.clone();
thread::spawn(move || {
handle_clone.set(run_generator(generate_fn));
});
handle
}
}
impl<V> CacheHandle<V> {
pub fn try_get(&self) -> ArcResult<&V> {
self.0.wait().as_ref().map_err(|e| e.clone())
}
pub fn poll(&self) -> Option<&ArcResult<V>> {
self.0.get()
}
pub fn get(&self) -> &V {
self.try_get().unwrap()
}
pub(crate) fn set(&self, value: ArcResult<V>) {
if self.0.set(value).is_err() {
tracing::error!("failed to set cache handle value");
panic!("failed to set cache handle value");
}
}
}
impl<V: Debug> CacheHandle<V> {
pub fn get_err(&self) -> Arc<error::Error> {
self.try_get().unwrap_err()
}
}
impl<V, E> CacheHandle<std::result::Result<V, E>> {
pub fn try_inner(&self) -> std::result::Result<&V, TryInnerError<E>> {
Ok(self
.try_get()
.map_err(|e| TryInnerError::CacheError(e))?
.as_ref()?)
}
}
impl<V, E: Debug> CacheHandle<std::result::Result<V, E>> {
pub fn unwrap_inner(&self) -> &V {
self.get().as_ref().unwrap()
}
}
impl<V: Debug, E> CacheHandle<std::result::Result<V, E>> {
pub fn unwrap_err_inner(&self) -> &E {
self.get().as_ref().unwrap_err()
}
}
pub(crate) fn hash(val: &[u8]) -> Vec<u8> {
let mut hasher = Sha256::new();
hasher.update(val);
hasher.finalize()[..].into()
}
pub(crate) fn run_generator<V: Any + Send + Sync>(
generate_fn: impl FnOnce() -> V + Send + Any,
) -> ArcResult<V> {
let join_handle = thread::spawn(generate_fn);
join_handle.join().map_err(|_| Arc::new(Error::Panic))
}