use std::marker::PhantomData;
use std::sync::Arc;
#[derive(Debug)]
pub struct Place<T: 'static> {
name: Arc<str>,
_phantom: PhantomData<fn() -> T>,
}
impl<T: 'static> Place<T> {
pub fn new(name: impl Into<Arc<str>>) -> Self {
Self {
name: name.into(),
_phantom: PhantomData,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn name_arc(&self) -> &Arc<str> {
&self.name
}
pub fn as_ref(&self) -> PlaceRef {
PlaceRef(Arc::clone(&self.name))
}
}
impl<T: 'static> Clone for Place<T> {
fn clone(&self) -> Self {
Self {
name: Arc::clone(&self.name),
_phantom: PhantomData,
}
}
}
impl<T: 'static> PartialEq for Place<T> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl<T: 'static> Eq for Place<T> {}
impl<T: 'static> std::hash::Hash for Place<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
#[derive(Debug, Clone)]
pub struct EnvironmentPlace<T: 'static> {
place: Place<T>,
}
impl<T: 'static> EnvironmentPlace<T> {
pub fn new(name: impl Into<Arc<str>>) -> Self {
Self {
place: Place::new(name),
}
}
pub fn place(&self) -> &Place<T> {
&self.place
}
pub fn name(&self) -> &str {
self.place.name()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PlaceRef(pub(crate) Arc<str>);
impl PlaceRef {
pub fn new(name: impl Into<Arc<str>>) -> Self {
Self(name.into())
}
pub fn name(&self) -> &str {
&self.0
}
pub fn name_arc(&self) -> &Arc<str> {
&self.0
}
}
impl<T: 'static> From<&Place<T>> for PlaceRef {
fn from(place: &Place<T>) -> Self {
place.as_ref()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn place_equality_by_name() {
let p1: Place<i32> = Place::new("test");
let p2: Place<i32> = Place::new("test");
assert_eq!(p1, p2);
}
#[test]
fn place_inequality() {
let p1: Place<i32> = Place::new("a");
let p2: Place<i32> = Place::new("b");
assert_ne!(p1, p2);
}
#[test]
fn place_clone_is_cheap() {
let p: Place<i32> = Place::new("test");
let p2 = p.clone();
assert!(Arc::ptr_eq(p.name_arc(), p2.name_arc()));
}
#[test]
fn place_ref_from_place() {
let p: Place<i32> = Place::new("test");
let r = PlaceRef::from(&p);
assert_eq!(r.name(), "test");
}
#[test]
fn environment_place() {
let ep = EnvironmentPlace::<String>::new("events");
assert_eq!(ep.name(), "events");
assert_eq!(ep.place().name(), "events");
}
}