#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo.png")]
#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
#![warn(unused_extern_crates)]
#![warn(missing_docs)]
use std::{any::Any, fmt, marker::PhantomData};
use zng_unique_id::unique_id_64;
pub use zng_unique_id::static_id;
#[diagnostic::on_unimplemented(note = "`StateValue` is implemented for all `T: Any + Send + Sync`")]
pub trait StateValue: Any + Send + Sync {}
impl<T: Any + Send + Sync> StateValue for T {}
unique_id_64! {
pub struct StateId<T: (StateValue)>;
}
zng_unique_id::impl_unique_id_bytemuck!(StateId<T: (StateValue)>);
impl<T: StateValue> fmt::Debug for StateId<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(debug_assertions)]
let t = pretty_type_name::pretty_type_name::<T>();
#[cfg(not(debug_assertions))]
let t = "$T";
if f.alternate() {
writeln!(f, "StateId<{t} {{")?;
writeln!(f, " id: {},", self.get())?;
writeln!(f, " sequential: {}", self.sequential())?;
writeln!(f, "}}")
} else {
write!(f, "StateId<{t}>({})", self.sequential())
}
}
}
pub struct StateMapRef<'a, U>(&'a state_map::StateMap, PhantomData<U>);
impl<U> Clone for StateMapRef<'_, U> {
fn clone(&self) -> Self {
*self
}
}
impl<U> Copy for StateMapRef<'_, U> {}
impl<U> fmt::Debug for StateMapRef<'_, U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"StateMapRef<{}>({} entries);",
pretty_type_name::pretty_type_name::<U>(),
self.0.len()
)
}
}
impl<U> StateMapRef<'static, U> {
pub fn empty() -> Self {
static EMPTY: state_map::StateMap = state_map::StateMap::new();
Self(&EMPTY, PhantomData)
}
}
impl<'a, U> StateMapRef<'a, U> {
pub fn contains<T: StateValue>(self, id: impl Into<StateId<T>>) -> bool {
self.0.contains(id.into())
}
pub fn get<T: StateValue>(self, id: impl Into<StateId<T>>) -> Option<&'a T> {
self.0.get(id.into())
}
pub fn copy<T: StateValue + Copy>(self, id: impl Into<StateId<T>>) -> Option<T> {
self.get(id.into()).copied()
}
pub fn get_clone<T: StateValue + Clone>(self, id: impl Into<StateId<T>>) -> Option<T> {
self.get(id.into()).cloned()
}
pub fn req<T: StateValue>(self, id: impl Into<StateId<T>>) -> &'a T {
self.0.req(id.into())
}
pub fn flagged(self, id: impl Into<StateId<()>>) -> bool {
self.0.flagged(id.into())
}
pub fn is_empty(self) -> bool {
self.0.is_empty()
}
pub fn ptr_eq(self, other: Self) -> bool {
std::ptr::eq(self.0, other.0)
}
}
pub struct StateMapMut<'a, U>(&'a mut state_map::StateMap, PhantomData<U>);
impl<U> fmt::Debug for StateMapMut<'_, U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "StateMapMut<{}>({} entries);", std::any::type_name::<U>(), self.0.len())
}
}
impl<'a, U> StateMapMut<'a, U> {
pub fn contains<T: StateValue>(&self, id: impl Into<StateId<T>>) -> bool {
self.0.contains(id.into())
}
pub fn get<T: StateValue>(&self, id: impl Into<StateId<T>>) -> Option<&T> {
self.0.get(id.into())
}
pub fn into_get<T: StateValue>(self, id: impl Into<StateId<T>>) -> Option<&'a T> {
self.0.get(id.into())
}
pub fn copy<T: StateValue + Copy>(&self, id: impl Into<StateId<T>>) -> Option<T> {
self.get(id.into()).copied()
}
pub fn get_clone<T: StateValue + Clone>(&self, id: impl Into<StateId<T>>) -> Option<T> {
self.get(id).cloned()
}
pub fn req<T: StateValue>(&self, id: impl Into<StateId<T>>) -> &T {
self.0.req(id.into())
}
pub fn into_req<T: StateValue>(self, id: impl Into<StateId<T>>) -> &'a T {
self.0.req(id.into())
}
pub fn flagged(&self, id: impl Into<StateId<()>>) -> bool {
self.0.flagged(id.into())
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn set<T: StateValue>(&mut self, id: impl Into<StateId<T>>, value: impl Into<T>) -> Option<T> {
self.0.set(id.into(), value.into())
}
pub fn get_mut<T: StateValue>(&mut self, id: impl Into<StateId<T>>) -> Option<&mut T> {
self.0.get_mut(id.into())
}
pub fn into_get_mut<T: StateValue>(self, id: impl Into<StateId<T>>) -> Option<&'a mut T> {
self.0.get_mut(id.into())
}
pub fn req_mut<T: StateValue>(&mut self, id: impl Into<StateId<T>>) -> &mut T {
self.0.req_mut(id.into())
}
pub fn into_req_mut<T: StateValue>(self, id: impl Into<StateId<T>>) -> &'a mut T {
self.0.req_mut(id.into())
}
pub fn entry<T: StateValue>(&mut self, id: impl Into<StateId<T>>) -> state_map::StateMapEntry<T> {
self.0.entry(id.into())
}
pub fn into_entry<T: StateValue>(self, id: impl Into<StateId<T>>) -> state_map::StateMapEntry<'a, T> {
self.0.entry(id.into())
}
pub fn flag(&mut self, id: impl Into<StateId<()>>) -> bool {
self.0.flag(id.into())
}
pub fn reborrow(&mut self) -> StateMapMut<U> {
StateMapMut(self.0, PhantomData)
}
pub fn as_ref(&self) -> StateMapRef<U> {
StateMapRef(self.0, PhantomData)
}
}
pub struct OwnedStateMap<U>(state_map::StateMap, PhantomData<U>);
impl<U> fmt::Debug for OwnedStateMap<U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"OwnedStateMap<{}>({} entries);",
pretty_type_name::pretty_type_name::<U>(),
self.0.len()
)
}
}
impl<U> Default for OwnedStateMap<U> {
fn default() -> Self {
Self::new()
}
}
impl<U> OwnedStateMap<U> {
pub const fn new() -> Self {
OwnedStateMap(state_map::StateMap::new(), PhantomData)
}
pub fn remove<T: StateValue>(&mut self, id: impl Into<StateId<T>>) -> Option<T> {
self.0.remove(id.into())
}
pub fn clear(&mut self) {
self.0.clear()
}
pub fn borrow(&self) -> StateMapRef<U> {
StateMapRef(&self.0, PhantomData)
}
pub fn borrow_mut(&mut self) -> StateMapMut<U> {
StateMapMut(&mut self.0, PhantomData)
}
}
pub mod state_map {
use std::any::Any;
use zng_unique_id::*;
use super::*;
type AnyMap = IdMap<u64, Box<dyn Any + Send + Sync>>;
pub(super) struct StateMap {
map: AnyMap,
}
impl StateMap {
pub(super) const fn new() -> Self {
StateMap { map: AnyMap::new() }
}
pub(super) fn len(&self) -> usize {
self.map.len()
}
pub(super) fn remove<T: StateValue>(&mut self, id: StateId<T>) -> Option<T> {
self.map.remove(&id.get()).map(|a| *a.downcast().unwrap())
}
pub(super) fn clear(&mut self) {
self.map.clear()
}
pub fn set<T: StateValue>(&mut self, id: StateId<T>, value: T) -> Option<T> {
self.map.insert(id.get(), Box::new(value)).map(|any| *any.downcast().unwrap())
}
pub fn contains<T: StateValue>(&self, id: StateId<T>) -> bool {
self.map.contains_key(&id.get())
}
pub fn get<T: StateValue>(&self, id: StateId<T>) -> Option<&T> {
self.map.get(&id.get()).map(|any| any.downcast_ref().unwrap())
}
pub fn get_mut<T: StateValue>(&mut self, id: StateId<T>) -> Option<&mut T> {
self.map.get_mut(&id.get()).map(|any| any.downcast_mut().unwrap())
}
pub fn req<T: StateValue>(&self, id: StateId<T>) -> &T {
self.get(id).unwrap_or_else(move || panic!("expected `{id:?}` in state map"))
}
pub fn req_mut<T: StateValue>(&mut self, id: StateId<T>) -> &mut T {
self.get_mut(id).unwrap_or_else(move || panic!("expected `{id:?}` in state map"))
}
pub fn entry<T: StateValue>(&mut self, id: StateId<T>) -> StateMapEntry<T> {
match self.map.entry(id.get()) {
IdEntry::Occupied(e) => StateMapEntry::Occupied(OccupiedStateMapEntry {
_type: PhantomData,
entry: e,
}),
IdEntry::Vacant(e) => StateMapEntry::Vacant(VacantStateMapEntry {
_type: PhantomData,
entry: e,
}),
}
}
pub fn flag(&mut self, id: StateId<()>) -> bool {
self.set(id, ()).is_some()
}
pub fn flagged(&self, id: StateId<()>) -> bool {
self.map.contains_key(&id.get())
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
}
pub struct OccupiedStateMapEntry<'a, T: StateValue> {
_type: PhantomData<T>,
entry: IdOccupiedEntry<'a, u64, Box<dyn Any + Send + Sync>>,
}
impl<'a, T: StateValue> OccupiedStateMapEntry<'a, T> {
pub fn get(&self) -> &T {
self.entry.get().downcast_ref().unwrap()
}
pub fn get_mut(&mut self) -> &mut T {
self.entry.get_mut().downcast_mut().unwrap()
}
pub fn into_mut(self) -> &'a mut T {
self.entry.into_mut().downcast_mut().unwrap()
}
pub fn insert(&mut self, value: T) -> T {
*self.entry.insert(Box::new(value)).downcast().unwrap()
}
pub fn remove(self) -> T {
*self.entry.remove().downcast().unwrap()
}
}
impl<T: StateValue + fmt::Debug> fmt::Debug for OccupiedStateMapEntry<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let id = StateId::<T>::from_raw(*self.entry.key());
f.debug_struct("OccupiedStateMapEntry")
.field("key", &id)
.field("value", self.get())
.finish()
}
}
pub struct VacantStateMapEntry<'a, T: StateValue> {
_type: PhantomData<T>,
entry: IdVacantEntry<'a, u64, Box<dyn Any + Send + Sync>>,
}
impl<'a, T: StateValue> VacantStateMapEntry<'a, T> {
pub fn insert(self, value: impl Into<T>) -> &'a mut T {
self.entry.insert(Box::new(value.into())).downcast_mut().unwrap()
}
}
impl<T: StateValue + fmt::Debug> fmt::Debug for VacantStateMapEntry<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let id = StateId::<T>::from_raw(*self.entry.key());
f.debug_struct("VacantStateMapEntry").field("key", &id).finish_non_exhaustive()
}
}
pub enum StateMapEntry<'a, T: StateValue> {
Occupied(OccupiedStateMapEntry<'a, T>),
Vacant(VacantStateMapEntry<'a, T>),
}
impl<'a, T: StateValue> StateMapEntry<'a, T> {
pub fn or_insert(self, default: impl Into<T>) -> &'a mut T {
match self {
StateMapEntry::Occupied(e) => e.into_mut(),
StateMapEntry::Vacant(e) => e.insert(default),
}
}
pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
match self {
StateMapEntry::Occupied(e) => e.into_mut(),
StateMapEntry::Vacant(e) => e.insert(default()),
}
}
pub fn and_modify<F: FnOnce(&mut T)>(mut self, f: F) -> Self {
if let StateMapEntry::Occupied(e) = &mut self {
f(e.get_mut())
}
self
}
}
impl<'a, T: StateValue> StateMapEntry<'a, T>
where
T: Default,
{
pub fn or_default(self) -> &'a mut T {
self.or_insert_with(Default::default)
}
}
impl<T: StateValue + fmt::Debug> fmt::Debug for StateMapEntry<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Occupied(arg0) => f.debug_tuple("Occupied").field(arg0).finish(),
Self::Vacant(arg0) => f.debug_tuple("Vacant").field(arg0).finish(),
}
}
}
}