1use std::{collections::HashMap, fmt::Debug, fs::{self, File}, io::{BufReader, Cursor}, path::Path, sync::RwLock};
2
3
4use crate::{PAK_FILE_VERSION, Pak, btree::PakTreeBuilder, error::PakResult, index::PakIndex, item::{PakItemDeserialize, PakItemSearchable, PakItemSerialize}, meta::{PakMeta, PakSizing}, pointer::{PakPointer, PakUntypedPointer}};
5
6pub struct PakBuilder {
12 chunks : Vec<PakVaultReference>,
13 size_in_bytes : u64,
14 vault : Vec<u8>,
15 name: String,
16 description: String,
17 author: String,
18}
19
20impl PakBuilder {
21 pub fn new() -> Self {
23 Self {
24 vault : Vec::new(),
25 chunks : Vec::new(),
26 size_in_bytes : 0,
27 name: String::new(),
28 description: String::new(),
29 author: String::new(),
30 }
31 }
32
33 pub fn pak_no_search<T: PakItemSerialize + Debug + PakItemDeserialize>(&mut self, item : T) -> PakResult<PakPointer> {
35 let bytes = item.into_bytes()?;
36 let pointer = PakPointer::new_untyped(self.size_in_bytes, bytes.len() as u64);
37 self.size_in_bytes += bytes.len() as u64;
38 self.vault.extend(bytes);
39 self.chunks.push(PakVaultReference { pointer: pointer.clone(), indices: vec![] });
40 Ok(pointer)
41 }
42
43 pub fn pak<T : PakItemSerialize + PakItemSearchable>(&mut self, item : T) -> PakResult<PakPointer> {
45 let indices = item.get_indices();
46 let bytes = item.into_bytes()?;
47 let pointer = PakPointer::new_typed::<T>(self.size_in_bytes, bytes.len() as u64);
48 self.size_in_bytes += bytes.len() as u64;
49 self.vault.extend(bytes);
50 self.chunks.push(PakVaultReference { pointer: pointer.clone(), indices: indices.clone() });
51 Ok(pointer)
52 }
53
54 pub fn size(&self) -> u64 {
56 self.size_in_bytes
57 }
58
59 pub fn len(&self) -> usize {
61 self.chunks.len()
62 }
63
64 pub fn with_name(mut self, name: &str) -> Self {
66 self.name = name.to_string();
67 self
68 }
69
70 pub fn with_description(mut self, description: &str) -> Self {
72 self.description = description.to_string();
73 self
74 }
75
76 pub fn with_author(mut self, author: &str) -> Self {
78 self.author = author.to_string();
79 self
80 }
81
82 pub fn set_name(&mut self, name: &str) {
84 self.name = name.to_string();
85 }
86
87 pub fn set_description(&mut self, description: &str) {
89 self.description = description.to_string();
90 }
91
92 pub fn set_author(&mut self, author: &str) {
94 self.author = author.to_string();
95 }
96
97 pub fn build_file(self, path : impl AsRef<Path>) -> PakResult<Pak> {
99 let (out, sizing, meta) = self.build_internal()?;
100
101 fs::write(&path, out)?;
102 let pak = Pak {
103 sizing,
104 meta,
105 source: RwLock::new(Box::new(BufReader::new(File::open(path)?))),
106 };
107 Ok(pak)
108 }
109
110 pub fn build_in_memory(self) -> PakResult<Pak> {
112 let (out, sizing, meta) = self.build_internal()?;
113
114 let pak = Pak {
115 sizing,
116 meta,
117 source: RwLock::new(Box::new(Cursor::new(out))),
118 };
119 Ok(pak)
120 }
121
122 fn build_internal(mut self) -> PakResult<(Vec<u8>, PakSizing, PakMeta)> {
123 let mut map : HashMap<String, PakTreeBuilder> = HashMap::new();
124 let mut list_values : HashMap<String, Vec<PakPointer>> = HashMap::new();
125 for chunk in &self.chunks {
126 for index in &chunk.indices{
127 map.entry(index.key.clone())
128 .or_insert(PakTreeBuilder::new(16))
129 .access()
130 .insert(index.value.clone(), chunk.pointer.clone())
131 ;
132 }
133 let mut ptr = chunk.pointer.clone();
134 ptr.drop_type();
135 list_values.entry(chunk.pointer.type_name().to_string())
136 .or_insert(Vec::new())
137 .push(ptr);
138 }
139
140 let mut pointer_map : HashMap<String, PakUntypedPointer> = HashMap::new();
141 for (key, tree) in map {
142 let pointer = tree.into_pak(&mut self)?;
143 pointer_map.insert(key, pointer.as_untyped());
144 }
145
146 let mut lists = HashMap::<String, PakPointer>::new();
147 for (type_name, list) in list_values.into_iter() {
148 let pointer = self.pak_no_search(list)?;
149 lists.insert(type_name, pointer);
150 }
151
152 let meta = PakMeta {
153 name: self.name,
154 description: self.description,
155 author: self.author,
156 version: PAK_FILE_VERSION.to_string(),
157 };
158
159 let sizing = PakSizing {
160 meta_size: bincode::serialized_size(&meta)?,
161 indices_size: bincode::serialized_size(&pointer_map)?,
162 vault_size: bincode::serialized_size(&self.vault)?,
163 list_size: bincode::serialized_size(&lists)?,
164 };
165
166 let mut sizing_out = bincode::serialize(&sizing)?;
167 let mut meta_out = bincode::serialize(&meta)?;
168 let mut pointer_map_out = bincode::serialize(&pointer_map)?;
169 let mut vault_out = bincode::serialize(&self.vault)?;
170 let mut list_out = bincode::serialize(&lists)?;
171
172 let mut out = Vec::<u8>::new();
173 out.append(&mut sizing_out);
174 out.append(&mut meta_out);
175 out.append(&mut pointer_map_out);
176 out.append(&mut list_out);
177 out.append(&mut vault_out);
178 Ok((out, sizing, meta))
179 }
180}
181
182#[derive(Debug, Clone)]
187pub(crate) struct PakVaultReference {
188 pointer : PakPointer,
189 indices : Vec<PakIndex>
190}