Skip to main content

steel_registry/data_component_predicate/
books.rs

1use super::{
2    CollectionPredicate, ComponentHasher, DataComponentPredicateCodec, Debug, DowncastType,
3    DowncastTypeKey, HashComponent, IntBounds, NbtCompound, NbtNumeric, NbtTag, TextComponent,
4    collection_field_nbt, decode_optional, hash_entries, hash_optional_collection_field,
5    owned_string, push_hash_entry,
6};
7
8/// Predicate for one writable-book page.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct WritableBookPagePredicate(String);
11
12impl WritableBookPagePredicate {
13    #[must_use]
14    pub const fn new(contents: String) -> Self {
15        Self(contents)
16    }
17
18    #[must_use]
19    pub fn contents(&self) -> &str {
20        &self.0
21    }
22
23    fn from_nbt_value(tag: &NbtTag) -> Option<Self> {
24        tag.string()?.to_owned().try_into_string().ok().map(Self)
25    }
26
27    fn to_nbt_value(&self) -> NbtTag {
28        NbtTag::String(self.0.clone().into())
29    }
30}
31
32impl HashComponent for WritableBookPagePredicate {
33    fn hash_component(&self, hasher: &mut ComponentHasher) {
34        self.0.hash_component(hasher);
35    }
36}
37
38/// Predicate over writable-book pages.
39#[derive(Debug, Clone, PartialEq)]
40pub struct WritableBookPredicate(Option<CollectionPredicate<WritableBookPagePredicate>>);
41
42impl WritableBookPredicate {
43    #[must_use]
44    pub const fn new(pages: Option<CollectionPredicate<WritableBookPagePredicate>>) -> Self {
45        Self(pages)
46    }
47
48    #[must_use]
49    pub const fn pages(&self) -> Option<&CollectionPredicate<WritableBookPagePredicate>> {
50        self.0.as_ref()
51    }
52}
53
54impl DataComponentPredicateCodec for WritableBookPredicate {
55    fn from_nbt_value(tag: &NbtTag) -> Option<Self> {
56        let compound = tag.compound()?;
57        decode_optional(compound, "pages", |tag| {
58            CollectionPredicate::from_nbt_with(tag, WritableBookPagePredicate::from_nbt_value)
59        })
60        .map(Self)
61    }
62
63    fn to_nbt_value(&self) -> NbtTag {
64        collection_field_nbt(
65            self.0.as_ref(),
66            "pages",
67            WritableBookPagePredicate::to_nbt_value,
68        )
69    }
70}
71
72impl HashComponent for WritableBookPredicate {
73    fn hash_component(&self, hasher: &mut ComponentHasher) {
74        hash_optional_collection_field(
75            self.0.as_ref(),
76            "pages",
77            hasher,
78            HashComponent::compute_hash,
79        );
80    }
81}
82
83impl_predicate_downcast_type!(
84    WritableBookPredicate,
85    "steel:data_component_predicate/writable_book_content"
86);
87
88/// Predicate for one written-book page.
89#[derive(Debug, Clone, PartialEq)]
90pub struct WrittenBookPagePredicate(TextComponent);
91
92impl WrittenBookPagePredicate {
93    #[must_use]
94    pub const fn new(contents: TextComponent) -> Self {
95        Self(contents)
96    }
97
98    #[must_use]
99    pub const fn contents(&self) -> &TextComponent {
100        &self.0
101    }
102
103    fn from_nbt_value(tag: &NbtTag) -> Option<Self> {
104        TextComponent::from_nbt(tag).map(Self)
105    }
106
107    fn to_nbt_value(&self) -> NbtTag {
108        self.0.to_codec_nbt()
109    }
110}
111
112impl HashComponent for WrittenBookPagePredicate {
113    fn hash_component(&self, hasher: &mut ComponentHasher) {
114        self.0.hash_component(hasher);
115    }
116}
117
118/// Predicate over written-book metadata and pages.
119#[derive(Debug, Clone, PartialEq)]
120pub struct WrittenBookPredicate {
121    pages: Option<CollectionPredicate<WrittenBookPagePredicate>>,
122    author: Option<String>,
123    title: Option<String>,
124    generation: IntBounds,
125    resolved: Option<bool>,
126}
127
128impl WrittenBookPredicate {
129    #[must_use]
130    pub const fn new(
131        pages: Option<CollectionPredicate<WrittenBookPagePredicate>>,
132        author: Option<String>,
133        title: Option<String>,
134        generation: IntBounds,
135        resolved: Option<bool>,
136    ) -> Self {
137        Self {
138            pages,
139            author,
140            title,
141            generation,
142            resolved,
143        }
144    }
145
146    #[must_use]
147    pub const fn pages(&self) -> Option<&CollectionPredicate<WrittenBookPagePredicate>> {
148        self.pages.as_ref()
149    }
150
151    #[must_use]
152    pub const fn author(&self) -> Option<&String> {
153        self.author.as_ref()
154    }
155
156    #[must_use]
157    pub const fn title(&self) -> Option<&String> {
158        self.title.as_ref()
159    }
160
161    #[must_use]
162    pub const fn generation(&self) -> IntBounds {
163        self.generation
164    }
165
166    #[must_use]
167    pub const fn resolved(&self) -> Option<bool> {
168        self.resolved
169    }
170}
171
172impl DataComponentPredicateCodec for WrittenBookPredicate {
173    fn from_nbt_value(tag: &NbtTag) -> Option<Self> {
174        let compound = tag.compound()?;
175        Some(Self {
176            pages: decode_optional(compound, "pages", |tag| {
177                CollectionPredicate::from_nbt_with(tag, WrittenBookPagePredicate::from_nbt_value)
178            })?,
179            author: decode_optional(compound, "author", owned_string)?,
180            title: decode_optional(compound, "title", owned_string)?,
181            generation: compound
182                .get("generation")
183                .map_or(Some(IntBounds::ANY), IntBounds::from_owned_nbt)?,
184            resolved: decode_optional(compound, "resolved", NbtNumeric::codec_bool)?,
185        })
186    }
187
188    fn to_nbt_value(&self) -> NbtTag {
189        let mut compound = NbtCompound::new();
190        if let Some(pages) = &self.pages {
191            compound.insert(
192                "pages",
193                pages.to_nbt_with(WrittenBookPagePredicate::to_nbt_value),
194            );
195        }
196        if let Some(author) = &self.author {
197            compound.insert("author", author.as_str());
198        }
199        if let Some(title) = &self.title {
200            compound.insert("title", title.as_str());
201        }
202        if !self.generation.is_any() {
203            compound.insert("generation", self.generation.as_nbt_tag());
204        }
205        if let Some(resolved) = self.resolved {
206            compound.insert("resolved", resolved);
207        }
208        NbtTag::Compound(compound)
209    }
210}
211
212impl HashComponent for WrittenBookPredicate {
213    fn hash_component(&self, hasher: &mut ComponentHasher) {
214        let mut entries = Vec::new();
215        if let Some(pages) = &self.pages {
216            let mut value_hasher = ComponentHasher::new();
217            pages.hash_with(&mut value_hasher, HashComponent::compute_hash);
218            crate::item_predicate::push_prehashed_entry(&mut entries, "pages", value_hasher);
219        }
220        if let Some(author) = &self.author {
221            push_hash_entry(&mut entries, "author", author);
222        }
223        if let Some(title) = &self.title {
224            push_hash_entry(&mut entries, "title", title);
225        }
226        if !self.generation.is_any() {
227            push_hash_entry(&mut entries, "generation", &self.generation);
228        }
229        if let Some(resolved) = self.resolved {
230            push_hash_entry(&mut entries, "resolved", &resolved);
231        }
232        hash_entries(hasher, &mut entries);
233    }
234}
235
236impl_predicate_downcast_type!(
237    WrittenBookPredicate,
238    "steel:data_component_predicate/written_book_content"
239);