use crate::rc_string::RcString;
use std::borrow::Borrow;
use std::collections::HashMap;
use std::convert::TryInto;
use std::hash::Hash;
use std::sync::Arc;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum PropertyValue {
String(RcString),
Bytes(Vec<u8>),
SInt(i32),
UInt(u32),
Float(f64),
}
impl PropertyValue {
pub fn get_string(&self) -> Option<RcString> {
match self {
PropertyValue::String(s) => Some(s.clone()),
_ => None,
}
}
pub fn get_str(&self) -> Option<&str> {
match self {
PropertyValue::String(s) => Some(s.as_str()),
_ => None,
}
}
pub fn get_bytes(&self) -> Option<&Vec<u8>> {
match self {
PropertyValue::Bytes(s) => Some(s),
_ => None,
}
}
pub fn get_float(&self) -> Option<f64> {
match self {
PropertyValue::Float(v) => Some(*v),
_ => None,
}
}
pub fn get_sint(&self) -> Option<i32> {
match self {
PropertyValue::SInt(v) => Some(*v),
_ => None,
}
}
pub fn get_uint(&self) -> Option<u32> {
match self {
PropertyValue::UInt(v) => Some(*v),
_ => None,
}
}
}
impl From<String> for PropertyValue {
fn from(v: String) -> Self {
PropertyValue::String(v.into())
}
}
impl From<Arc<String>> for PropertyValue {
fn from(v: Arc<String>) -> Self {
PropertyValue::String(v.into())
}
}
impl From<&Arc<String>> for PropertyValue {
fn from(v: &Arc<String>) -> Self {
PropertyValue::String(v.into())
}
}
impl From<&str> for PropertyValue {
fn from(v: &str) -> Self {
PropertyValue::String(v.into())
}
}
impl From<Vec<u8>> for PropertyValue {
fn from(v: Vec<u8>) -> Self {
PropertyValue::Bytes(v)
}
}
impl<'a> TryInto<&'a str> for &'a PropertyValue {
type Error = ();
fn try_into(self) -> Result<&'a str, Self::Error> {
if let PropertyValue::String(s) = self {
Ok(s.as_str())
} else {
Err(())
}
}
}
impl From<i32> for PropertyValue {
fn from(v: i32) -> Self {
PropertyValue::SInt(v)
}
}
impl TryInto<i32> for &PropertyValue {
type Error = ();
fn try_into(self) -> Result<i32, Self::Error> {
if let PropertyValue::SInt(v) = self {
Ok(*v)
} else {
Err(())
}
}
}
impl From<u32> for PropertyValue {
fn from(v: u32) -> Self {
PropertyValue::UInt(v)
}
}
impl From<f64> for PropertyValue {
fn from(v: f64) -> Self {
PropertyValue::Float(v)
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PropertyStore<K>
where
K: Hash + Eq,
{
content: HashMap<K, PropertyValue>,
}
impl<K: Hash + Eq> Default for PropertyStore<K> {
fn default() -> Self {
Self::new()
}
}
impl<K: Hash + Eq> PropertyStore<K> {
pub fn new() -> Self {
PropertyStore {
content: HashMap::new(),
}
}
pub fn insert<V: Into<PropertyValue>>(&mut self, key: K, value: V) -> Option<PropertyValue> {
self.content.insert(key, value.into())
}
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&PropertyValue>
where
K: Borrow<Q>,
Q: Eq + Hash,
{
self.content.get(key)
}
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: Eq + Hash,
{
self.content.contains_key(key)
}
pub fn get_string<Q: ?Sized>(&self, key: &Q) -> Option<&RcString>
where
K: Borrow<Q>,
Q: Eq + Hash,
{
self.get(key).and_then(|v| {
if let PropertyValue::String(s) = v {
Some(s)
} else {
None
}
})
}
}
pub trait WithProperties {
type Key: Hash + Eq;
fn with_properties<F, R>(&self, f: F) -> R
where
F: FnOnce(Option<&PropertyStore<Self::Key>>) -> R;
fn with_properties_mut<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut PropertyStore<Self::Key>) -> R;
fn property<Q: ?Sized>(&self, key: &Q) -> Option<PropertyValue>
where
Self::Key: Borrow<Q>,
Q: Eq + Hash,
{
self.with_properties(|p| p.and_then(|p| p.get(key).cloned()))
}
fn property_str<Q: ?Sized>(&self, key: &Q) -> Option<RcString>
where
Self::Key: Borrow<Q>,
Q: Eq + Hash,
{
self.with_properties(|p| p.and_then(|p| p.get_string(key).cloned()))
}
fn set_property<V: Into<PropertyValue>>(
&self,
key: Self::Key,
value: V,
) -> Option<PropertyValue> {
self.with_properties_mut(|p| p.insert(key, value))
}
}