pub trait UiBindable {
fn get_field(&self, path: &[&str]) -> Option<BindingValue>;
fn available_fields() -> Vec<String>
where
Self: Sized;
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum BindingValue {
String(String),
Integer(i64),
Float(f64),
Bool(bool),
List(Vec<BindingValue>),
Object(std::collections::HashMap<String, BindingValue>),
#[serde(skip)]
Custom(std::sync::Arc<dyn std::any::Any + Send + Sync>),
None,
}
impl PartialEq for BindingValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::String(l0), Self::String(r0)) => l0 == r0,
(Self::Integer(l0), Self::Integer(r0)) => l0 == r0,
(Self::Float(l0), Self::Float(r0)) => l0 == r0,
(Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
(Self::List(l0), Self::List(r0)) => l0 == r0,
(Self::Object(l0), Self::Object(r0)) => l0 == r0,
(Self::Custom(l0), Self::Custom(r0)) => std::sync::Arc::ptr_eq(l0, r0),
(Self::None, Self::None) => true,
_ => false,
}
}
}
impl BindingValue {
pub fn to_display_string(&self) -> String {
match self {
BindingValue::String(s) => s.clone(),
BindingValue::Integer(i) => i.to_string(),
BindingValue::Float(f) => f.to_string(),
BindingValue::Bool(b) => b.to_string(),
BindingValue::List(l) => format!("[{} items]", l.len()),
BindingValue::Object(map) => format!("{{Object with {} fields}}", map.len()),
BindingValue::Custom(_) => "[Custom Value]".to_string(),
BindingValue::None => String::new(),
}
}
pub fn to_bool(&self) -> bool {
match self {
BindingValue::Bool(b) => *b,
BindingValue::String(s) => !s.is_empty(),
BindingValue::Integer(i) => *i != 0,
BindingValue::Float(f) => *f != 0.0,
BindingValue::List(l) => !l.is_empty(),
BindingValue::Object(map) => !map.is_empty(),
BindingValue::Custom(_) => true,
BindingValue::None => false,
}
}
pub fn from_value<T: ToBindingValue>(value: &T) -> Self {
value.to_binding_value()
}
pub fn get_field(&self, field_name: &str) -> Option<BindingValue> {
match self {
BindingValue::Object(map) => map.get(field_name).cloned(),
_ => None,
}
}
}
pub trait ToBindingValue {
fn to_binding_value(&self) -> BindingValue;
}
impl ToBindingValue for String {
fn to_binding_value(&self) -> BindingValue {
BindingValue::String(self.clone())
}
}
impl ToBindingValue for &str {
fn to_binding_value(&self) -> BindingValue {
BindingValue::String(self.to_string())
}
}
impl ToBindingValue for i32 {
fn to_binding_value(&self) -> BindingValue {
BindingValue::Integer(*self as i64)
}
}
impl ToBindingValue for i64 {
fn to_binding_value(&self) -> BindingValue {
BindingValue::Integer(*self)
}
}
impl ToBindingValue for f32 {
fn to_binding_value(&self) -> BindingValue {
BindingValue::Float(*self as f64)
}
}
impl ToBindingValue for f64 {
fn to_binding_value(&self) -> BindingValue {
BindingValue::Float(*self)
}
}
impl ToBindingValue for bool {
fn to_binding_value(&self) -> BindingValue {
BindingValue::Bool(*self)
}
}
impl<T: ToBindingValue> ToBindingValue for Vec<T> {
fn to_binding_value(&self) -> BindingValue {
BindingValue::List(self.iter().map(|v| v.to_binding_value()).collect())
}
}
impl<T: ToBindingValue> ToBindingValue for Option<T> {
fn to_binding_value(&self) -> BindingValue {
match self {
Some(v) => v.to_binding_value(),
None => BindingValue::None,
}
}
}
impl<T: ToBindingValue> ToBindingValue for std::collections::HashMap<String, T> {
fn to_binding_value(&self) -> BindingValue {
BindingValue::Object(
self.iter()
.map(|(k, v)| (k.clone(), v.to_binding_value()))
.collect(),
)
}
}
impl ToBindingValue for std::sync::Arc<dyn std::any::Any + Send + Sync> {
fn to_binding_value(&self) -> BindingValue {
BindingValue::Custom(self.clone())
}
}
impl UiBindable for () {
fn get_field(&self, _path: &[&str]) -> Option<BindingValue> {
None
}
fn available_fields() -> Vec<String> {
vec![]
}
}