use super::*;
use crate::core::internals::*;
use crate::core::*;
use crate::sys;
use core::mem::ManuallyDrop;
#[cfg(feature = "std")]
extern crate std;
extern crate alloc;
use alloc::{format, string::String, vec::Vec};
pub struct AlertBuilder<'a, T>
where
T: QueryTuple,
{
pub(crate) desc: sys::ecs_alert_desc_t,
term_builder: TermBuilder,
world: WorldRef<'a>,
severity_filter_count: i32,
str_ptrs_to_free: Vec<ManuallyDrop<String>>,
_phantom: core::marker::PhantomData<&'a T>,
}
impl<T> Drop for AlertBuilder<'_, T>
where
T: QueryTuple,
{
fn drop(&mut self) {
for s in self.str_ptrs_to_free.iter_mut() {
unsafe { ManuallyDrop::drop(s) };
}
self.str_ptrs_to_free.clear();
}
}
impl<'a, T> AlertBuilder<'a, T>
where
T: QueryTuple,
{
pub(crate) fn new(world: &'a World) -> Self {
let mut obj = Self {
desc: Default::default(),
term_builder: TermBuilder::default(),
world: world.into(),
severity_filter_count: 0,
str_ptrs_to_free: Vec::new(),
_phantom: core::marker::PhantomData,
};
T::populate(&mut obj);
obj
}
pub(crate) fn new_from_desc(world: &'a World, desc: sys::ecs_alert_desc_t) -> Self {
let mut obj = Self {
desc,
term_builder: TermBuilder::default(),
world: world.into(),
severity_filter_count: 0,
str_ptrs_to_free: Vec::new(),
_phantom: core::marker::PhantomData,
};
if obj.desc.entity == 0 {
obj.desc.entity =
unsafe { sys::ecs_entity_init(obj.world_ptr_mut(), &Default::default()) };
}
T::populate(&mut obj);
#[cfg(feature = "flecs_pipeline")]
unsafe {
sys::ecs_add_id(
world.world_ptr_mut(),
obj.desc.entity,
ecs_dependson(ECS_ON_UPDATE),
);
sys::ecs_add_id(world.world_ptr_mut(), obj.desc.entity, ECS_ON_UPDATE);
}
obj
}
pub(crate) fn new_named(world: &'a World, name: &str) -> Self {
let name = compact_str::format_compact!("{}\0", name);
let mut obj = Self {
desc: Default::default(),
term_builder: TermBuilder::default(),
world: world.into(),
severity_filter_count: 0,
str_ptrs_to_free: Vec::new(),
_phantom: core::marker::PhantomData,
};
let entity_desc = sys::ecs_entity_desc_t {
name: name.as_ptr() as *const _,
sep: SEPARATOR.as_ptr(),
root_sep: SEPARATOR.as_ptr(),
..Default::default()
};
obj.desc.entity = unsafe { sys::ecs_entity_init(world.world_ptr_mut(), &entity_desc) };
T::populate(&mut obj);
obj
}
pub fn message(&mut self, message: &str) -> &mut Self {
let message = ManuallyDrop::new(format!("{message}\0"));
self.desc.message = message.as_ptr() as *const _;
self.str_ptrs_to_free.push(message);
self
}
pub fn brief(&mut self, brief: &str) -> &mut Self {
let brief = ManuallyDrop::new(format!("{brief}\0"));
self.desc.brief = brief.as_ptr() as *const _;
self.str_ptrs_to_free.push(brief);
self
}
pub fn doc_name(&mut self, doc_name: &str) -> &mut Self {
let doc_name = ManuallyDrop::new(format!("{doc_name}\0"));
self.desc.doc_name = doc_name.as_ptr() as *const _;
self.str_ptrs_to_free.push(doc_name);
self
}
pub fn severity(&mut self, severity: impl IntoEntity) -> &mut Self {
self.desc.severity = *severity.into_entity(self.world);
self
}
pub fn retain_period(&mut self, period: f32) -> &mut Self {
self.desc.retain_period = period;
self
}
pub fn severity_filter(
&mut self,
severity: impl IntoEntity,
with: impl IntoId,
var: Option<&str>,
) -> &mut Self {
ecs_assert!(
self.severity_filter_count < sys::ECS_ALERT_MAX_SEVERITY_FILTERS as i32,
"Maximum number of severity filters reached"
);
let filter = &mut self.desc.severity_filters[self.severity_filter_count as usize];
self.severity_filter_count += 1;
filter.severity = *severity.into_entity(self.world);
filter.with = *with.into_id(self.world);
if let Some(var) = var {
let var = ManuallyDrop::new(format!("{var}\0"));
filter.var = var.as_ptr() as *const _;
self.str_ptrs_to_free.push(var);
}
self
}
pub fn severity_filter_component<Severity, With>(&mut self, var: Option<&str>) -> &mut Self
where
Severity: ComponentId,
With: ComponentId + ComponentType<Struct>,
{
let severity_id = Severity::entity_id(self.world());
let with_id = With::entity_id(self.world());
self.severity_filter(severity_id, with_id, var)
}
pub fn severity_filter_enum<Severity, With>(
&mut self,
with: With,
var: Option<&str>,
) -> &mut Self
where
Severity: ComponentId,
With: EnumComponentInfo + ComponentType<Enum>,
{
let world = self.world();
let severity_id = Severity::entity_id(world);
let with_id = With::entity_id(world);
let constant_id = with.id_variant(world);
let pair_id = ecs_pair(with_id, *constant_id.id());
self.severity_filter(severity_id, pair_id, var)
}
pub fn member(&mut self, member: impl IntoEntity) -> &mut Self {
self.desc.member = *member.into_entity(self.world);
self
}
pub fn id(&mut self, id: impl IntoId) -> &mut Self {
self.desc.id = *id.into_id(self.world);
self
}
pub fn member_type<With>(&mut self, member_name: &str, var: Option<&str>) -> &mut Self
where
With: ComponentId,
{
let member_name = compact_str::format_compact!("{}\0", member_name);
let world = self.world();
let id = With::entity_id(world);
let member_id = unsafe {
sys::ecs_lookup_path_w_sep(
world.world_ptr_mut(),
id,
member_name.as_ptr() as *const _,
SEPARATOR.as_ptr(),
SEPARATOR.as_ptr(),
false,
)
};
ecs_assert!(
member_id != 0,
FlecsErrorCode::InvalidParameter,
"Member {} not found in component {}",
member_name,
core::any::type_name::<With>()
);
if let Some(var) = var {
let var = ManuallyDrop::new(format!("{var}\0"));
self.desc.var = var.as_ptr() as *const _;
self.str_ptrs_to_free.push(var);
}
self.member(member_id)
}
pub fn var(&mut self, var: &str) -> &mut Self {
let var = ManuallyDrop::new(format!("{var}\0"));
self.desc.var = var.as_ptr() as *const _;
self.str_ptrs_to_free.push(var);
self
}
}
#[doc(hidden)]
impl<'a, T: QueryTuple> internals::QueryConfig<'a> for AlertBuilder<'a, T> {
#[inline(always)]
fn term_builder(&self) -> &TermBuilder {
&self.term_builder
}
#[inline(always)]
fn term_builder_mut(&mut self) -> &mut TermBuilder {
&mut self.term_builder
}
#[inline(always)]
fn query_desc(&self) -> &sys::ecs_query_desc_t {
&self.desc.query
}
#[inline(always)]
fn query_desc_mut(&mut self) -> &mut sys::ecs_query_desc_t {
&mut self.desc.query
}
#[inline(always)]
fn count_generic_terms(&self) -> i32 {
T::COUNT
}
}
impl<'a, T: QueryTuple> TermBuilderImpl<'a> for AlertBuilder<'a, T> {}
impl<'a, T: QueryTuple> QueryBuilderImpl<'a> for AlertBuilder<'a, T> {}
impl<'a, T> Builder<'a> for AlertBuilder<'a, T>
where
T: QueryTuple,
{
type BuiltType = Alert<'a>;
fn build(&mut self) -> Self::BuiltType {
let alert = Alert::new(self.world(), self.desc);
for s in self.term_builder.str_ptrs_to_free.iter_mut() {
unsafe { ManuallyDrop::drop(s) };
}
alert
}
}
impl<'a, T: QueryTuple> WorldProvider<'a> for AlertBuilder<'a, T> {
fn world(&self) -> WorldRef<'a> {
self.world
}
}