Skip to main content

tiger_lib/
block.rs

1//! [`Block`] is the core type to represent Pdx script code
2
3use crate::date::Date;
4use crate::macros::MACRO_MAP;
5use crate::parse::pdxfile::{MacroComponent, MacroComponentKind, PdxfileMemory, parse_pdx_macro};
6use crate::token::{Loc, Token};
7
8mod blockitem;
9mod bv;
10mod comparator;
11mod field;
12
13pub use crate::block::blockitem::BlockItem;
14pub use crate::block::bv::BV;
15pub use crate::block::comparator::{Comparator, Eq};
16pub use crate::block::field::Field;
17
18/// This type represents the most basic structural element of Pdx script code.
19/// Blocks are delimited by `{` and `}`. An entire file is also a `Block`.
20///
21/// A `Block` can contain a mix of these kinds of items:
22///
23/// * Assignments: `key = value`
24/// * Definitions: `key = { ... }`
25/// * Loose sub-blocks: `{ ... } { ... } ...`
26/// * Loose values: `value value ...`
27/// * Comparisons: `key < value` for a variety of comparators, including `=` for equality
28/// * `key < { ... }` is accepted by the parser but is not used anywhere
29///
30/// The same key can occur multiple times in a block. If a single field is requested and its key
31/// occurs multiple times, the last instance is returned (which is how the game usually resolves
32/// this).
33#[derive(Clone, Debug)]
34pub struct Block {
35    /// The contents of this block.
36    v: Vec<BlockItem>,
37    /// The `tag` is a short string that precedes a block, as in `color = hsv { 0.5 0.5 1.0 }`.
38    /// Only a small number of hardcoded tags are parsed this way.
39    /// It is in a `Box` to save space in blocks that don't have a tag, which is most of them.
40    pub tag: Option<Box<Token>>,
41    /// The location of the start of the block. Used mostly for error reporting.
42    pub loc: Loc,
43    /// If the block is a top-level block and contains macro substitutions, this field will
44    /// hold the original source for re-parsing.
45    /// The source has already been split into a vec that alternates content with macro parameters.
46    /// It is in a `Box` to save space (80 bytes) from blocks that don't contain macro substitutions,
47    /// which is most of them.
48    pub source: Option<Box<(Vec<MacroComponent>, PdxfileMemory)>>,
49}
50
51impl Block {
52    /// Open a new `Block` at the given location.
53    pub fn new(loc: Loc) -> Self {
54        Block { v: Vec::new(), tag: None, loc, source: None }
55    }
56
57    /// Add a loose value to this `Block`. Mostly used by the parser.
58    #[allow(dead_code)]
59    pub fn add_value(&mut self, value: Token) {
60        self.v.push(BlockItem::Value(value));
61    }
62
63    /// Add a loose sub-block to this `Block`. Mostly used by the parser.
64    #[allow(dead_code)]
65    pub fn add_block(&mut self, block: Block) {
66        self.v.push(BlockItem::Block(block));
67    }
68
69    /// Add a `key = value` or `key = { ... }` field to this `Block`.
70    /// Mostly used by the parser.
71    #[allow(dead_code)] // used only by json parser
72    pub fn add_key_bv(&mut self, key: Token, cmp: Comparator, value: BV) {
73        self.v.push(BlockItem::Field(Field(key, cmp, value)));
74    }
75
76    /// Add a `BlockItem` to this `Block`.
77    /// It can contain any of the variations of things that a `Block` can hold.
78    pub fn add_item(&mut self, item: BlockItem) {
79        self.v.push(item);
80    }
81
82    /// Add a `BlockItem` to this `Block`.
83    /// If it is a `BlockItem::Block` and the previous item is a `key = tag`,
84    /// where the tag is one of a predefined set of strings, then combine
85    /// the block with that previous item.
86    pub fn add_item_check_tag(&mut self, item: BlockItem) {
87        if let BlockItem::Block(mut block) = item {
88            if let Some(BlockItem::Field(Field(key, cmp, BV::Value(value)))) = self.v.last()
89                && (value.is("hsv")
90                    || value.is("rgb")
91                    || value.is("hsv360")
92                    || value.is("cylindrical")
93                    || value.is("cartesian"))
94            {
95                let key = key.clone();
96                let cmp = *cmp;
97                block.tag = Some(Box::new(value.clone()));
98                self.v.pop();
99                self.v.push(BlockItem::Field(Field(key, cmp, BV::Block(block))));
100                return;
101            }
102            self.v.push(BlockItem::Block(block));
103        } else {
104            self.v.push(item);
105        }
106    }
107
108    /// Combine two blocks by adding the contents of `other` to this block.
109    /// To avoid lots of cloning, `other` will be emptied in the process.
110    #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5"))]
111    pub fn append(&mut self, other: &mut Block) {
112        self.v.append(&mut other.v);
113    }
114
115    /// Get the value of a single `name = value` assignment.
116    pub fn get_field_value(&self, name: &str) -> Option<&Token> {
117        for item in self.v.iter().rev() {
118            if let BlockItem::Field(Field(key, _, bv)) = item
119                && key.is(name)
120            {
121                match bv {
122                    BV::Value(t) => return Some(t),
123                    BV::Block(_) => (),
124                }
125            }
126        }
127        None
128    }
129
130    /// Check if `name` is a field that has the literal string `value` as its value.
131    pub fn field_value_is(&self, name: &str, value: &str) -> bool {
132        if let Some(token) = self.get_field_value(name) { token.is(value) } else { false }
133    }
134
135    /// Get the value of a literal boolean field
136    pub fn get_field_bool(&self, name: &str) -> Option<bool> {
137        self.get_field_value(name).map(|t| t.is("yes"))
138    }
139
140    /// Get the value of a literal integer field
141    #[allow(dead_code)] // Not used by all games
142    pub fn get_field_integer(&self, name: &str) -> Option<i64> {
143        self.get_field_value(name).and_then(Token::get_integer)
144    }
145
146    /// Get the value of a literal date field
147    #[allow(dead_code)] // Not used by all games
148    pub fn get_field_date(&self, name: &str) -> Option<Date> {
149        self.get_field_value(name).and_then(Token::get_date)
150    }
151
152    /// Get all the values of `name = value` assignments in this block
153    ///
154    /// TODO: should be an iterator
155    pub fn get_field_values(&self, name: &str) -> Vec<&Token> {
156        let mut vec = Vec::new();
157        for (key, token) in self.iter_assignments() {
158            if key.is(name) {
159                vec.push(token);
160            }
161        }
162        vec
163    }
164
165    /// Get the block of a `name = { ... }` definition
166    pub fn get_field_block(&self, name: &str) -> Option<&Block> {
167        for item in self.v.iter().rev() {
168            if let BlockItem::Field(Field(key, _, bv)) = item
169                && key.is(name)
170            {
171                match bv {
172                    BV::Value(_) => (),
173                    BV::Block(b) => return Some(b),
174                }
175            }
176        }
177        None
178    }
179
180    /// Get all the blocks of `name = { ... }` definitions in this block
181    pub fn get_field_blocks(&self, name: &str) -> Vec<&Block> {
182        let mut vec = Vec::new();
183        for (key, block) in self.iter_definitions() {
184            if key.is(name) {
185                vec.push(block);
186            }
187        }
188        vec
189    }
190
191    /// Get the values of a single `name = { value value ... }` list
192    pub fn get_field_list(&self, name: &str) -> Option<Vec<Token>> {
193        for item in self.v.iter().rev() {
194            if let BlockItem::Field(Field(key, _, bv)) = item
195                && key.is(name)
196            {
197                match bv {
198                    BV::Value(_) => (),
199                    BV::Block(b) => {
200                        return Some(b.iter_values().cloned().collect());
201                    }
202                }
203            }
204        }
205        None
206    }
207
208    /// Get the combined values of any number of `name = { value value ... }` list
209    #[allow(dead_code)] // not used by all games
210    pub fn get_multi_field_list(&self, name: &str) -> Vec<Token> {
211        let mut vec = Vec::new();
212        for item in &self.v {
213            if let BlockItem::Field(Field(key, _, bv)) = item
214                && key.is(name)
215            {
216                match bv {
217                    BV::Value(_) => (),
218                    BV::Block(b) => {
219                        vec.extend(b.iter_values().cloned());
220                    }
221                }
222            }
223        }
224        vec
225    }
226
227    /// Get the value or block on the right-hand side of a field `name`.
228    pub fn get_field(&self, name: &str) -> Option<&BV> {
229        for item in self.v.iter().rev() {
230            if let BlockItem::Field(Field(key, _, bv)) = item
231                && key.is(name)
232            {
233                return Some(bv);
234            }
235        }
236        None
237    }
238
239    /// Get the key of a field `name` in the `Block`. The string value of the key will be equal to
240    /// `name`, but it can be useful to get this key as a `Token` with its location.
241    pub fn get_key(&self, name: &str) -> Option<&Token> {
242        for item in self.v.iter().rev() {
243            if let BlockItem::Field(Field(key, _, _)) = item
244                && key.is(name)
245            {
246                return Some(key);
247            }
248        }
249        None
250    }
251
252    /// Get all the keys of fields with key `name`. The string values of these keys will be equal
253    /// to `name`, but it can be useful to get these keys as `Token` with their locations.
254    pub fn get_keys(&self, name: &str) -> Vec<&Token> {
255        let mut vec = Vec::new();
256        for Field(key, _, _) in self.iter_fields() {
257            if key.is(name) {
258                vec.push(key);
259            }
260        }
261        vec
262    }
263
264    /// Return true iff the `name` occurs in this block at least once as a field key.
265    pub fn has_key(&self, name: &str) -> bool {
266        self.get_key(name).is_some()
267    }
268
269    #[cfg(feature = "vic3")]
270    pub fn has_key_recursive(&self, name: &str) -> bool {
271        for item in &self.v {
272            match item {
273                BlockItem::Field(Field(key, _, bv)) => {
274                    if key.is(name) {
275                        return true;
276                    }
277                    if let Some(block) = bv.get_block()
278                        && block.has_key_recursive(name)
279                    {
280                        return true;
281                    }
282                }
283                BlockItem::Block(block) => {
284                    if block.has_key_recursive(name) {
285                        return true;
286                    }
287                }
288                BlockItem::Value(_) => (),
289            }
290        }
291        false
292    }
293
294    /// Return the number of times `name` occurs in this block as a field key.
295    #[allow(dead_code)] // Not used by all games
296    pub fn count_keys(&self, name: &str) -> usize {
297        let mut count = 0;
298        for Field(key, _, _) in self.iter_fields() {
299            if key.is(name) {
300                count += 1;
301            }
302        }
303        count
304    }
305
306    /// Return the number of items in this block.
307    pub fn num_items(&self) -> usize {
308        self.v.len()
309    }
310
311    /// Return an iterator over the contents of this block.
312    pub fn iter_items(&self) -> std::slice::Iter<'_, BlockItem> {
313        self.v.iter()
314    }
315
316    /// Return a destructive iterator over the contents of this block.
317    /// It will give ownership of the returned `BlockItem` objects.
318    pub fn drain(&mut self) -> std::vec::Drain<'_, BlockItem> {
319        self.v.drain(..)
320    }
321
322    /// Return an iterator over all the `key = ...` fields in this block, ignoring the loose values
323    /// and loose blocks.
324    pub fn iter_fields(&self) -> IterFields<'_> {
325        IterFields { iter: self.v.iter(), warn: false }
326    }
327
328    /// Return an iterator over all the `key = ...` fields in this block, while warning about loose values
329    /// and loose blocks.
330    #[allow(dead_code)] // Not used by all games
331    pub fn iter_fields_warn(&self) -> IterFields<'_> {
332        IterFields { iter: self.v.iter(), warn: true }
333    }
334
335    /// Return an iterator over all the `key = value` fields in this block, ignoring other kinds of contents.
336    pub fn iter_assignments(&self) -> IterAssignments<'_> {
337        IterAssignments { iter: self.v.iter(), warn: false }
338    }
339
340    /// Return an iterator over all the `key = value` fields in this block, while warning about
341    /// every other kind of content.
342    #[allow(dead_code)] // It's here for symmetry
343    pub fn iter_assignments_warn(&self) -> IterAssignments<'_> {
344        IterAssignments { iter: self.v.iter(), warn: true }
345    }
346
347    /// Return an iterator over all the `key = { ... }` fields in this block, ignoring other kinds of contents.
348    pub fn iter_definitions(&self) -> IterDefinitions<'_> {
349        IterDefinitions { iter: self.v.iter(), warn: false }
350    }
351
352    /// Return an iterator over all the `key = { ... }` fields in this block, while warning about
353    /// every other kind of content.
354    pub fn iter_definitions_warn(&self) -> IterDefinitions<'_> {
355        IterDefinitions { iter: self.v.iter(), warn: true }
356    }
357
358    /// Return an iterator over all the `key = value` and `key = { ... }` fields in this block,
359    /// ignoring every other kind of content.
360    /// It differs from [`Block::iter_fields`] in that it requires the comparator to be `=`.
361    #[allow(dead_code)] // It's here for symmetry
362    pub fn iter_assignments_and_definitions(&self) -> IterAssignmentsAndDefinitions<'_> {
363        IterAssignmentsAndDefinitions { iter: self.v.iter(), warn: false }
364    }
365
366    /// Return an iterator over all the `key = value` and `key = { ... }` fields in this block,
367    /// while warning about every other kind of content.
368    /// It differs from [`Block::iter_fields_warn`] in that it requires the comparator to be `=`.
369    pub fn iter_assignments_and_definitions_warn(&self) -> IterAssignmentsAndDefinitions<'_> {
370        IterAssignmentsAndDefinitions { iter: self.v.iter(), warn: true }
371    }
372
373    /// Like [`Block::iter_definitions_warn`] but it's a destructive iterator that gives ownership
374    /// over the returned definitions.
375    pub fn drain_definitions_warn(&mut self) -> DrainDefinitions<'_> {
376        DrainDefinitions { iter: self.v.drain(..) }
377    }
378
379    /// Like [`Block::iter_assignments_warn`] but it's a destructive iterator that gives ownership
380    /// over the returned assignments.
381    #[allow(dead_code)] // Not used by all games
382    pub fn drain_assignments_warn(&mut self) -> DrainAssignments<'_> {
383        DrainAssignments { iter: self.v.drain(..) }
384    }
385
386    /// Iterate over the loose values in the block.
387    pub fn iter_values(&self) -> IterValues<'_> {
388        IterValues { iter: self.v.iter(), warn: false }
389    }
390
391    /// Iterate over the loose values in the block, while warning about everything else.
392    pub fn iter_values_warn(&self) -> IterValues<'_> {
393        IterValues { iter: self.v.iter(), warn: true }
394    }
395
396    /// Iterate over the loose sub-blocks in the block.
397    #[allow(dead_code)]
398    pub fn iter_blocks(&self) -> IterBlocks<'_> {
399        IterBlocks { iter: self.v.iter(), warn: false }
400    }
401
402    /// Iterate over the loose sub-blocks in the block, while warning about everything else.
403    #[allow(dead_code)] // It's here for symmetry
404    pub fn iter_blocks_warn(&self) -> IterBlocks<'_> {
405        IterBlocks { iter: self.v.iter(), warn: true }
406    }
407
408    /// Search through the history fields in this block and return the block or value the
409    /// field `name` would have at the given `date`. The field value that's directly in this block,
410    /// not in any history block, is considered to be the field value at the beginning of time.
411    /// History fields are ones that have a date as the key, like `900.1.1 = { ... }`.
412    #[allow(dead_code)] // Not used by all games
413    pub fn get_field_at_date(&self, name: &str, date: Date) -> Option<&BV> {
414        let mut found_date: Option<Date> = None;
415        let mut found: Option<&BV> = None;
416
417        for Field(key, _, bv) in self.iter_fields() {
418            if key.is(name) && found_date.is_none() {
419                found = Some(bv);
420            } else if let Ok(isdate) = Date::try_from(key)
421                && isdate <= date
422                && (found_date.is_none() || found_date.unwrap() < isdate)
423                && let Some(value) = bv.get_block().and_then(|b| b.get_field(name))
424            {
425                found_date = Some(isdate);
426                found = Some(value);
427            }
428        }
429        found
430    }
431
432    /// Just like [`Block::get_field_at_date`] but only for fields that have values (not blocks).
433    #[allow(dead_code)] // Not used by all games
434    pub fn get_field_value_at_date(&self, name: &str, date: Date) -> Option<&Token> {
435        self.get_field_at_date(name, date).and_then(BV::get_value)
436    }
437
438    /// Return a sorted vector of macro parameters taken by this block.
439    /// Macro parameters are between `$` like `$CHARACTER$`.
440    pub fn macro_parms(&self) -> Vec<&'static str> {
441        if let Some(block_source) = &self.source {
442            let (ref source, _) = **block_source;
443            let mut vec = source
444                .iter()
445                .filter(|mc| mc.kind() == MacroComponentKind::Macro)
446                .map(|mc| mc.token().as_str())
447                .collect::<Vec<_>>();
448            vec.sort_unstable();
449            vec.dedup();
450            vec
451        } else {
452            Vec::new()
453        }
454    }
455
456    /// Expand a block that has macro parameters by substituting arguments for those parameters,
457    /// then re-parsing the script, that links the expanded content back to `loc`.
458    pub fn expand_macro(
459        &self,
460        args: &[(&str, Token)],
461        loc: Loc,
462        global: &PdxfileMemory,
463    ) -> Option<Block> {
464        let link_index = MACRO_MAP.get_or_insert_loc(loc);
465        if let Some(block_source) = &self.source {
466            let (ref source, ref local) = **block_source;
467            let mut content = Vec::new();
468            for part in source {
469                let token = part.token();
470                match part.kind() {
471                    MacroComponentKind::Source => {
472                        content.push(token.clone().linked(Some(link_index)));
473                    }
474                    MacroComponentKind::Macro => {
475                        for (arg, val) in args {
476                            if token.is(arg) {
477                                // Make the replacement be a token that has the substituted content, but the original's loc,
478                                // and a loc.link back to the caller's parameter. This gives the best error messages.
479                                let mut val = val.clone();
480                                let orig_loc = val.loc;
481                                val.loc = token.loc;
482                                val.loc.column -= 1; // point at the $, it looks better
483                                val.loc.link_idx = Some(MACRO_MAP.get_or_insert_loc(orig_loc));
484                                content.push(val);
485                                break;
486                            }
487                        }
488                    }
489                }
490            }
491            Some(parse_pdx_macro(&content, global, local))
492        } else {
493            None
494        }
495    }
496
497    /// Return true iff this block has the same block items in the same order as `other`,
498    /// including equivalence of blocks inside them.
499    pub fn equivalent(&self, other: &Self) -> bool {
500        if self.v.len() != other.v.len() {
501            return false;
502        }
503        for i in 0..self.v.len() {
504            if !self.v[i].equivalent(&other.v[i]) {
505                return false;
506            }
507        }
508        true
509    }
510
511    /// Create a version of this block where the `tag` is combined with a token that follows it.
512    /// Example: `color1 = list colorlist` becomes `color1 = list"colorlist` (where the `"` character
513    /// is used as the separator because it can't show up in normal parsing).
514    ///
515    /// This function is used as a last resort when validating awkward syntax.
516    #[allow(dead_code)]
517    pub fn condense_tag(self, tag: &str) -> Self {
518        let mut other = Block::new(self.loc);
519        let mut reserve: Option<(Token, Comparator, Token)> = None;
520        for item in self.v {
521            if let Some((rkey, rcmp, mut rtoken)) = reserve {
522                if let BlockItem::Value(token) = item {
523                    // Combine current value with reserved assignment
524                    rtoken.combine(&token, '"');
525                    other.add_key_bv(rkey, rcmp, BV::Value(rtoken));
526                    reserve = None;
527                    // This consumed the current item
528                    continue;
529                }
530                other.add_key_bv(rkey, rcmp, BV::Value(rtoken));
531                reserve = None;
532            }
533            if let BlockItem::Field(Field(key, cmp, bv)) = item {
534                match bv {
535                    BV::Value(token) => {
536                        if token.is(tag) {
537                            reserve = Some((key, cmp, token));
538                            continue;
539                        }
540                        other.add_key_bv(key, cmp, BV::Value(token));
541                    }
542                    BV::Block(block) => {
543                        other.add_key_bv(key, cmp, BV::Block(block.condense_tag(tag)));
544                    }
545                }
546            } else {
547                other.add_item(item);
548            }
549        }
550        other
551    }
552}
553
554/// An iterator for (key, value) pairs. It is returned by [`Block::iter_assignments`].
555#[derive(Clone, Debug)]
556pub struct IterAssignments<'a> {
557    iter: std::slice::Iter<'a, BlockItem>,
558    warn: bool,
559}
560
561impl<'a> Iterator for IterAssignments<'a> {
562    type Item = (&'a Token, &'a Token);
563
564    fn next(&mut self) -> Option<Self::Item> {
565        for item in self.iter.by_ref() {
566            if self.warn {
567                item.expect_assignment();
568            }
569            if let Some((key, token)) = item.get_assignment() {
570                return Some((key, token));
571            }
572        }
573        None
574    }
575}
576
577/// An iterator for (key, block) pairs. It is returned by [`Block::iter_definitions`].
578#[derive(Clone, Debug)]
579pub struct IterDefinitions<'a> {
580    iter: std::slice::Iter<'a, BlockItem>,
581    warn: bool,
582}
583
584impl<'a> Iterator for IterDefinitions<'a> {
585    type Item = (&'a Token, &'a Block);
586
587    fn next(&mut self) -> Option<Self::Item> {
588        for item in self.iter.by_ref() {
589            if self.warn {
590                item.expect_definition();
591            }
592            if let Some((key, block)) = item.get_definition() {
593                return Some((key, block));
594            }
595        }
596        None
597    }
598}
599
600/// An iterator for (key, bv) pairs. It is returned by [`Block::iter_assignments_and_definitions`].
601#[derive(Clone, Debug)]
602pub struct IterAssignmentsAndDefinitions<'a> {
603    iter: std::slice::Iter<'a, BlockItem>,
604    warn: bool,
605}
606
607impl<'a> Iterator for IterAssignmentsAndDefinitions<'a> {
608    type Item = (&'a Token, &'a BV);
609
610    fn next(&mut self) -> Option<Self::Item> {
611        for item in self.iter.by_ref() {
612            if self.warn {
613                item.expect_field();
614            }
615            if let BlockItem::Field(field) = item {
616                if !field.is_eq() {
617                    if self.warn {
618                        field.expect_eq();
619                    }
620                    continue;
621                }
622                return Some((field.key(), field.bv()));
623            }
624        }
625        None
626    }
627}
628
629/// An iterator for (key, block) pairs that transfers ownership.
630/// It is returned by [`Block::drain_definitions_warn`].
631#[derive(Debug)]
632pub struct DrainDefinitions<'a> {
633    iter: std::vec::Drain<'a, BlockItem>,
634}
635
636impl Iterator for DrainDefinitions<'_> {
637    type Item = (Token, Block);
638
639    fn next(&mut self) -> Option<Self::Item> {
640        for item in self.iter.by_ref() {
641            if let Some((key, block)) = item.expect_into_definition() {
642                return Some((key, block));
643            }
644        }
645        None
646    }
647}
648
649/// An iterator for (key, value) pairs that transfers ownership.
650/// It is returned by [`Block::drain_assignments_warn`].
651#[derive(Debug)]
652pub struct DrainAssignments<'a> {
653    iter: std::vec::Drain<'a, BlockItem>,
654}
655
656impl Iterator for DrainAssignments<'_> {
657    type Item = (Token, Token);
658
659    fn next(&mut self) -> Option<Self::Item> {
660        for item in self.iter.by_ref() {
661            if let Some((key, value)) = item.expect_into_assignment() {
662                return Some((key, value));
663            }
664        }
665        None
666    }
667}
668
669/// An iterator for [`Field`] structs, returning the fields of a block.
670/// It is returned by [`Block::iter_fields`].
671#[derive(Clone, Debug)]
672pub struct IterFields<'a> {
673    iter: std::slice::Iter<'a, BlockItem>,
674    warn: bool,
675}
676
677impl<'a> Iterator for IterFields<'a> {
678    type Item = &'a Field;
679
680    fn next(&mut self) -> Option<Self::Item> {
681        for item in self.iter.by_ref() {
682            if self.warn {
683                item.expect_field();
684            }
685            if let BlockItem::Field(field) = item {
686                return Some(field);
687            }
688        }
689        None
690    }
691}
692
693/// An iterator for values (tokens), returning the loose values of a block.
694/// It is returned by [`Block::iter_values`].
695#[derive(Clone, Debug)]
696pub struct IterValues<'a> {
697    iter: std::slice::Iter<'a, BlockItem>,
698    warn: bool,
699}
700
701impl<'a> Iterator for IterValues<'a> {
702    type Item = &'a Token;
703
704    fn next(&mut self) -> Option<Self::Item> {
705        for item in self.iter.by_ref() {
706            if self.warn {
707                item.expect_value();
708            }
709            if let BlockItem::Value(value) = item {
710                return Some(value);
711            }
712        }
713        None
714    }
715}
716
717/// An iterator returning the loose sub-blocks of a block.
718/// It is returned by [`Block::iter_blocks`].
719#[derive(Clone, Debug)]
720pub struct IterBlocks<'a> {
721    iter: std::slice::Iter<'a, BlockItem>,
722    warn: bool,
723}
724
725impl<'a> Iterator for IterBlocks<'a> {
726    type Item = &'a Block;
727
728    fn next(&mut self) -> Option<Self::Item> {
729        for item in self.iter.by_ref() {
730            if self.warn {
731                item.expect_block();
732            }
733            if let BlockItem::Block(block) = item {
734                return Some(block);
735            }
736        }
737        None
738    }
739}