use arc_swap::{ArcSwap, Guard};
use std::ops::Deref;
use std::sync::{Arc, OnceLock};
pub enum AnyCow<'a, T>
where
T: 'a + ToOwned,
{
Borrowed(&'a T),
Owned(Box<T>),
Shared(Arc<T>),
Updatable(ArcSwap<T>),
Lazy {
data: OnceLock<ArcSwap<T>>,
init: fn() -> T,
},
}
impl<'a, T> AnyCow<'a, T>
where
T: 'a + ToOwned<Owned = T>,
{
pub const fn borrowed(value: &'a T) -> Self {
AnyCow::Borrowed(value)
}
pub fn owned(value: T) -> Self {
AnyCow::Owned(Box::new(value))
}
pub const fn shared(value: Arc<T>) -> Self {
AnyCow::Shared(value)
}
pub fn updatable(value: T) -> Self {
AnyCow::Updatable(ArcSwap::from(Arc::new(value)))
}
pub const fn lazy(init: fn() -> T) -> Self {
AnyCow::Lazy {
data: OnceLock::new(),
init,
}
}
pub const fn is_borrowed(&self) -> bool {
matches!(self, AnyCow::Borrowed(_))
}
pub const fn is_owned(&self) -> bool {
matches!(self, AnyCow::Owned(_))
}
pub const fn is_shared(&self) -> bool {
matches!(self, AnyCow::Shared(_))
}
pub const fn is_updatable(&self) -> bool {
matches!(self, AnyCow::Updatable(_))
}
pub const fn is_lazy(&self) -> bool {
matches!(self, AnyCow::Lazy { .. })
}
pub fn to_mut(&mut self) -> &mut T {
match self {
AnyCow::Borrowed(value) => {
*self = AnyCow::Owned(Box::new(value.to_owned()));
match self {
AnyCow::Owned(value) => value,
_ => unreachable!(),
}
}
AnyCow::Owned(value) => value,
AnyCow::Shared(value) => {
*self = AnyCow::Owned(Box::new(value.as_ref().to_owned()));
match self {
AnyCow::Owned(value) => value,
_ => unreachable!(),
}
}
AnyCow::Updatable(value) => {
let owned = value.load().as_ref().to_owned();
*self = AnyCow::Owned(Box::new(owned));
match self {
AnyCow::Owned(value) => value,
_ => unreachable!(),
}
}
AnyCow::Lazy { data, init } => {
let arc_swap = data.get_or_init(|| ArcSwap::from(Arc::new(init())));
let owned = arc_swap.load().as_ref().to_owned();
*self = AnyCow::Owned(Box::new(owned));
match self {
AnyCow::Owned(value) => value,
_ => unreachable!(),
}
}
}
}
pub fn into_owned(self) -> T {
match self {
AnyCow::Borrowed(value) => value.to_owned(),
AnyCow::Owned(value) => *value,
AnyCow::Shared(value) => {
Arc::try_unwrap(value).unwrap_or_else(|arc| arc.as_ref().to_owned())
}
AnyCow::Updatable(value) => value.load().as_ref().to_owned(),
AnyCow::Lazy { data, init } => {
let arc_swap = data.get_or_init(|| ArcSwap::from(Arc::new(init())));
arc_swap.load().as_ref().to_owned()
}
}
}
pub fn borrow(&self) -> AnyCowRef<T> {
match self {
AnyCow::Borrowed(value) => AnyCowRef::Direct(value),
AnyCow::Owned(value) => AnyCowRef::Direct(&**value),
AnyCow::Shared(value) => AnyCowRef::Direct(value),
AnyCow::Updatable(value) => AnyCowRef::Guarded(value.load()),
AnyCow::Lazy { data, init } => {
let arc_swap = data.get_or_init(|| ArcSwap::from(Arc::new(init())));
AnyCowRef::Guarded(arc_swap.load())
}
}
}
pub fn try_replace(&self, new_val: T) -> Result<(), AnyCowReplaceError> {
match self {
AnyCow::Updatable(a) => {
a.store(Arc::new(new_val));
Ok(())
}
AnyCow::Lazy { data, init } => {
let arc_swap = data.get_or_init(|| ArcSwap::from(Arc::new(init())));
arc_swap.store(Arc::new(new_val));
Ok(())
}
_ => Err(AnyCowReplaceError),
}
}
pub fn to_arc(&self) -> Arc<T> {
match self {
AnyCow::Borrowed(value) => Arc::new((*value).to_owned()),
AnyCow::Owned(value) => Arc::new((**value).to_owned()),
AnyCow::Shared(value) => value.clone(),
AnyCow::Updatable(value) => value.load().to_owned(),
AnyCow::Lazy { data, init } => {
let arc_swap = data.get_or_init(|| ArcSwap::from(Arc::new(init())));
arc_swap.load().to_owned()
}
}
}
pub fn to_shared(&self) -> AnyCow<'a, T> {
match self {
AnyCow::Borrowed(value) => AnyCow::Borrowed(value),
_ => AnyCow::Shared(self.to_arc()),
}
}
}
impl<T> From<T> for AnyCow<'_, T>
where
T: ToOwned,
{
fn from(value: T) -> Self {
AnyCow::Owned(Box::new(value))
}
}
impl<'a, T> From<&'a T> for AnyCow<'a, T>
where
T: 'a + ToOwned,
{
fn from(value: &'a T) -> Self {
AnyCow::Borrowed(value)
}
}
impl<T> From<Arc<T>> for AnyCow<'_, T>
where
T: ToOwned,
{
fn from(value: Arc<T>) -> Self {
AnyCow::Shared(value)
}
}
pub enum AnyCowRef<'a, T>
where
T: 'a + ToOwned,
{
Direct(&'a T),
Guarded(Guard<Arc<T>>),
}
impl<'a, T> Deref for AnyCowRef<'a, T>
where
T: 'a + ToOwned,
{
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
AnyCowRef::Direct(value) => value,
AnyCowRef::Guarded(guard) => guard.as_ref(),
}
}
}
impl<'a, T> Clone for AnyCow<'a, T>
where
T: 'a + ToOwned<Owned = T> + Clone,
{
fn clone(&self) -> Self {
match self {
AnyCow::Borrowed(value) => AnyCow::Borrowed(value),
AnyCow::Owned(value) => AnyCow::Owned(Box::new((**value).clone())),
AnyCow::Shared(value) => AnyCow::Shared(value.clone()),
AnyCow::Updatable(value) => {
AnyCow::Updatable(ArcSwap::from(value.load().clone()))
}
AnyCow::Lazy { data, init } => {
let arc_swap = data.get_or_init(|| ArcSwap::from(Arc::new(init())));
AnyCow::Updatable(ArcSwap::from(arc_swap.load().clone()))
}
}
}
}
impl<'a, T> std::fmt::Debug for AnyCow<'a, T>
where
T: 'a + ToOwned<Owned = T> + std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AnyCow::Borrowed(value) => f.debug_tuple("Borrowed").field(value).finish(),
AnyCow::Owned(value) => f.debug_tuple("Owned").field(&**value).finish(),
AnyCow::Shared(value) => f.debug_tuple("Shared").field(value).finish(),
AnyCow::Updatable(value) => f.debug_tuple("Updatable").field(&*value.load()).finish(),
AnyCow::Lazy { data, .. } => {
if let Some(arc_swap) = data.get() {
f.debug_tuple("Lazy").field(&*arc_swap.load()).finish()
} else {
f.debug_tuple("Lazy").field(&"<uninitialized>").finish()
}
}
}
}
}
impl<'a, T> PartialEq for AnyCow<'a, T>
where
T: 'a + ToOwned<Owned = T> + PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.borrow().deref() == other.borrow().deref()
}
}
impl<'a, T> Eq for AnyCow<'a, T> where T: 'a + ToOwned<Owned = T> + Eq {}
impl<'a, T> std::hash::Hash for AnyCow<'a, T>
where
T: 'a + ToOwned<Owned = T> + std::hash::Hash,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.borrow().deref().hash(state)
}
}
impl<'a, T> PartialOrd for AnyCow<'a, T>
where
T: 'a + ToOwned<Owned = T> + PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.borrow().deref().partial_cmp(other.borrow().deref())
}
}
impl<'a, T> Ord for AnyCow<'a, T>
where
T: 'a + ToOwned<Owned = T> + Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.borrow().deref().cmp(other.borrow().deref())
}
}
impl<'a, T> std::fmt::Display for AnyCow<'a, T>
where
T: 'a + ToOwned<Owned = T> + std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.borrow().deref().fmt(f)
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct AnyCowReplaceError;