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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::{DataSource, Error, Result};
use hff_core::Ecc;

mod table_array;
pub(crate) use table_array::TableArray;

mod chunk_array;
pub(crate) use chunk_array::ChunkArray;

mod data_array;
pub(crate) use data_array::DataArray;

mod chunk_desc;
pub(crate) use chunk_desc::ChunkDesc;

mod table_desc;
pub(crate) use table_desc::TableDesc;

mod table_builder;
pub(crate) use table_builder::TableBuilder;

mod hff_content;
pub use hff_content::HffContent;

/// Start building a new table.
pub fn table(primary: impl Into<Ecc>, secondary: impl Into<Ecc>) -> TableBuilder {
    TableBuilder::new(primary.into(), secondary.into())
}

/// Build a new chunk.
pub fn chunk<T>(primary: impl Into<Ecc>, secondary: impl Into<Ecc>, content: T) -> Result<ChunkDesc>
where
    T: TryInto<Box<dyn DataSource>>,
    <T as TryInto<Box<dyn DataSource>>>::Error: std::fmt::Debug,
    Error: From<<T as TryInto<Box<dyn DataSource>>>::Error>,
{
    Ok(ChunkDesc::new(
        primary.into(),
        secondary.into(),
        content.try_into()?,
    ))
}

/// Build the structure of the Hff content.
pub fn hff(tables: impl IntoIterator<Item = TableBuilder>) -> HffContent {
    // Split the tables into their components.
    let mut table_array = TableArray::new();
    let mut chunk_array = ChunkArray::new();
    let mut data_array = DataArray::new();

    // Collect the tables into a vector so we know the length.
    let tables = tables
        .into_iter()
        .map(|desc| desc.finish())
        .collect::<Vec<_>>();

    let table_count = tables.len();
    for (index, table) in tables.into_iter().enumerate() {
        // Determine if this table has a sibling.
        let has_sibling = index < table_count - 1;
        // And flatten the table.
        table.flatten(
            has_sibling,
            &mut table_array,
            &mut chunk_array,
            &mut data_array,
        );
    }
    HffContent::new(table_array, chunk_array, data_array)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let content = hff([
            table("p0", "s0")
                .metadata("123")
                .unwrap()
                .children([table("p1", "s1")
                    .metadata("1234")
                    .unwrap()
                    .chunks([
                        chunk("c0", "cs0", "chunk 0").unwrap(),
                        chunk("c1", "cs1", "chunk 1").unwrap(),
                        chunk("c2", "cs2", "chunk 2").unwrap(),
                    ])
                    .children([
                        table("p2", "s2").metadata("12345").unwrap().chunks([]),
                        table("p3", "s3").metadata("123456").unwrap().chunks([]),
                    ])])
                .chunks([]),
            table("p4", "s4").metadata("1234567").unwrap(),
            table("p5", "s5")
                .metadata("12345678")
                .unwrap()
                .chunks([chunk("c3", "cs3", "chunk 3").unwrap()]),
        ]);

        let mut buffer = vec![];
        content.write::<hff_core::LE>("Test", &mut buffer).unwrap();

        let (hff, _cache) = crate::read_stream_full(&mut buffer.as_slice()).unwrap();
        println!("{:#?}", hff);
        println!("-----------------------------");
        for (depth, table) in hff.depth_first() {
            println!("-- <{}>: <{:?}>", depth, table);
        }
        println!("-----------------------------");

        //assert!(false);
    }
}