1use std::{collections::HashMap, fmt::Debug, fs::{self, File}, io::{BufReader, Cursor}, path::Path, sync::{Arc, RwLock}};
2
3
4use serde::Serialize;
5
6use crate::{PAK_FILE_VERSION, Pak, PakInner, btree::PakTreeBuilder, error::PakResult, index::{Indices, PakIndex, PakSearchable}, meta::{PakMeta, PakSizing}, pointer::{PakPointer, PakUntypedPointer}};
7
8pub struct PakBuilder {
14 chunks : Vec<PakVaultReference>,
15 size_in_bytes : u64,
16 vault : Vec<u8>,
17 name: String,
18 description: String,
19 author: String,
20 version : String,
21 extra : Vec<u8>
22}
23
24impl PakBuilder {
25 pub fn new() -> Self {
27 Self {
28 vault : Vec::new(),
29 chunks : Vec::new(),
30 size_in_bytes : 0,
31 name: String::new(),
32 description: String::new(),
33 author: String::new(),
34 extra : Vec::new(),
35 version : String::new()
36 }
37 }
38
39 pub fn pak_no_search<T>(&mut self, item : &T) -> PakResult<PakPointer> where T : Serialize {
41 let bytes = bincode::serialize(item)?;
42 let pointer = PakPointer::new_untyped(self.size_in_bytes, bytes.len() as u64);
43 self.size_in_bytes += bytes.len() as u64;
44 self.vault.extend(bytes);
45 self.chunks.push(PakVaultReference { pointer: pointer.clone(), indices: vec![] });
46 Ok(pointer)
47 }
48
49 pub fn pak<T>(&mut self, item : &T) -> PakResult<PakPointer> where T : Serialize + PakSearchable {
51 let mut indices = Indices::default();
52 item.get_indices(&mut indices);
53 let bytes = bincode::serialize(item)?;
54 let pointer = PakPointer::new_typed::<T>(self.size_in_bytes, bytes.len() as u64);
55 self.size_in_bytes += bytes.len() as u64;
56 self.vault.extend(bytes);
57 self.chunks.push(PakVaultReference { pointer: pointer.clone(), indices: indices.unwrap() });
58 Ok(pointer)
59 }
60
61 pub fn size(&self) -> u64 {
63 self.size_in_bytes
64 }
65
66 pub fn len(&self) -> usize {
68 self.chunks.len()
69 }
70
71 pub fn with_name(mut self, name: &str) -> Self {
73 self.name = name.to_string();
74 self
75 }
76
77 pub fn with_description(mut self, description: &str) -> Self {
79 self.description = description.to_string();
80 self
81 }
82
83 pub fn with_author(mut self, author: &str) -> Self {
85 self.author = author.to_string();
86 self
87 }
88
89 pub fn set_name(&mut self, name: &str) {
91 self.name = name.to_string();
92 }
93
94 pub fn set_description(&mut self, description: &str) {
96 self.description = description.to_string();
97 }
98
99 pub fn set_author(&mut self, author: &str) {
101 self.author = author.to_string();
102 }
103
104 pub fn set_extra<T>(&mut self, value : &T) -> PakResult<()> where T : Serialize {
106 self.extra = bincode::serialize(value)?;
107 Ok(())
108 }
109
110 pub fn set_version(&mut self, version: String) {
112 self.version = version;
113 }
114
115 pub fn build_file(self, path : impl AsRef<Path>) -> PakResult<Pak> {
117 let (out, sizing, meta) = self.build_internal()?;
118
119 fs::write(&path, out)?;
120 let inner = Arc::new(PakInner {
121 sizing,
122 meta,
123 source: RwLock::new(Box::new(BufReader::new(File::open(path)?))),
124 });
125 let pak = Pak { inner };
126 Ok(pak)
127 }
128
129 pub fn build_in_memory(self) -> PakResult<Pak> {
131 let (out, sizing, meta) = self.build_internal()?;
132 let inner = Arc::new(PakInner {
133 sizing,
134 meta,
135 source: RwLock::new(Box::new(Cursor::new(out))),
136 });
137 let pak = Pak { inner };
138 Ok(pak)
139 }
140
141 fn build_internal(mut self) -> PakResult<(Vec<u8>, PakSizing, PakMeta)> {
142 let mut map : HashMap<String, PakTreeBuilder> = HashMap::new();
143 let mut list_values : HashMap<String, Vec<PakPointer>> = HashMap::new();
144 for chunk in &self.chunks {
145 for index in &chunk.indices{
146 map.entry(index.key.clone())
147 .or_insert(PakTreeBuilder::new(16))
148 .access()
149 .insert(index.value.clone(), chunk.pointer.clone())
150 ;
151 }
152 let mut ptr = chunk.pointer.clone();
153 ptr.drop_type();
154 list_values.entry(chunk.pointer.type_name().to_string())
155 .or_insert(Vec::new())
156 .push(ptr);
157 }
158
159 let mut pointer_map : HashMap<String, PakUntypedPointer> = HashMap::new();
160 for (key, tree) in map {
161 let pointer = tree.into_pak(&mut self)?;
162 pointer_map.insert(key, pointer.as_untyped());
163 }
164
165 let mut lists = HashMap::<String, PakPointer>::new();
166 for (type_name, list) in list_values.into_iter() {
167 let pointer = self.pak_no_search(&list)?;
168 lists.insert(type_name, pointer);
169 }
170
171 let hash = sha256::digest(self.vault.as_slice());
172 let meta = PakMeta {
173 identifier : format!("{hash}|{}|{}", self.name, self.version),
174 name: self.name,
175 description: self.description,
176 author: self.author,
177 version: self.version,
178 pak_version: PAK_FILE_VERSION.to_string(),
179 extra : self.extra
180 };
181
182
183 let sizing = PakSizing {
184 meta_size: bincode::serialized_size(&meta)?,
185 indices_size: bincode::serialized_size(&pointer_map)?,
186 vault_size: bincode::serialized_size(&self.vault)?,
187 list_size: bincode::serialized_size(&lists)?,
188 };
189
190 let mut sizing_out = bincode::serialize(&sizing)?;
191 let mut meta_out = bincode::serialize(&meta)?;
192 let mut pointer_map_out = bincode::serialize(&pointer_map)?;
193 let mut vault_out = bincode::serialize(&self.vault)?;
194 let mut list_out = bincode::serialize(&lists)?;
195
196 let mut out = Vec::<u8>::new();
197 out.append(&mut sizing_out);
198 out.append(&mut meta_out);
199 out.append(&mut pointer_map_out);
200 out.append(&mut list_out);
201 out.append(&mut vault_out);
202 Ok((out, sizing, meta))
203 }
204}
205
206#[derive(Debug, Clone)]
211pub(crate) struct PakVaultReference {
212 pointer : PakPointer,
213 indices : Vec<PakIndex>
214}