Skip to content

Commit

Permalink
first steps
Browse files Browse the repository at this point in the history
  • Loading branch information
JieningYu committed Jan 29, 2024
1 parent 25896a5 commit 81293d0
Show file tree
Hide file tree
Showing 6 changed files with 842 additions and 3 deletions.
9 changes: 6 additions & 3 deletions util/freezer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,14 @@ pub trait Freeze<T> {
fn freeze(self, opts: Self::Opts) -> T;
}

impl<T> Freeze<T> for T {
impl<T, U> Freeze<U> for T
where
T: Into<U>,
{
type Opts = ();

#[inline]
fn freeze(self, _opts: Self::Opts) -> T {
self
fn freeze(self, _opts: Self::Opts) -> U {
self.into()
}
}
20 changes: 20 additions & 0 deletions util/registry/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "rimecraft-registry"
version = "0.1.0"
edition = "2021"
authors = ["JieningYu <[email protected]>"]
description = "Minecraft Registry implementation"
repository = "https://github.com/rimecraft-rs/rimecraft/"
license = "AGPL-3.0-or-later"
categories = ["data-structures"]

[badges]
maintenance = { status = "passively-maintained" }

[dependencies]
parking_lot = "0.12"
serde = { version = "1.0", optional = true }

[features]
default = ["serde"]
serde = ["dep:serde"]
148 changes: 148 additions & 0 deletions util/registry/src/entry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
use std::{collections::HashSet, hash::Hash, ops::Deref};

use parking_lot::RwLock;

use crate::{key::Key, tag::TagKey, ProvideRegistry};

/// Type holds a value that can be registered
/// in a registry.
#[derive(Debug)]
pub enum Entry<'a, K, T> {
/// Holds the value directly.
Direct(T),
/// Holds the value by reference.
Ref(&'a RefEntry<K, T>),
}

impl<'a, K, T> Entry<'a, K, T> {
/// Gets the containing value of this entry.
#[inline]
pub fn value(&self) -> Option<&T> {
match self {
Entry::Direct(value) => Some(value),
Entry::Ref(entry) => entry.value(),
}
}

/// Gets the key of this entry.
///
/// Returns `None` if the entry is a direct value.
#[inline]
pub fn key(&self) -> Option<&Key<K, T>> {
match self {
Entry::Direct(_) => None,
Entry::Ref(entry) => Some(entry.key()),
}
}

/// Gets the id of this entry.
///
/// Returns `None` if the entry is a direct value.
#[inline]
pub fn id(&self) -> Option<&K> {
self.key().map(Key::value)
}
}

impl<'a, K, T> From<T> for Entry<'a, K, T> {
#[inline]
fn from(value: T) -> Self {
Self::Direct(value)
}
}

/// Registry entry holds the value by reference.
///
/// The value is previously registered in a `Registry`, so
/// they can be referred to their registry keys.
///
/// This type also holds the entry's tags.
#[derive(Debug)]
pub struct RefEntry<K, T> {
pub(crate) raw: usize,
pub(crate) key: Key<K, T>,
pub(crate) value: Option<T>,
pub(crate) tags: RwLock<HashSet<TagKey<K, T>>>,
}

impl<K, T> RefEntry<K, T> {
/// Gets the raw id of this entry.
#[inline]
pub fn raw_id(&self) -> usize {
self.raw
}

/// Gets the containing value of this entry.
#[inline]
pub fn value(&self) -> Option<&T> {
self.value.as_ref()
}

/// Gets the key of this entry.
#[inline]
pub fn key(&self) -> &Key<K, T> {
&self.key
}

/// Gets the tags of this entry.
#[inline]
pub fn tags(&self) -> TagsGuard<'_, K, T> {
TagsGuard {
inner: self.tags.read(),
}
}
}

pub struct TagsGuard<'a, K, T> {
inner: parking_lot::RwLockReadGuard<'a, HashSet<TagKey<K, T>>>,
}

impl<'a, K, T> Deref for TagsGuard<'a, K, T> {
type Target = HashSet<TagKey<K, T>>;

#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl<'a, K: std::fmt::Debug, T> std::fmt::Debug for TagsGuard<'a, K, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("TagsGuard").field(&self.inner).finish()
}
}

#[cfg(feature = "serde")]
impl<K, T> serde::Serialize for RefEntry<K, T>
where
K: serde::Serialize,
{
/// Serializes the registry entry using the ID.
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.key.value().serialize(serializer)
}
}

#[cfg(feature = "serde")]
impl<'a, 'r, 'de, K, T> serde::Deserialize<'de> for &'a RefEntry<K, T>
where
'r: 'a,
K: serde::Deserialize<'de> + Hash + Eq + std::fmt::Debug + 'r,
T: ProvideRegistry<'r, K, T> + 'r,
{
/// Deserializes the registry entry using the ID.
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let id = K::deserialize(deserializer)?;
T::registry()
.get(&id)
.map(From::from)
.ok_or_else(|| serde::de::Error::custom(format!("unknown registry key {id:?}")))
}
}
83 changes: 83 additions & 0 deletions util/registry/src/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use std::{hash::Hash, marker::PhantomData};

/// A key for a value in a registry in a context
/// where a root registry is available.
pub struct Key<K, T> {
/// The id of the registry in the root registry.
registry: K,
/// The id of the value in the registry specified
/// by [`Self::registry`].
value: K,

_marker: PhantomData<T>,
}

impl<K, T> Key<K, T> {
/// Creates a new key.
#[inline]
pub const fn new(registry: K, value: K) -> Self {
Self {
registry,
value,
_marker: PhantomData,
}
}

/// Gets the id of the value in the registry.
#[inline]
pub fn value(&self) -> &K {
&self.value
}

/// Gets the id of the registry in the root registry.
#[inline]
pub fn registry(&self) -> &K {
&self.registry
}
}

impl<K: Hash, T> Hash for Key<K, T> {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.registry.hash(state);
self.value.hash(state);
}
}

impl<K: Clone, T> Clone for Key<K, T> {
#[inline]
fn clone(&self) -> Self {
Self {
registry: self.registry.clone(),
value: self.value.clone(),
_marker: PhantomData,
}
}
}

impl<K: Copy, T> Copy for Key<K, T> {}

impl<K: std::fmt::Debug, T> std::fmt::Debug for Key<K, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("RegistryKey")
.field(&self.registry)
.field(&self.value)
.finish()
}
}

impl<K: PartialEq, T> PartialEq for Key<K, T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.registry == other.registry && self.value == other.value
}
}

impl<K: Eq, T> Eq for Key<K, T> {}

impl<K, T> AsRef<K> for Key<K, T> {
#[inline]
fn as_ref(&self) -> &K {
&self.value
}
}
Loading

0 comments on commit 81293d0

Please sign in to comment.