1#![doc = include_str!("../README.md")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/MrVintage710/pak/refs/heads/main/docs/icon.png")]
3
4use std::{collections::HashMap, fs::File, io::{BufReader, Read, Seek, SeekFrom}, path::Path, sync::{RwLock, RwLockWriteGuard}};
5use btree::PakTree;
6use group::{DeserializeGroup};
7use meta::{PakMeta, PakSizing};
8use pointer::{PakPointer, PakUntypedPointer};
9use query::PakQueryExpression;
10use serde::Deserialize;
11
12use crate::{error::PakResult};
13
14#[cfg(test)]
15mod test;
16
17pub mod meta;
18pub mod group;
19pub mod index;
20pub mod value;
21pub(crate) mod btree;
22pub mod query;
23pub mod error;
24pub mod pointer;
25pub mod builder;
26
27pub const PAK_FILE_VERSION : &'static str = "1.1";
32
33pub const PAK_SIZING_STRUCT_SIZE_IN_BYTES : u64 = 32;
34
35pub struct Pak {
37 sizing : PakSizing,
38 meta : PakMeta,
39 source : RwLock<Box<dyn PakSource + Send + Sync + 'static>>
40}
41
42impl Pak {
43 pub fn new<S>(mut source : S) -> PakResult<Self> where S : PakSource + Send + Sync + 'static {
45 let sizing_pointer = PakPointer::new_untyped(0, PAK_SIZING_STRUCT_SIZE_IN_BYTES);
46 let sizing_buffer = source.read(&sizing_pointer, 0)?;
47 let sizing : PakSizing = bincode::deserialize(&sizing_buffer)?;
48
49 let meta_pointer = PakPointer::new_untyped(PAK_SIZING_STRUCT_SIZE_IN_BYTES, sizing.meta_size);
50 let meta_buffer = source.read(&meta_pointer, 0)?;
51 let meta : PakMeta = bincode::deserialize(&meta_buffer)?;
52
53 Ok(Self { sizing, source : RwLock::new(Box::new(source)), meta })
54 }
55
56 pub fn new_from_file<P>(path : P) -> PakResult<Self> where P : AsRef<Path> {
58 let file = File::open(path)?;
59 Self::new(BufReader::new(file))
60 }
61
62 pub fn query<T>(&self, query : impl PakQueryExpression<T>) -> PakResult<T::ReturnType> where T : DeserializeGroup {
64 let pointers = query.execute(self)?.into_iter().collect();
65 T::deserialize_group(self, pointers)
66 }
67
68 pub fn query_sql<T>(&self, pql : &str) -> PakResult<T::ReturnType> where T : DeserializeGroup + 'static {
70 let query = crate::query::pql::pql(pql)?;
71 self.query::<T>(query)
72 }
73
74 pub fn size(&self) -> u64 {
76 24 + self.sizing.meta_size + self.sizing.indices_size + self.sizing.vault_size
77 }
78
79 pub fn name(&self) -> &str {
81 &self.meta.name
82 }
83
84 pub fn version(&self) -> &str {
86 &self.meta.version
87 }
88
89 pub fn author(&self) -> &str {
91 &self.meta.author
92 }
93
94 pub fn description(&self) -> &str {
96 &self.meta.description
97 }
98
99 pub fn read_err<T>(&self, pointer : &PakPointer) -> PakResult<T> where T : for<'de> Deserialize<'de> {
100 if !pointer.type_is_match::<T>() { return Err(error::PakError::TypeMismatchError(pointer.type_name().to_string(), std::any::type_name::<T>().to_string())) }
101 let Ok(mut source) = self.source.write() else { return Err(error::PakError::SourceInUse)};
102 self.read_internal(pointer, &mut source)
103 }
104
105 pub fn read<T>(&self, pointer : &PakPointer) -> Option<T> where T : for<'de> Deserialize<'de> {
106 self.read_err::<T>(pointer).ok()
107 }
108
109 fn read_internal<T>(&self, pointer : &PakPointer, source : &mut RwLockWriteGuard<Box<dyn PakSource + Send + Sync + 'static>>) -> PakResult<T> where T : for<'de> Deserialize<'de> {
110 let buffer = source.read(pointer, self.get_vault_start())?;
111 let res = bincode::deserialize(&buffer)?;
112 Ok(res)
113 }
114
115 pub(crate) fn get_tree(&self, key : &str) -> PakResult<PakTree<'_>> {
116 PakTree::new(self, key)
117 }
118
119 pub(crate) fn fetch_indices(&self) -> PakResult<HashMap<String, PakUntypedPointer>> {
120 let pointer = PakPointer::new_untyped(self.get_indices_start(), self.sizing.indices_size);
121 let Ok(mut source) = self.source.write() else { return Err(error::PakError::SourceInUse) };
122 let buffer = source.read(&pointer, 0)?;
123 let indices = bincode::deserialize(&buffer)?;
124 Ok(indices)
125 }
126
127 pub(crate) fn fetch_all_pointers_of<T>(&self) -> PakResult<Vec<PakPointer>> where T : DeserializeGroup {
128 let Ok(mut source) = self.source.write() else { return Err(error::PakError::SourceInUse) };
129 let lists_pointer = PakPointer::new_untyped(self.get_list_start(), self.sizing.list_size);
130 let lists_buffer = source.read(&lists_pointer, 0)?;
131 let lists : HashMap<String, PakPointer> = bincode::deserialize(&lists_buffer)?;
132 let values = T::get_types().into_iter()
133 .filter_map(|type_name| lists.get(type_name))
134 .filter_map(|pointer| self.read_internal::<Vec<PakPointer>>(pointer, &mut source).ok())
135 .flatten()
136 .collect::<Vec<_>>();
137 Ok(values)
138 }
139
140 pub(crate) fn get_vault_start(&self) -> u64 {
141 self.get_list_start() + self.sizing.list_size + 8
143 }
144
145 pub(crate) fn get_list_start(&self) -> u64 {
146 self.get_indices_start() + self.sizing.indices_size
147 }
148
149 pub(crate) fn get_indices_start(&self) -> u64 {
150 PAK_SIZING_STRUCT_SIZE_IN_BYTES + self.sizing.meta_size
151 }
152}
153
154pub trait PakSource {
160 fn read(&mut self, pointer : &PakPointer, offset : u64) -> PakResult<Vec<u8>>;
162}
163
164impl <R> PakSource for R where R : Read + Seek {
165 fn read(&mut self, pointer : &PakPointer, offset : u64) -> PakResult<Vec<u8>> {
166 let mut buffer = vec![0u8; pointer.size() as usize];
167 self.seek(SeekFrom::Start(pointer.offset() + offset))?;
168 self.read_exact(&mut buffer)?;
169 Ok(buffer)
170 }
171}
172