use std::collections::btree_map::*;
use std::fmt;
use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign};
use std::sync::LazyLock;
use bevy_ecs::component::Component;
use bevy_ecs::resource::Resource;
use estr::Estr;
mod ext;
pub use ext::*;
#[derive(Debug, Copy, Clone)]
pub enum Value {
Bool(bool),
Num(f32),
Str(Estr),
}
impl Default for Value {
fn default() -> Self {
Value::Bool(false)
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Bool(bool) => write!(f, "{bool}"),
Value::Num(num) => write!(f, "{num}"),
Value::Str(estr) => write!(f, "{estr}"),
}
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Value::Bool(value)
}
}
impl From<Value> for Option<bool> {
fn from(value: Value) -> Self {
match value {
Value::Bool(bool) => Some(bool),
_ => None,
}
}
}
impl From<Value> for bool {
fn from(value: Value) -> Self {
Option::from(value).unwrap_or_default()
}
}
impl From<f32> for Value {
fn from(value: f32) -> Self {
Value::Num(value)
}
}
impl From<Value> for Option<f32> {
fn from(value: Value) -> Self {
match value {
Value::Num(num) => Some(num),
_ => None,
}
}
}
impl From<Value> for f32 {
fn from(value: Value) -> Self {
Option::from(value).unwrap_or_default()
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Value::Num(value as f32)
}
}
impl From<Value> for Option<f64> {
fn from(value: Value) -> Self {
match value {
Value::Num(num) => Some(num as f64),
_ => None,
}
}
}
impl From<Value> for f64 {
fn from(value: Value) -> Self {
Option::from(value).unwrap_or_default()
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Value::Str(value.into())
}
}
impl From<Value> for Option<&str> {
fn from(value: Value) -> Self {
match value {
Value::Str(str) => Some(str.as_str()),
_ => None,
}
}
}
impl From<Value> for &str {
fn from(value: Value) -> Self {
Option::from(value).unwrap_or_default()
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::Str(value.into())
}
}
impl From<Value> for Option<String> {
fn from(value: Value) -> Self {
match value {
Value::Str(str) => Some(str.as_str().to_string()),
_ => None,
}
}
}
impl From<Value> for String {
fn from(value: Value) -> Self {
Option::from(value).unwrap_or_default()
}
}
impl From<Estr> for Value {
fn from(value: Estr) -> Self {
Value::Str(value)
}
}
impl From<Value> for Option<Estr> {
fn from(value: Value) -> Self {
match value {
Value::Str(str) => Some(str),
_ => None,
}
}
}
impl From<Value> for Estr {
fn from(value: Value) -> Self {
Option::from(value).unwrap_or_default()
}
}
impl AsRef<bool> for Value {
fn as_ref(&self) -> &bool {
match self {
Value::Bool(bool) => bool,
_ => &false,
}
}
}
impl AsRef<f32> for Value {
fn as_ref(&self) -> &f32 {
match self {
Value::Num(num) => num,
_ => &0.0,
}
}
}
static EMPTY_ESTR: LazyLock<Estr> = LazyLock::new(|| Estr::from(""));
impl AsRef<Estr> for Value {
fn as_ref(&self) -> &Estr {
match self {
Value::Str(str) => str,
_ => &EMPTY_ESTR,
}
}
}
impl AsRef<Value> for Value {
fn as_ref(&self) -> &Value {
self
}
}
impl AsMut<bool> for Value {
fn as_mut(&mut self) -> &mut bool {
match self {
Value::Bool(bool) => bool,
_ => {
*self = Value::Bool(false);
let Value::Bool(bool) = self else {
unreachable!();
};
bool
}
}
}
}
impl AsMut<f32> for Value {
fn as_mut(&mut self) -> &mut f32 {
match self {
Value::Num(num) => num,
_ => {
*self = Value::Num(0.0);
let Value::Num(num) = self else {
unreachable!();
};
num
}
}
}
}
impl AsMut<Estr> for Value {
fn as_mut(&mut self) -> &mut Estr {
match self {
Value::Str(str) => str,
_ => {
*self = Value::Str(Estr::from(""));
let Value::Str(str) = self else {
unreachable!();
};
str
}
}
}
}
impl AsMut<Value> for Value {
fn as_mut(&mut self) -> &mut Value {
self
}
}
impl PartialEq<bool> for Value {
fn eq(&self, other: &bool) -> bool {
match self {
Value::Bool(this) => this == other,
_ => false,
}
}
}
impl PartialEq<Value> for bool {
fn eq(&self, other: &Value) -> bool {
match other {
Value::Bool(that) => self == that,
_ => false,
}
}
}
impl PartialEq<f32> for Value {
fn eq(&self, other: &f32) -> bool {
match self {
Value::Num(this) => this == other,
_ => false,
}
}
}
impl PartialEq<Value> for f32 {
fn eq(&self, other: &Value) -> bool {
match other {
Value::Num(that) => self == that,
_ => false,
}
}
}
impl PartialEq<&str> for Value {
fn eq(&self, other: &&str) -> bool {
match self {
Value::Str(this) => *this == Estr::from(other),
_ => false,
}
}
}
impl PartialEq<Value> for &str {
fn eq(&self, other: &Value) -> bool {
match other {
Value::Str(that) => *self == Estr::from(that),
_ => false,
}
}
}
impl PartialEq<String> for Value {
fn eq(&self, other: &String) -> bool {
match self {
Value::Str(this) => *this == Estr::from(other),
_ => false,
}
}
}
impl PartialEq<Value> for String {
fn eq(&self, other: &Value) -> bool {
match other {
Value::Str(that) => *self == Estr::from(that),
_ => false,
}
}
}
impl PartialEq<Estr> for Value {
fn eq(&self, other: &Estr) -> bool {
match self {
Value::Str(this) => this == other,
_ => false,
}
}
}
impl PartialEq<Value> for Estr {
fn eq(&self, other: &Value) -> bool {
match other {
Value::Str(that) => self == that,
_ => false,
}
}
}
impl PartialEq<Value> for Value {
fn eq(&self, other: &Value) -> bool {
match (self, other) {
(Value::Bool(this), Value::Bool(that)) => this == that,
(Value::Num(this), Value::Num(that)) => this == that,
(Value::Str(this), Value::Str(that)) => this == that,
_ => false,
}
}
}
impl Eq for Value {}
impl PartialOrd<bool> for Value {
fn partial_cmp(&self, that: &bool) -> Option<std::cmp::Ordering> {
match self {
Value::Bool(this) => this.partial_cmp(that),
_ => None,
}
}
}
impl PartialOrd<Value> for bool {
fn partial_cmp(&self, other: &Value) -> Option<std::cmp::Ordering> {
match other {
Value::Bool(that) => self.partial_cmp(that),
_ => None,
}
}
}
impl PartialOrd<f32> for Value {
fn partial_cmp(&self, that: &f32) -> Option<std::cmp::Ordering> {
match self {
Value::Num(this) => this.partial_cmp(that),
_ => None,
}
}
}
impl PartialOrd<Value> for f32 {
fn partial_cmp(&self, other: &Value) -> Option<std::cmp::Ordering> {
match other {
Value::Num(that) => self.partial_cmp(that),
_ => None,
}
}
}
impl PartialOrd<Estr> for Value {
fn partial_cmp(&self, that: &Estr) -> Option<std::cmp::Ordering> {
match self {
Value::Str(this) => this.partial_cmp(that),
_ => None,
}
}
}
impl PartialOrd<Value> for Estr {
fn partial_cmp(&self, other: &Value) -> Option<std::cmp::Ordering> {
match other {
Value::Str(that) => self.partial_cmp(that),
_ => None,
}
}
}
impl PartialOrd<Value> for Value {
fn partial_cmp(&self, other: &Value) -> Option<std::cmp::Ordering> {
match (self, other) {
(Value::Bool(this), Value::Bool(that)) => this.partial_cmp(that),
(Value::Num(this), Value::Num(that)) => this.partial_cmp(that),
(Value::Str(this), Value::Str(that)) => this.partial_cmp(that),
_ => None,
}
}
}
impl Add<f32> for Value {
type Output = Value;
fn add(self, rhs: f32) -> Self::Output {
match self {
Value::Num(lhs) => Value::Num(lhs + rhs),
_ => Value::Num(rhs),
}
}
}
impl Add<Value> for f32 {
type Output = Value;
fn add(self, rhs: Value) -> Self::Output {
match rhs {
Value::Num(rhs) => Value::Num(self + rhs),
_ => Value::Num(self),
}
}
}
impl AddAssign<f32> for Value {
fn add_assign(&mut self, rhs: f32) {
*self = *self + rhs
}
}
impl Add<Value> for Value {
type Output = Value;
fn add(self, rhs: Value) -> Self::Output {
match (self, rhs) {
(Value::Num(lhs), Value::Num(rhs)) => Value::Num(lhs + rhs),
(Value::Num(num), _) | (_, Value::Num(num)) => Value::Num(num),
_ => Value::Num(0.0),
}
}
}
impl AddAssign<Value> for Value {
fn add_assign(&mut self, rhs: Value) {
*self = *self + rhs
}
}
impl Sub<f32> for Value {
type Output = Value;
fn sub(self, rhs: f32) -> Self::Output {
match self {
Value::Num(lhs) => Value::Num(lhs - rhs),
_ => Value::Num(-rhs),
}
}
}
impl Sub<Value> for f32 {
type Output = Value;
fn sub(self, rhs: Value) -> Self::Output {
match rhs {
Value::Num(rhs) => Value::Num(self - rhs),
_ => Value::Num(-self),
}
}
}
impl SubAssign<f32> for Value {
fn sub_assign(&mut self, rhs: f32) {
*self = *self - rhs
}
}
impl Sub<Value> for Value {
type Output = Value;
fn sub(self, rhs: Value) -> Self::Output {
match (self, rhs) {
(Value::Num(lhs), Value::Num(rhs)) => Value::Num(lhs - rhs),
(Value::Num(num), _) => Value::Num(num),
(_, Value::Num(num)) => Value::Num(-num),
_ => Value::Num(0.0),
}
}
}
impl SubAssign<Value> for Value {
fn sub_assign(&mut self, rhs: Value) {
*self = *self - rhs
}
}
impl Mul<f32> for Value {
type Output = Value;
fn mul(self, rhs: f32) -> Self::Output {
match self {
Value::Num(lhs) => Value::Num(lhs * rhs),
_ => Value::Num(0.0),
}
}
}
impl Mul<Value> for f32 {
type Output = Value;
fn mul(self, rhs: Value) -> Self::Output {
match rhs {
Value::Num(rhs) => Value::Num(self * rhs),
_ => Value::Num(0.0),
}
}
}
impl MulAssign<f32> for Value {
fn mul_assign(&mut self, rhs: f32) {
*self = *self * rhs
}
}
impl Mul<Value> for Value {
type Output = Value;
fn mul(self, rhs: Value) -> Self::Output {
match (self, rhs) {
(Value::Num(lhs), Value::Num(rhs)) => Value::Num(lhs * rhs),
_ => Value::Num(0.0),
}
}
}
impl MulAssign<Value> for Value {
fn mul_assign(&mut self, rhs: Value) {
*self = *self * rhs
}
}
impl Div<f32> for Value {
type Output = Value;
fn div(self, rhs: f32) -> Self::Output {
match self {
Value::Num(lhs) => Value::Num(lhs / rhs),
_ => Value::Num(0.0),
}
}
}
impl Div<Value> for f32 {
type Output = Value;
fn div(self, rhs: Value) -> Self::Output {
match rhs {
Value::Num(rhs) => Value::Num(self / rhs),
_ => Value::Num(self),
}
}
}
impl DivAssign<f32> for Value {
fn div_assign(&mut self, rhs: f32) {
*self = *self / rhs
}
}
impl Div<Value> for Value {
type Output = Value;
fn div(self, rhs: Value) -> Self::Output {
match (self, rhs) {
(Value::Num(lhs), Value::Num(rhs)) => Value::Num(lhs / rhs),
(Value::Num(lhs), _) => Value::Num(lhs),
(_, Value::Num(_)) => Value::Num(0.0),
_ => Value::Num(0.0),
}
}
}
impl DivAssign<Value> for Value {
fn div_assign(&mut self, rhs: Value) {
*self = *self / rhs
}
}
#[derive(Component, Resource, Default, Clone, Debug)]
pub struct Props {
properties: BTreeMap<Estr, Value>,
}
impl Props {
pub fn new() -> Props {
Props::default()
}
pub fn entry(&mut self, name: impl Into<Estr>) -> Entry<'_, Estr, Value> {
self.properties.entry(name.into())
}
pub fn get<T>(&self, name: impl Into<Estr>) -> T
where
T: From<Value> + Default + 'static,
{
if let Some(&value) = self.properties.get(&name.into()) {
value.into()
} else {
T::default()
}
}
pub fn get_mut<T>(&mut self, name: impl Into<Estr>) -> &mut T
where
Value: AsMut<T>,
{
self.properties.entry(name.into()).or_default().as_mut()
}
pub fn set(&mut self, name: impl Into<Estr>, value: impl Into<Value>) {
self.properties.insert(name.into(), value.into());
}
pub fn with(mut self, name: impl Into<Estr>, value: impl Into<Value>) -> Self {
self.set(name, value);
self
}
pub fn remove(&mut self, name: impl Into<Estr>) {
self.properties.remove(&name.into());
}
pub fn clear(&mut self) {
self.properties.clear();
}
pub fn iter(&self) -> Iter<'_, Estr, Value> {
self.properties.iter()
}
pub fn keys(&self) -> Keys<'_, Estr, Value> {
self.properties.keys()
}
pub fn into_keys(self) -> IntoKeys<Estr, Value> {
self.properties.into_keys()
}
pub fn values(&self) -> Values<'_, Estr, Value> {
self.properties.values()
}
pub fn into_values(self) -> IntoValues<Estr, Value> {
self.properties.into_values()
}
pub fn values_mut(&mut self) -> ValuesMut<'_, Estr, Value> {
self.properties.values_mut()
}
}
static DEFAULT_VALUE: LazyLock<Value> = LazyLock::new(Value::default);
impl<S: Into<Estr>> Index<S> for Props {
type Output = Value;
fn index(&self, index: S) -> &Self::Output {
self.properties.get(&index.into()).unwrap_or(&DEFAULT_VALUE)
}
}
impl<S: Into<Estr>> IndexMut<S> for Props {
fn index_mut(&mut self, index: S) -> &mut Self::Output {
self.get_mut(index)
}
}
impl IntoIterator for Props {
type Item = (Estr, Value);
type IntoIter = IntoIter<Estr, Value>;
fn into_iter(self) -> Self::IntoIter {
self.properties.into_iter()
}
}