all_is_cubes/
tag.rs

1//! [`Tag`] and related types, defining categories of entities for game rules.
2
3use core::convert::Infallible;
4
5use bevy_ecs::prelude as ecs;
6
7use crate::transaction;
8use crate::universe::{self, Handle};
9
10#[cfg(doc)]
11use crate::universe::Universe;
12
13//--------------------------------------------------------------------------------------------------
14
15/// Identifies game entities of a certain game-mechanical kind.
16///
17/// For example, blocks that can be destroyed with a particular tool.
18#[derive(Clone, Debug, Eq, Hash, PartialEq)]
19#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
20#[non_exhaustive]
21pub enum Tag {
22    /// A tag defined by its identity as a [`Universe`] member.
23    Handle(Handle<TagDef>),
24    // System(SysTag),
25}
26
27// pub enum SysTag {
28//     ///
29//     Replaceable,
30// }
31
32/// A [`Tag`] in the role of “this entity is tagged with this tag”.
33#[expect(clippy::exhaustive_structs)]
34#[derive(Clone, Debug, Eq, Hash, PartialEq)]
35#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
36pub struct Be(pub Tag);
37
38/// A [`Tag`] in the role of “check whether other entities are tagged with this tag”.
39#[expect(clippy::exhaustive_structs)]
40#[derive(Clone, Debug, Eq, Hash, PartialEq)]
41#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
42pub struct Is(pub Tag);
43
44//--------------------------------------------------------------------------------------------------
45
46impl universe::VisitHandles for Tag {
47    fn visit_handles(&self, visitor: &mut dyn universe::HandleVisitor) {
48        match self {
49            Tag::Handle(handle) => handle.visit_handles(visitor),
50        }
51    }
52}
53impl universe::VisitHandles for Be {
54    fn visit_handles(&self, visitor: &mut dyn universe::HandleVisitor) {
55        match self {
56            Be(tag) => tag.visit_handles(visitor),
57        }
58    }
59}
60impl universe::VisitHandles for Is {
61    fn visit_handles(&self, visitor: &mut dyn universe::HandleVisitor) {
62        match self {
63            Is(tag) => tag.visit_handles(visitor),
64        }
65    }
66}
67
68//--------------------------------------------------------------------------------------------------
69
70/// A tag defined by its identity as a [`Universe`] member.
71///
72#[doc = include_str!("save/serde-warning.md")]
73#[expect(clippy::exhaustive_structs)]
74#[expect(clippy::module_name_repetitions, reason = "TODO: reconsider")]
75#[derive(Debug, bevy_ecs::component::Component)]
76#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
77pub struct TagDef;
78
79universe::impl_universe_member_for_single_component_type!(TagDef);
80
81impl universe::VisitHandles for TagDef {
82    fn visit_handles(&self, _: &mut dyn universe::HandleVisitor) {
83        let &TagDef = self;
84        // No handles
85    }
86}
87
88impl transaction::Transactional for TagDef {
89    type Transaction = DefTransaction;
90}
91
92/// Transaction type for [`TagDef`].
93///
94/// Currently, there is nothing for it to do.
95#[non_exhaustive]
96#[derive(Clone, Debug, Eq, PartialEq)]
97pub enum DefTransaction {}
98
99impl transaction::Merge for DefTransaction {
100    type MergeCheck = ();
101    type Conflict = Infallible;
102
103    fn check_merge(&self, _: &Self) -> Result<Self::MergeCheck, Self::Conflict> {
104        match *self {}
105    }
106
107    fn commit_merge(&mut self, _: Self, (): Self::MergeCheck) {
108        match *self {}
109    }
110}
111
112impl transaction::Transaction for DefTransaction {
113    type Target = TagDef;
114    // This ReadTicket is not currently used, but at least for now, *all* universe member transactions are to have ReadTicket as their context type.
115    type Context<'a> = universe::ReadTicket<'a>;
116    type CommitCheck = ();
117    type Output = transaction::NoOutput;
118    type Mismatch = Infallible;
119
120    fn check(
121        &self,
122        _: &Self::Target,
123        _: Self::Context<'_>,
124    ) -> Result<Self::CommitCheck, Self::Mismatch> {
125        match *self {}
126    }
127
128    fn commit(
129        self,
130        _: &mut Self::Target,
131        (): Self::CommitCheck,
132        _: &mut dyn FnMut(Self::Output),
133    ) -> Result<(), transaction::CommitError> {
134        match self {}
135    }
136}
137
138impl universe::TransactionOnEcs for DefTransaction {
139    type WriteQueryData = &'static mut Self::Target;
140
141    fn check(
142        &self,
143        target: &TagDef,
144        read_ticket: universe::ReadTicket<'_>,
145    ) -> Result<Self::CommitCheck, Self::Mismatch> {
146        transaction::Transaction::check(self, target, read_ticket)
147    }
148
149    fn commit(
150        self,
151        mut target: ecs::Mut<'_, TagDef>,
152        check: Self::CommitCheck,
153    ) -> Result<(), transaction::CommitError> {
154        transaction::Transaction::commit(self, &mut *target, check, &mut transaction::no_outputs)
155    }
156}