aboutsummaryrefslogtreecommitdiff
path: root/matroska/src/unflatten.rs
blob: 8f408195142377c10b3de37b239e69ca5434abf1 (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
84
85
86
87
88
89
90
91
92
93
94
95
96
/*
    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) 2023 metamuffin <metamuffin.org>
*/
use crate::{matroska::MatroskaTag, Master};
use crate::Result;


pub trait IterWithPos {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    fn position(&self) -> usize;
}

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

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

impl<'a> Unflatten<'a> {
    pub fn new(inner: &'a mut dyn IterWithPos<Item = Result<MatroskaTag>>) -> Self {
        Self {
            inner,
            stop: false,
            end: None,
        }
    }
    pub fn new_with_end(
        inner: &'a mut dyn IterWithPos<Item = Result<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 position(&self) -> usize {
        self.inner.position()
    }

    pub fn n(&mut self) -> Option<Result<Unflat>> {
        if self.stop {
            return None;
        }
        let position = self.inner.position();
        match self.inner.next() {
            None => None,
            Some(Err(e)) => Some(Err(e)),
            Some(Ok(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() {}
    }
}