1use crate::{util, Cell, Ordering, Rc, Record, SaveOp, SortedFile, DB};
2
3pub const NFT: usize = 4;
5
6fn tot(len: usize, bpf: usize) -> usize {
8 let nf = (len + bpf - 1) / bpf;
9 nf * (bpf + 12)
10}
11
12pub fn fragment_type(len: usize, bpf: &[usize]) -> usize {
14 let mut best = usize::MAX;
15 let mut result = 0;
16 for (ft, bpf) in bpf.iter().enumerate() {
17 let t = tot(len, *bpf);
18 if t <= best {
19 best = t;
20 result = ft;
21 }
22 }
23 result
24}
25
26pub fn bpf(hp: usize) -> [usize; NFT] {
28 let hp = hp - 8; let pp = hp / 1000;
30 let max_bpf = hp / pp - 12;
31 [40, 127, 333, max_bpf]
32}
33
34pub struct ByteStorage {
36 pub file: Rc<SortedFile>,
38 id_gen: Cell<u64>,
39 bpf: usize,
41}
42
43impl ByteStorage {
44 pub fn new(root_page: u64, bpf: usize) -> Self {
46 let file = Rc::new(SortedFile::new(9 + bpf, 8, root_page));
47 ByteStorage {
48 file,
49 id_gen: Cell::new(u64::MAX),
50 bpf,
51 }
52 }
53
54 fn get_id(&self, db: &DB) -> u64 {
56 let mut result = self.id_gen.get();
57 if result == u64::MAX {
58 result = 0;
59 let start = Fragment::new(u64::MAX, self.bpf);
61 if let Some((pp, off)) = self.file.clone().dsc(db, Box::new(start)).next() {
62 let p = pp.borrow();
63 result = 1 + util::getu64(&p.data, off);
64 }
65 self.id_gen.set(result);
66 }
67 result
68 }
69
70 pub fn changed(&self) -> bool {
72 self.file.changed()
73 }
74
75 pub fn save(&self, db: &DB, op: SaveOp) {
77 self.file.save(db, op);
78 }
79
80 pub fn encode(&self, db: &DB, bytes: &[u8]) -> u64 {
82 let result = self.get_id(db);
83 let mut r = Fragment::new(0, self.bpf);
84 let n = bytes.len();
85 let mut done = 0;
86 loop {
87 r.id = self.id_gen.get();
88 self.id_gen.set(r.id + 1);
89 let mut len = n - done;
90 if len > self.bpf {
91 r.last = false;
92 len = self.bpf;
93 } else {
94 r.last = true;
95 }
96 r.len = len;
97 r.bytes[..len].copy_from_slice(&bytes[done..(len + done)]);
98 done += len;
99 self.file.insert(db, &r);
100 if done == n {
101 break;
102 }
103 }
104 result
105 }
106
107 pub fn decode(&self, db: &DB, mut id: u64, inline: usize) -> Vec<u8> {
109 let mut result = vec![0_u8; inline];
110 let start = Fragment::new(id, self.bpf);
111 for (pp, off) in self.file.asc(db, Box::new(start)) {
112 let p = pp.borrow();
113 let data = &p.data;
114 debug_assert!(util::getu64(data, off) == id);
115 id += 1;
116 let off = off + 8;
117 let (len, last) = decode(&data[off..], self.bpf);
118 result.extend_from_slice(&data[off..off + len]);
119 if last {
120 break;
121 }
122 }
123 result
124 }
125
126 pub fn delcode(&self, db: &DB, id: u64) {
128 let start = Fragment::new(id, self.bpf);
129 let mut n = 0;
130 for (pp, off) in self.file.asc(db, Box::new(start)) {
131 let p = pp.borrow();
132 debug_assert!(util::getu64(&p.data, off) == id + n);
133 n += 1;
134 let off = off + 8;
135 let (_len, last) = decode(&p.data[off..], self.bpf);
136 if last {
137 break;
138 }
139 }
140 let mut r = Fragment::new(0, self.bpf);
141 for xid in id..id + n {
142 r.id = xid;
143 self.file.remove(db, &r);
144 }
145 }
146
147 #[cfg(feature = "pack")]
149 pub fn repack_file(&self, db: &DB) -> i64 {
150 let r = Fragment::new(0, self.bpf);
151 self.file.repack(db, &r)
152 }
153}
154
155struct Fragment {
157 id: u64,
158 len: usize,
159 last: bool,
160 bytes: Vec<u8>,
161}
162
163impl Fragment {
164 pub fn new(id: u64, bpf: usize) -> Self {
165 Fragment {
166 id,
167 len: 0,
168 last: false,
169 bytes: vec![0; bpf],
170 }
171 }
172}
173
174impl Record for Fragment {
175 fn compare(&self, _db: &DB, data: &[u8]) -> Ordering {
176 let val = util::getu64(data, 0);
177 self.id.cmp(&val)
178 }
179
180 fn save(&self, data: &mut [u8]) {
181 util::setu64(data, self.id);
182 let bpf = self.bytes.len();
183 data[8..8 + self.len].copy_from_slice(&self.bytes[..self.len]);
184
185 let unused = bpf - self.len;
188 data[8 + bpf] = (unused % 64) as u8
189 + if self.last { 64 } else { 0 }
190 + if unused >= 64 { 128 } else { 0 };
191 if unused >= 64 {
192 data[8 + bpf - 1] = (unused / 64) as u8;
193 }
194 }
195}
196
197fn decode(data: &[u8], bpf: usize) -> (usize, bool) {
199 let b = data[bpf];
200 let unused = (b % 64) as usize
201 + if b >= 128 {
202 data[bpf - 1] as usize * 64
203 } else {
204 0
205 };
206 (bpf - unused, b & 64 != 0)
207}