use std::{any::Any, cell::OnceCell};
use crate::DispatchableQuery;
#[derive(Debug)]
pub struct DispatchedQuery {
query: Option<Box<dyn Any + Send + Sync>>,
value: OnceCell<(Box<dyn Any + Send + Sync>, String)>,
name: String,
pub(crate) handled: bool,
}
impl DispatchedQuery {
pub(crate) fn new(query: Box<dyn Any + Send + Sync>, name: &str) -> Self {
Self {
query: Some(query),
value: OnceCell::new(),
handled: false,
name: name.to_string(),
}
}
pub fn the_query<T: 'static>(&self) -> Option<&T> {
if let Some(query) = &self.query {
query.downcast_ref()
} else {
None
}
}
pub fn the_query_mut<T: 'static>(&mut self) -> Option<&mut T> {
if let Some(query) = &mut self.query {
query.downcast_mut()
} else {
None
}
}
pub fn take_query<T: 'static>(&mut self) -> Option<Box<T>> {
if let Some(query) = self.query.take() {
query.downcast().ok()
} else {
None
}
}
pub fn set_value<V: Send + Sync + 'static>(&self, value: V) {
let x = std::any::type_name::<V>();
if self.value.set((Box::new(value), x.to_string())).is_err() {
tracing::error!(target: "dispatched query", "value can only be set once. Query: {}", &self.name);
}
}
pub fn value<T: 'static>(&self) -> Option<&T> {
if let Some(v) = self.value.get() {
v.0.downcast_ref()
} else {
None
}
}
pub fn take_value<T: 'static>(&mut self) -> Option<Box<T>> {
if let Some(v) = self.value.take() {
return v.0.downcast().ok();
}
None
}
pub fn handled(&self) -> bool {
self.handled
}
pub fn name(&self) -> &String {
&self.name
}
pub fn is<Q>(&self) -> bool {
std::any::type_name::<Q>() == self.name()
}
pub fn value_type_is<T>(&self) -> bool {
if let Some((_, name)) = self.value.get() {
std::any::type_name::<T>() == name
} else {
false
}
}
}
impl<Q: DispatchableQuery + 'static> From<Q> for DispatchedQuery {
fn from(value: Q) -> Self {
let name = std::any::type_name::<Q>().to_string();
Self::new(Box::new(value), &name)
}
}