use oorandom::Rand64;
use std::fmt::{Debug, Formatter};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub enum OwnedOrRef<'a, T: ?Sized> {
Owned(Box<T>),
Ref(&'a T),
AsRef(&'a (dyn AsRef<T> + Send + Sync)),
AsOwnedRef(Arc<dyn AsRef<T> + Send + Sync + 'a>),
}
impl Clone for OwnedOrRef<'_, str> {
fn clone(&self) -> Self {
match self {
OwnedOrRef::Owned(v) => OwnedOrRef::Owned(v.clone()),
OwnedOrRef::Ref(v) => OwnedOrRef::Ref(*v),
OwnedOrRef::AsRef(v) => OwnedOrRef::AsRef(*v),
OwnedOrRef::AsOwnedRef(v) => OwnedOrRef::AsOwnedRef(v.clone()),
}
}
}
impl<'a, T: Send + Sync + 'a> OwnedOrRef<'a, T> {
pub fn share_clone(&mut self) -> Self {
match self {
OwnedOrRef::Owned(_) => {
let owned = unsafe { std::ptr::read(self as *const Self) };
if let OwnedOrRef::Owned(v) = owned {
let arc: Arc<dyn AsRef<T> + Send + Sync> = Arc::new(v);
unsafe { std::ptr::write(self, OwnedOrRef::AsOwnedRef(arc.clone())) };
OwnedOrRef::AsOwnedRef(arc)
} else {
unreachable!()
}
}
OwnedOrRef::Ref(v) => OwnedOrRef::Ref(v),
OwnedOrRef::AsRef(v) => OwnedOrRef::AsRef(*v),
OwnedOrRef::AsOwnedRef(v) => OwnedOrRef::AsOwnedRef(v.clone()),
}
}
}
impl<T: Debug + ?Sized> Debug for OwnedOrRef<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self {
OwnedOrRef::Owned(t) => {
write!(f, "OwnedOrRef::Owned({:?})", t)
}
OwnedOrRef::Ref(t) => {
write!(f, "OwnedOrRef::Ref({:?})", t)
}
OwnedOrRef::AsRef(t) => {
write!(f, "OwnedOrRef::AsRef(&'a dyn AsRef<{:?}>)", t.as_ref())
}
&OwnedOrRef::AsOwnedRef(t) => {
write!(
f,
"OwnedOrRef::AsOwnedRef(Arc<dyn AsRef<{:?}>>)",
(**t).as_ref()
)
}
}
}
}
impl<T: ?Sized> AsRef<T> for OwnedOrRef<'_, T> {
fn as_ref(&self) -> &T {
match &self {
OwnedOrRef::Owned(t) => t,
OwnedOrRef::Ref(t) => t,
OwnedOrRef::AsRef(t) => t.as_ref(),
OwnedOrRef::AsOwnedRef(t) => (**t).as_ref(),
}
}
}
#[cfg(feature = "serialization")]
pub mod serialization {
use super::*;
use serde::de::DeserializeOwned;
use serde::ser::{Serialize, Serializer};
use serde::{Deserialize, Deserializer};
impl<T: Serialize + ?Sized> Serialize for OwnedOrRef<'_, T> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.as_ref().serialize(serializer)
}
}
impl<'de, T> Deserialize<'de> for OwnedOrRef<'_, T>
where
T: DeserializeOwned,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
T::deserialize(deserializer).map(|v| OwnedOrRef::Owned(Box::new(v)))
}
}
impl<'de> Deserialize<'de> for OwnedOrRef<'_, str> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
String::deserialize(deserializer).map(|v| OwnedOrRef::AsOwnedRef(Arc::new(v)))
}
}
}
pub enum OwnedOrRefMut<'a, T: ?Sized> {
Owned(Box<T>),
Ref(&'a mut T),
AsRef(&'a mut (dyn AsMut<T> + Send + Sync)),
}
impl<T: Debug + ?Sized> Debug for OwnedOrRefMut<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self {
OwnedOrRefMut::Owned(t) => {
write!(f, "OwnedOrRefMut::Owned({:?})", t)
}
OwnedOrRefMut::Ref(t) => {
write!(f, "OwnedOrRefMut::Ref({:?})", t)
}
OwnedOrRefMut::AsRef(_) => {
write!(f, "OwnedOrRefMut::AsRef(&'a dyn AsRef<..>)")
}
}
}
}
impl<T: ?Sized> AsMut<T> for OwnedOrRefMut<'_, T> {
fn as_mut(&mut self) -> &mut T {
match self {
OwnedOrRefMut::Owned(t) => t,
OwnedOrRefMut::Ref(t) => t,
OwnedOrRefMut::AsRef(t) => t.as_mut(),
}
}
}
impl<T: ?Sized> OwnedOrRefMut<'_, T> {
pub fn reborrow(&'_ mut self) -> OwnedOrRefMut<'_, T> {
match self {
OwnedOrRefMut::Owned(t) => OwnedOrRefMut::Ref(&mut *t),
OwnedOrRefMut::Ref(t) => OwnedOrRefMut::Ref(*t),
OwnedOrRefMut::AsRef(t) => OwnedOrRefMut::Ref(t.as_mut()),
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct ElementIdConfig<'render> {
pub(crate) id_name: Option<OwnedOrRef<'render, String>>,
pub(crate) handle: ElementId,
}
impl<'render> ElementIdConfig<'render> {
pub fn new_named(id_name: OwnedOrRef<'render, String>) -> Self {
Self {
id_name: Some(id_name),
handle: ElementId::new(),
}
}
pub fn new_empty() -> Self {
Self {
id_name: None,
handle: ElementId::new(),
}
}
pub fn get_id_name(&self) -> Option<&String> {
Some(self.id_name.as_ref()?.as_ref())
}
pub fn get_handle(&self) -> ElementId {
self.handle
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(
feature = "serialization",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct ElementId {
static_id: u128,
}
static RAND_GEN_STATE: Mutex<Option<(u128, u128)>> = Mutex::new(None);
impl ElementId {
fn new() -> Self {
let mut guard = RAND_GEN_STATE.lock().unwrap();
let state = match *guard {
Some(s) => s,
None => {
let rng = Rand64::new(0xDEAD_BEEF_CAFE_BABE);
let s = rng.state();
*guard = Some(s);
s
}
};
let mut rand = Rand64::from_state(state);
let static_id = rand.rand_u64() as u128 + ((rand.rand_u64() as u128) << 64);
*guard = Some(rand.state());
ElementId { static_id }
}
pub fn get_id(&self) -> u128 {
self.static_id
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
struct StrWrapper(String);
impl AsRef<String> for StrWrapper {
fn as_ref(&self) -> &String {
&self.0
}
}
#[test]
fn owned_or_ref_variants_resolve_via_as_ref() {
let owned = OwnedOrRef::Owned(Box::new(7u32));
assert_eq!(*owned.as_ref(), 7);
let value = 9u32;
let borrowed = OwnedOrRef::Ref(&value);
assert_eq!(*borrowed.as_ref(), 9);
let wrapper = StrWrapper(String::from("cotis"));
let trait_ref: &(dyn AsRef<String> + Send + Sync) = &wrapper;
let as_ref = OwnedOrRef::AsRef(trait_ref);
assert_eq!(as_ref.as_ref(), "cotis");
let arc: Arc<dyn AsRef<str> + Send + Sync> = Arc::new(String::from("shared"));
let as_owned = OwnedOrRef::AsOwnedRef(arc);
assert_eq!(as_owned.as_ref(), "shared");
}
#[test]
fn share_clone_promotes_owned_to_shared_arc() {
let mut owned = OwnedOrRef::Owned(Box::new(String::from("cotis")));
let shared = owned.share_clone();
assert_eq!(owned.as_ref(), "cotis");
assert_eq!(shared.as_ref(), "cotis");
}
#[test]
fn owned_or_ref_mut_reborrow_updates_underlying_value() {
let mut value = 10;
let mut wrapper = OwnedOrRefMut::Ref(&mut value);
{
let mut reborrowed = wrapper.reborrow();
*reborrowed.as_mut() += 5;
}
assert_eq!(value, 15);
}
#[test]
fn element_id_config_named_and_empty() {
let named = ElementIdConfig::new_named(OwnedOrRef::Owned(Box::new(String::from("panel"))));
assert_eq!(named.get_id_name(), Some(&String::from("panel")));
assert_ne!(named.get_handle().get_id(), 0);
let empty = ElementIdConfig::new_empty();
assert_eq!(empty.get_id_name(), None);
assert_ne!(empty.get_handle().get_id(), 0);
}
#[test]
fn element_ids_are_unique() {
let first = ElementIdConfig::new_empty().get_handle();
let second = ElementIdConfig::new_empty().get_handle();
assert_ne!(first, second);
}
#[cfg(feature = "serialization")]
mod serialization_tests {
use super::*;
use serde_json;
#[test]
fn owned_string_roundtrips_through_json() {
let value = OwnedOrRef::Owned(Box::new(String::from("cotis")));
let json = serde_json::to_string(&value).unwrap();
let decoded: OwnedOrRef<'_, String> = serde_json::from_str(&json).unwrap();
assert_eq!(decoded.as_ref(), "cotis");
}
#[test]
fn owned_str_roundtrips_through_json() {
let arc: Arc<dyn AsRef<str> + Send + Sync> = Arc::new(String::from("hello"));
let value: OwnedOrRef<'_, str> = OwnedOrRef::AsOwnedRef(arc);
let json = serde_json::to_string(&value).unwrap();
let decoded: OwnedOrRef<'_, str> = serde_json::from_str(&json).unwrap();
assert_eq!(decoded.as_ref(), "hello");
}
}
}