aboutsummaryrefslogtreecommitdiff
path: root/matroska/src/unflatten.rs
blob: a9bc5ccf0379e3af0779a3ac87ad2b0237987b00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2025 metamuffin <metamuffin.org>
*/
use crate::{matroska::MatroskaTag, Master, Result};

pub struct Unflat<'a> {
    pub item: MatroskaTag,
    pub children: Option<Unflatten<'a>>,
    pub position: Option<u64>,
}

pub struct Unflatten<'a> {
    inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>,
    stop: bool,
    end: Option<MatroskaTag>,
}

impl<'a> Unflatten<'a> {
    pub fn new(inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>) -> Self {
        Self {
            inner,
            stop: false,
            end: None,
        }
    }
    pub fn new_with_end(
        inner: &'a mut dyn Iterator<Item = Result<(Option<u64>, MatroskaTag)>>,
        start: MatroskaTag,
    ) -> Self {
        Self {
            inner,
            stop: false,
            end: Some(MatroskaTag::construct_master(start.id(), Master::End).unwrap()),
        }
    }
    pub fn exit_dirty(&mut self) {
        self.stop = true;
    }

    pub fn n(&mut self) -> Option<Result<Unflat>> {
        if self.stop {
            return None;
        }
        match self.inner.next() {
            None => None,
            Some(Err(e)) => Some(Err(e)),
            Some(Ok((position, item))) => {
                let master = MatroskaTag::is_master(item.id()).unwrap();
                if Some(&item) == self.end.as_ref() {
                    self.stop = true;
                    None
                } else {
                    Some(Ok(Unflat {
                        position,
                        children: if master {
                            let end =
                                MatroskaTag::construct_master(item.id(), Master::End).unwrap();
                            if end == item {
                                return None;
                            }
                            Some(Unflatten {
                                inner: self.inner,
                                stop: false,
                                end: Some(end),
                            })
                        } else {
                            None
                        },
                        item,
                    }))
                }
            }
        }
    }
}

impl Drop for Unflatten<'_> {
    fn drop(&mut self) {
        while self.n().is_some() {}
    }
}