gbf_core/graal_io.rs
1#![deny(missing_docs)]
2
3use std::io::{self, Read, Write};
4
5use serde::{Serialize, Serializer, ser::SerializeStruct};
6use thiserror::Error;
7
8/// The maximum values for a one-byte Graal-encoded integer.
9pub const GUINT8_MAX: u64 = 0xDF;
10
11/// The maximum values for a two-byte Graal-encoded integer.
12pub const GUINT16_MAX: u64 = 0x705F;
13
14/// The maximum values for a three-byte Graal-encoded integer.
15pub const GUINT24_MAX: u64 = 0x38305F;
16
17/// The maximum values for a four-byte Graal-encoded integer.
18pub const GUINT32_MAX: u64 = 0x1C18305F;
19
20/// The maximum values for a five-byte Graal-encoded integer. 60332453983 is the theoretical maximum value for a 40-bit integer,
21/// but the Graal encoding only supports up to 0xFFFFFFFF in practice.
22pub const GUINT40_MAX: u64 = 0xFFFFFFFF;
23
24/// A reader that reads Graal-encoded data.
25pub struct GraalReader<R: Read> {
26 inner: R,
27}
28
29/// A writer that writes Graal-encoded data.
30pub struct GraalWriter<W: Write> {
31 inner: W,
32}
33
34/// Errors that can occur when reading or writing to a GraalReader / GraalWriter.
35#[derive(Debug, Error)]
36pub enum GraalIoError {
37 /// A null terminator was not found when reading a string.
38 #[error("No null terminator found when reading a string.")]
39 NoNullTerminator(),
40
41 /// A value exceeds the maximum for a Graal-encoded integer.
42 #[error(
43 "Value exceeds maximum for Graal-encoded integer. Value was {0}, but cannot exceed {1}."
44 )]
45 ValueExceedsMaximum(u64, u64),
46
47 /// An I/O error occurred.
48 #[error("IO error: {0}")]
49 Io(#[from] io::Error),
50}
51
52// Custom implementation of clone
53impl Clone for GraalIoError {
54 fn clone(&self) -> Self {
55 match self {
56 GraalIoError::NoNullTerminator() => GraalIoError::NoNullTerminator(),
57 GraalIoError::ValueExceedsMaximum(value, max) => {
58 GraalIoError::ValueExceedsMaximum(*value, *max)
59 }
60 GraalIoError::Io(err) => GraalIoError::Io(io::Error::new(err.kind(), err.to_string())),
61 }
62 }
63}
64
65// Custom implementation of Serialize
66impl Serialize for GraalIoError {
67 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68 where
69 S: Serializer,
70 {
71 let mut state = serializer.serialize_struct("GraalIoError", 2)?;
72 match self {
73 GraalIoError::NoNullTerminator() => {
74 state.serialize_field("type", "NoNullTerminator")?;
75 }
76 GraalIoError::ValueExceedsMaximum(value, max) => {
77 state.serialize_field("type", "ValueExceedsMaximum")?;
78 state.serialize_field("value", value)?;
79 state.serialize_field("max", max)?;
80 }
81 GraalIoError::Io(err) => {
82 state.serialize_field("type", "Io")?;
83 state.serialize_field("error", &err.to_string())?;
84 }
85 }
86 state.end()
87 }
88}
89
90impl<R: Read> GraalReader<R> {
91 /// Creates a new GraalReader
92 ///
93 /// # Arguments
94 /// - `inner`: The reader to wrap.
95 ///
96 /// # Returns
97 /// - A new GraalReader with the given bytes.
98 ///
99 /// # Examples
100 /// ```
101 /// use gbf_core::graal_io::GraalReader;
102 /// use std::io::Cursor;
103 ///
104 /// let reader = GraalReader::new(Cursor::new(vec![1, 2, 3, 4]));
105 /// ```
106 pub fn new(inner: R) -> Self {
107 Self { inner }
108 }
109
110 /// Decodes a sequence of bytes using the Graal encoding.
111 ///
112 /// # Arguments
113 /// - `slice`: The slice of bytes to decode.
114 ///
115 /// # Returns
116 /// - The decoded integer.
117 ///
118 /// # Examples
119 /// ```
120 /// use gbf_core::graal_io::GraalReader;
121 /// use std::io::Cursor;
122 ///
123 /// let value = GraalReader::<Cursor<Vec<u8>>>::decode_bits(&[32, 32, 32, 33]);
124 /// assert_eq!(value, 1);
125 /// ```
126 pub fn decode_bits(slice: &[u8]) -> u64 {
127 let mut value = 0;
128
129 for (i, &byte) in slice.iter().enumerate() {
130 let chunk = (byte - 32) as u64; // Remove printable offset
131 let shift = 7 * (slice.len() - 1 - i);
132 value += chunk << shift; // Accumulate the value
133 }
134
135 value
136 }
137
138 /// Reads a null-terminated string from the reader.
139 ///
140 /// # Returns
141 /// - The string read from the reader.
142 ///
143 /// # Errors
144 /// - `GraalIoError::NoNullTerminator`: If the null terminator (`0x00`) is not found.
145 /// - `GraalIoError::Io`: If there is an underlying I/O error.
146 ///
147 /// # Examples
148 /// ```
149 /// use gbf_core::graal_io::GraalReader;
150 /// use std::io::Cursor;
151 ///
152 /// let mut reader = GraalReader::new(Cursor::new(vec![104, 101, 108, 108, 111, 0, 119, 111, 114, 108, 100, 0]));
153 /// assert_eq!(reader.read_string().unwrap().0, "hello");
154 /// ```
155 pub fn read_string(&mut self) -> Result<(String, u32), GraalIoError> {
156 let mut buffer = Vec::new();
157 let mut byte = [0; 1];
158
159 // Read bytes until a null terminator (0x00) is found
160 loop {
161 let bytes_read = self.inner.read(&mut byte)?;
162 if bytes_read == 0 {
163 return Err(GraalIoError::NoNullTerminator()); // EOF before finding null terminator
164 }
165 if byte[0] == 0x00 {
166 break; // Null terminator found
167 }
168 buffer.push(byte[0]);
169 }
170
171 // Convert latin-1 bytes to a UTF-8 string
172 let s: String = buffer.iter().map(|&c| c as char).collect();
173 Ok((s, buffer.len() as u32))
174 }
175
176 /// Reads a string with a graal-encoded integer at the beginning.
177 ///
178 /// # Returns
179 /// - The string read from the reader.
180 ///
181 /// # Errors
182 /// - `GraalIoError::Io`: If there is an underlying I/O error.
183 /// - `GraalIoError::ValueExceedsMaximum`: If the value exceeds the maximum for a Graal-encoded integer.
184 ///
185 /// # Examples
186 /// ```
187 /// use gbf_core::graal_io::GraalReader;
188 /// use std::io::Cursor;
189 ///
190 /// let mut reader = GraalReader::new(Cursor::new(vec![32 + 5, 104, 101, 108, 108, 111, 32 + 5, 119, 111, 114, 108, 100]));
191 /// assert_eq!(reader.read_gstring().unwrap(), "hello");
192 /// assert_eq!(reader.read_gstring().unwrap(), "world");
193 /// ```
194 pub fn read_gstring(&mut self) -> Result<String, GraalIoError> {
195 // Read the length prefix
196 let length = self.read_gu8()? as usize;
197
198 // Read the specified number of bytes for the string
199 let mut chars = vec![0; length];
200 self.inner.read_exact(&mut chars)?;
201
202 // Convert bytes to a UTF-8 string
203 Ok(chars.iter().map(|&c| c as char).collect::<String>())
204 }
205
206 /// Reads an unsigned char from the reader.
207 ///
208 /// # Returns
209 /// - The unsigned char read from the reader.
210 ///
211 /// # Errors
212 /// - `GraalIoError::Io`: If there is an underlying I/O error.
213 ///
214 /// # Examples
215 /// ```
216 /// use gbf_core::graal_io::GraalReader;
217 /// use std::io::Cursor;
218 ///
219 /// let mut reader = GraalReader::new(Cursor::new(vec![1, 2]));
220 /// assert_eq!(reader.read_u8().unwrap(), 1);
221 /// assert_eq!(reader.read_u8().unwrap(), 2);
222 /// ```
223 pub fn read_u8(&mut self) -> Result<u8, GraalIoError> {
224 let mut buffer = [0; 1];
225 self.inner.read_exact(&mut buffer)?;
226 Ok(buffer[0])
227 }
228
229 /// Read an unsigned short from the reader.
230 ///
231 /// # Returns
232 /// - The unsigned short read from the reader.
233 ///
234 /// # Errors
235 /// - `GraalIoError::Io`: If there is an underlying I/O error.
236 ///
237 /// # Examples
238 /// ```
239 /// use gbf_core::graal_io::GraalReader;
240 /// use std::io::Cursor;
241 ///
242 /// let mut reader = GraalReader::new(Cursor::new(vec![0, 1, 0, 2]));
243 /// assert_eq!(reader.read_u16().unwrap(), 1);
244 /// assert_eq!(reader.read_u16().unwrap(), 2);
245 /// ```
246 pub fn read_u16(&mut self) -> Result<u16, GraalIoError> {
247 let mut buffer = [0; 2];
248 self.inner.read_exact(&mut buffer)?;
249 Ok(u16::from_be_bytes(buffer))
250 }
251
252 /// Read an unsigned int from the reader.
253 ///
254 /// # Returns
255 /// - The unsigned int read from the reader.
256 ///
257 /// # Errors
258 /// - `GraalIoError::Io`: If there is an underlying I/O error.
259 ///
260 /// # Examples
261 /// ```
262 /// use gbf_core::graal_io::GraalReader;
263 /// use std::io::Cursor;
264 ///
265 /// let mut reader = GraalReader::new(Cursor::new(vec![0, 0, 0, 1, 0, 0, 0, 2]));
266 /// assert_eq!(reader.read_u32().unwrap(), 1);
267 /// assert_eq!(reader.read_u32().unwrap(), 2);
268 /// ```
269 pub fn read_u32(&mut self) -> Result<u32, GraalIoError> {
270 let mut buffer = [0; 4];
271 self.inner.read_exact(&mut buffer)?;
272 Ok(u32::from_be_bytes(buffer))
273 }
274
275 /// Reads a Graal encoded unsigned 8-bit integer from the reader.
276 ///
277 /// # Returns
278 /// - The decoded unsigned char.
279 ///
280 /// # Errors
281 /// - `GraalIoError::Io`: If there is an underlying I/O error.
282 ///
283 /// # Examples
284 /// ```
285 /// use gbf_core::graal_io::GraalReader;
286 /// use std::io::Cursor;
287 ///
288 /// let mut reader = GraalReader::new(Cursor::new(vec![32 + 1]));
289 /// assert_eq!(reader.read_gu8().unwrap(), 1);
290 /// ```
291 pub fn read_gu8(&mut self) -> Result<u64, GraalIoError> {
292 self.read_gu(1)
293 }
294
295 /// Reads a Graal encoded unsigned 16-bit integer from the reader.
296 ///
297 /// # Returns
298 /// - The decoded unsigned short.
299 ///
300 /// # Errors
301 /// - `GraalIoError::Io`: If there is an underlying I/O error.
302 ///
303 /// # Examples
304 /// ```
305 /// use gbf_core::graal_io::GraalReader;
306 /// use std::io::Cursor;
307 ///
308 /// let mut reader = GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1]));
309 /// assert_eq!(reader.read_gu16().unwrap(), 129);
310 /// ```
311 pub fn read_gu16(&mut self) -> Result<u64, GraalIoError> {
312 self.read_gu(2)
313 }
314
315 /// Reads a Graal encoded unsigned 24-bit integer from the reader.
316 ///
317 /// # Returns
318 /// - The decoded unsigned int.
319 ///
320 /// # Errors
321 /// - `GraalIoError::Io`: If there is an underlying I/O error.
322 ///
323 /// # Examples
324 /// ```
325 /// use gbf_core::graal_io::GraalReader;
326 /// use std::io::Cursor;
327 ///
328 /// let mut reader = GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1, 32 + 1]));
329 /// assert_eq!(reader.read_gu24().unwrap(), 16513);
330 /// ```
331 pub fn read_gu24(&mut self) -> Result<u64, GraalIoError> {
332 self.read_gu(3)
333 }
334
335 /// Reads a Graal encoded unsigned 32-bit integer from the reader.
336 ///
337 /// # Returns
338 /// - The decoded unsigned int.
339 ///
340 /// # Errors
341 /// - `GraalIoError::Io`: If there is an underlying I/O error.
342 ///
343 /// # Examples
344 /// ```
345 /// use gbf_core::graal_io::GraalReader;
346 /// use std::io::Cursor;
347 ///
348 /// let mut reader = GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1, 32 + 1, 32 + 1]));
349 /// assert_eq!(reader.read_gu32().unwrap(), 2113665);
350 /// ```
351 pub fn read_gu32(&mut self) -> Result<u64, GraalIoError> {
352 self.read_gu(4)
353 }
354
355 /// Reads a Graal encoded unsigned 40-bit integer from the reader.
356 ///
357 /// # Returns
358 /// - The decoded unsigned int.
359 ///
360 /// # Errors
361 /// - `GraalIoError::Io`: If there is an underlying I/O error.
362 ///
363 /// # Examples
364 /// ```
365 /// use gbf_core::graal_io::GraalReader;
366 /// use std::io::Cursor;
367 ///
368 /// let mut reader = GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1, 32 + 1, 32 + 1, 32 + 1]));
369 /// assert_eq!(reader.read_gu40().unwrap(), 270549121);
370 /// ```
371 pub fn read_gu40(&mut self) -> Result<u64, GraalIoError> {
372 self.read_gu(5)
373 }
374
375 /// Reads `n` bytes from the reader and decodes them as a Graal unsigned integer.
376 ///
377 /// # Arguments
378 /// - `n`: The number of bytes to read.
379 ///
380 /// # Returns
381 /// - The decoded Graal unsigned integer.
382 ///
383 /// # Errors
384 /// - `GraalIoError::Io`: If an I/O error occurs
385 ///
386 /// # Examples
387 /// ```
388 /// use gbf_core::graal_io::GraalReader;
389 /// use std::io::Cursor;
390 ///
391 /// let mut reader = GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1, 32 + 1, 32 + 1, 32 + 1]));
392 /// assert_eq!(reader.read_gu(5).unwrap(), 270549121);
393 /// ```
394 pub fn read_gu(&mut self, n: usize) -> Result<u64, GraalIoError> {
395 let mut buffer = vec![0; n];
396
397 // Read exactly `n` bytes into the buffer
398 self.inner.read_exact(&mut buffer)?;
399
400 // Decode the buffer into a u64
401 Ok(Self::decode_bits(&buffer))
402 }
403}
404
405impl<W: Write> GraalWriter<W> {
406 /// Creates a new GraalWriter
407 ///
408 /// # Arguments
409 /// - `inner`: The writer to wrap.
410 ///
411 /// # Returns
412 /// - A new GraalWriter with the given bytes.
413 ///
414 /// # Examples
415 /// ```
416 /// use gbf_core::graal_io::GraalWriter;
417 /// use std::io::Cursor;
418 ///
419 /// let data = vec![0];
420 /// let writer = GraalWriter::new(Cursor::new(data));
421 /// ```
422 pub fn new(inner: W) -> Self {
423 Self { inner }
424 }
425
426 /// Encodes a value as a sequence of bytes using the Graal encoding.
427 ///
428 /// # Arguments
429 /// - `value`: The value to encode.
430 /// - `buffer`: The buffer to write the encoded bytes to.
431 /// - `byte_count`: The number of bytes to encode.
432 ///
433 /// # Returns
434 /// - The encoded bytes.
435 ///
436 /// # Examples
437 /// ```
438 /// use gbf_core::graal_io::GraalWriter;
439 /// use std::io::Cursor;
440 ///
441 /// let mut buffer = vec![0, 0, 0, 0];
442 /// GraalWriter::<Cursor<Vec<u8>>>::encode_bits(1, &mut buffer, 4);
443 /// assert_eq!(buffer, vec![32, 32, 32, 33]);
444 /// ```
445 pub fn encode_bits(mut value: u64, buffer: &mut Vec<u8>, byte_count: usize) {
446 buffer.clear();
447
448 for i in 0..byte_count {
449 let shift = 7 * (byte_count - 1 - i);
450 let chunk = (value >> shift) & 0x7F; // Extract 7 bits
451 buffer.push((chunk as u8) + 32); // Add printable offset
452 value -= chunk << shift; // Remove the chunk's contribution
453 }
454 }
455
456 /// Writes the given bytes to the writer.
457 ///
458 /// # Arguments
459 /// - `vec`: The bytes to write.
460 ///
461 /// # Errors
462 /// - `GraalIoError::Io`: If there is an I/O error.
463 ///
464 /// # Examples
465 /// ```
466 /// use std::io::Cursor;
467 /// use gbf_core::graal_io::GraalWriter;
468 ///
469 /// let mut buffer = Cursor::new(Vec::new());
470 /// let mut writer = GraalWriter::new(buffer);
471 /// writer.write(&[1, 2, 3, 4]).unwrap();
472 /// ```
473 pub fn write(&mut self, vec: &[u8]) -> Result<(), GraalIoError> {
474 self.inner.write_all(vec).map_err(GraalIoError::Io)
475 }
476
477 /// Write a string to the writer, followed by a null terminator.
478 ///
479 /// # Arguments
480 /// - `s`: The string to write.
481 ///
482 /// # Examples
483 /// ```
484 /// use gbf_core::graal_io::GraalWriter;
485 /// use std::io::Cursor;
486 ///
487 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
488 /// writer.write_string("hello").unwrap();
489 /// writer.write_string("world").unwrap();
490 /// ```
491 pub fn write_string(&mut self, s: &str) -> Result<(), GraalIoError> {
492 self.write(s.as_bytes())?;
493 self.write(&[0])?;
494 Ok(())
495 }
496
497 /// Writes a Graal-encoded string.
498 ///
499 /// # Arguments
500 /// - `s`: The string to write.
501 ///
502 /// # Errors
503 /// - `GraalIoError::ValueExceedsMaximum`: If the string is too long to be represented by a Graal encoded 8 bit integer.
504 /// - `GraalIoError::Io`: If there is an underlying I/O error.
505 ///
506 /// # Examples
507 /// ```
508 /// use gbf_core::graal_io::GraalWriter;
509 /// use std::io::Cursor;
510 ///
511 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
512 /// writer.write_gstring("hello").unwrap();
513 /// ```
514 pub fn write_gstring(&mut self, s: &str) -> Result<(), GraalIoError> {
515 let length = s.len();
516
517 // Write the length prefix
518 self.write_gu8(length as u64)?;
519
520 // Write the string bytes
521 self.write(s.as_bytes())?;
522
523 Ok(())
524 }
525
526 /// Writes an unsigned 8-bit integer to the writer.
527 ///
528 /// # Arguments
529 /// - `c`: The unsigned char to write.
530 ///
531 /// # Errors
532 /// - `GraalIoError::Io`: If there is an underlying I/O error.
533 ///
534 /// # Examples
535 /// ```
536 /// use gbf_core::graal_io::GraalWriter;
537 /// use std::io::Cursor;
538 ///
539 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
540 /// writer.write_u8(1);
541 /// writer.write_u8(2);
542 /// writer.write_u8(3);
543 /// writer.write_u8(4);
544 /// ```
545 pub fn write_u8(&mut self, c: u8) -> Result<(), GraalIoError> {
546 // Ensure the seek location is within bounds before resizing
547 self.write(&c.to_be_bytes())?;
548 Ok(())
549 }
550
551 /// Write an unsigned 16-bit integer to the writer.
552 ///
553 /// # Arguments
554 /// - `s`: The unsigned short to write.
555 ///
556 /// # Errors
557 /// - `GraalIoError::Io`: If there is an underlying I/O error.
558 ///
559 /// # Examples
560 /// ```
561 /// use gbf_core::graal_io::GraalWriter;
562 /// use std::io::Cursor;
563 ///
564 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
565 /// writer.write_u16(1);
566 /// ```
567 pub fn write_u16(&mut self, s: u16) -> Result<(), GraalIoError> {
568 let bytes = s.to_be_bytes();
569 self.write(&bytes)?;
570 Ok(())
571 }
572
573 /// Write an unsigned 32-bit integer to the writer.
574 ///
575 /// # Arguments
576 /// - `i`: The unsigned int to write.
577 ///
578 /// # Errors
579 /// - `GraalIoError::Io`: If there is an underlying I/O error.
580 ///
581 /// # Examples
582 /// ```
583 /// use gbf_core::graal_io::GraalWriter;
584 /// use std::io::Cursor;
585 ///
586 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
587 /// writer.write_u32(1).unwrap();
588 /// ```
589 pub fn write_u32(&mut self, i: u32) -> Result<(), GraalIoError> {
590 let bytes = i.to_be_bytes();
591 self.write(&bytes)?;
592 Ok(())
593 }
594
595 /// Writes an encoded Graal unsigned 8-bit integer.
596 ///
597 /// # Arguments
598 /// - `v`: The value to write.
599 ///
600 /// # Errors
601 /// - `GraalIoError::ValueExceedsMaximum`: If the value exceeds the maximum for a Graal-encoded integer.
602 /// - `GraalIoError::Io`: If there is an underlying I/O error.
603 ///
604 /// # Examples
605 /// ```
606 /// use gbf_core::graal_io::GraalWriter;
607 /// use std::io::Cursor;
608 ///
609 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
610 /// writer.write_gu8(1).unwrap();
611 /// ```
612 pub fn write_gu8(&mut self, v: u64) -> Result<(), GraalIoError> {
613 if v > GUINT8_MAX {
614 return Err(GraalIoError::ValueExceedsMaximum(v, GUINT8_MAX));
615 }
616
617 let mut buffer = vec![0];
618 Self::encode_bits(v, &mut buffer, 1);
619 self.write(&buffer)?;
620 Ok(())
621 }
622
623 /// Writes an encoded Graal unsigned 16-bit integer.
624 ///
625 /// # Arguments
626 /// - `v`: The value to write.
627 ///
628 /// # Errors
629 /// - `GraalIoError::ValueExceedsMaximum`: If the value exceeds the maximum for a Graal-encoded integer.
630 /// - `GraalIoError::Io`: If there is an underlying I/O error.
631 ///
632 /// # Examples
633 /// ```
634 /// use gbf_core::graal_io::GraalWriter;
635 /// use std::io::Cursor;
636 ///
637 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
638 /// writer.write_gu16(1).unwrap();
639 /// ```
640 pub fn write_gu16(&mut self, v: u64) -> Result<(), GraalIoError> {
641 if v > GUINT16_MAX {
642 return Err(GraalIoError::ValueExceedsMaximum(v, GUINT16_MAX));
643 }
644
645 let mut buffer = vec![0, 0];
646 Self::encode_bits(v, &mut buffer, 2);
647 self.write(&buffer)?;
648 Ok(())
649 }
650
651 /// Writes an encoded Graal unsigned 24-bit integer.
652 ///
653 /// # Arguments
654 /// - `v`: The value to write.
655 ///
656 /// # Errors
657 /// - `GraalIoError::ValueExceedsMaximum`: If the value exceeds the maximum for a Graal-encoded integer.
658 /// - `GraalIoError::Io`: If there is an underlying I/O error.
659 ///
660 /// # Examples
661 /// ```
662 /// use gbf_core::graal_io::GraalWriter;
663 /// use std::io::Cursor;
664 ///
665 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
666 /// writer.write_gu24(1).unwrap();
667 /// ```
668 pub fn write_gu24(&mut self, v: u64) -> Result<(), GraalIoError> {
669 if v > GUINT24_MAX {
670 return Err(GraalIoError::ValueExceedsMaximum(v, GUINT24_MAX));
671 }
672
673 let mut buffer = vec![0, 0, 0];
674 Self::encode_bits(v, &mut buffer, 3);
675 self.write(&buffer)?;
676 Ok(())
677 }
678
679 /// Writes an encoded Graal unsigned 32-bit integer.
680 ///
681 /// # Arguments
682 /// - `v`: The value to write.
683 ///
684 /// # Errors
685 /// - `GraalIoError::ValueExceedsMaximum`: If the value exceeds the maximum for a Graal-encoded integer.
686 /// - `GraalIoError::Io`: If there is an underlying I/O error.
687 ///
688 /// # Examples
689 /// ```
690 /// use gbf_core::graal_io::GraalWriter;
691 /// use std::io::Cursor;
692 ///
693 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
694 /// writer.write_gu32(1).unwrap();
695 /// ```
696 pub fn write_gu32(&mut self, v: u64) -> Result<(), GraalIoError> {
697 if v > GUINT32_MAX {
698 return Err(GraalIoError::ValueExceedsMaximum(v, GUINT32_MAX));
699 }
700
701 let mut buffer = vec![0, 0, 0, 0];
702 Self::encode_bits(v, &mut buffer, 4);
703 self.write(&buffer)?;
704 Ok(())
705 }
706
707 /// Writes an encoded Graal unsigned 40-bit integer.
708 ///
709 /// # Arguments
710 /// - `v`: The value to write.
711 ///
712 /// # Errors
713 /// - `GraalIoError::ValueExceedsMaximum`: If the value exceeds the maximum for a Graal-encoded integer.
714 /// - `GraalIoError::Io`: If there is an underlying I/O error.
715 ///
716 /// # Examples
717 /// ```
718 /// use gbf_core::graal_io::GraalWriter;
719 /// use std::io::Cursor;
720 ///
721 /// let mut writer = GraalWriter::new(Cursor::new(vec![]));
722 /// writer.write_gu40(1).unwrap();
723 /// ```
724 pub fn write_gu40(&mut self, v: u64) -> Result<(), GraalIoError> {
725 if v > GUINT40_MAX {
726 return Err(GraalIoError::ValueExceedsMaximum(v, GUINT40_MAX));
727 }
728
729 let mut buffer = vec![0, 0, 0, 0, 0];
730 Self::encode_bits(v, &mut buffer, 5);
731 self.write(&buffer)?;
732 Ok(())
733 }
734}
735
736#[cfg(test)]
737mod tests {
738 use io::Cursor;
739
740 use super::*;
741
742 const MAX_ENCODED: u8 = 0xff;
743 const MIN_ENCODED: u8 = 0x20;
744 const MIN_DECODED: u64 = 0;
745
746 #[test]
747 fn test_constants() {
748 // Test for GUINT8
749 let data = [MAX_ENCODED, MIN_ENCODED];
750 let mut reader = GraalReader::new(Cursor::new(&data));
751 assert_eq!(reader.read_gu8().unwrap(), GUINT8_MAX);
752 assert_eq!(reader.read_gu8().unwrap(), MIN_DECODED);
753
754 // Test for GUINT16
755 let data = [MAX_ENCODED, MAX_ENCODED, MIN_ENCODED, MIN_ENCODED];
756 let mut reader = GraalReader::new(Cursor::new(&data));
757 assert_eq!(reader.read_gu16().unwrap(), GUINT16_MAX);
758 assert_eq!(reader.read_gu16().unwrap(), MIN_DECODED);
759
760 // Test for GUINT24
761 let data = [
762 MAX_ENCODED,
763 MAX_ENCODED,
764 MAX_ENCODED,
765 MIN_ENCODED,
766 MIN_ENCODED,
767 MIN_ENCODED,
768 ];
769 let mut reader = GraalReader::new(Cursor::new(&data));
770 assert_eq!(reader.read_gu24().unwrap(), GUINT24_MAX);
771 assert_eq!(reader.read_gu24().unwrap(), MIN_DECODED);
772
773 // Test for GUINT32
774 let data = [
775 MAX_ENCODED,
776 MAX_ENCODED,
777 MAX_ENCODED,
778 MAX_ENCODED,
779 MIN_ENCODED,
780 MIN_ENCODED,
781 MIN_ENCODED,
782 MIN_ENCODED,
783 ];
784 let mut reader = GraalReader::new(Cursor::new(&data));
785 assert_eq!(reader.read_gu32().unwrap(), GUINT32_MAX);
786 assert_eq!(reader.read_gu32().unwrap(), MIN_DECODED);
787 }
788
789 // ===== General Operations =====
790
791 #[test]
792 fn test_new() {
793 let data = vec![1, 2, 3, 4];
794 let reader = GraalReader::new(&data[..]);
795 assert_eq!(reader.inner, data);
796
797 let data = vec![1, 2, 3, 4];
798 let cursor = Cursor::new(data.clone());
799 let writer = GraalReader::new(cursor);
800 assert_eq!(writer.inner.into_inner(), data);
801 }
802
803 #[test]
804 fn test_out_of_bounds() {
805 // do it on a non-empty buffer
806 let mut reader = GraalReader::new(Cursor::new(vec![1, 2, 3, 4]));
807 assert!(reader.read_u8().is_ok());
808 assert!(reader.read_u8().is_ok());
809 assert!(reader.read_u8().is_ok());
810 assert!(reader.read_u8().is_ok());
811 assert!(reader.read_u8().is_err());
812
813 // do it on an empty buffer
814 let mut reader = GraalReader::new(Cursor::new(vec![]));
815 assert!(reader.read_u8().is_err());
816
817 // do it on a buffer with a single byte, then read a u16
818 let mut reader = GraalReader::new(Cursor::new(vec![1]));
819 assert!(reader.read_u16().is_err());
820
821 // do it on a buffer with a single byte, then read a u32
822 let mut reader = GraalReader::new(Cursor::new(vec![1]));
823 assert!(reader.read_u32().is_err());
824
825 // do it on a buffer with two bytes, then read a u32
826 let mut reader = GraalReader::new(Cursor::new(vec![1, 2]));
827 assert!(reader.read_u32().is_err());
828 }
829
830 #[test]
831 fn test_decode_bits() {
832 assert_eq!(
833 GraalReader::<Cursor<Vec<u8>>>::decode_bits(&[32, 32, 32, 32]),
834 0
835 );
836 assert_eq!(
837 GraalReader::<Cursor<Vec<u8>>>::decode_bits(&[32, 32, 32, 33]),
838 1
839 );
840 assert_eq!(
841 GraalReader::<Cursor<Vec<u8>>>::decode_bits(&[32, 32, 33, 32]),
842 128
843 );
844 assert_eq!(
845 GraalReader::<Cursor<Vec<u8>>>::decode_bits(&[32, 33, 32, 32]),
846 16384
847 );
848 assert_eq!(
849 GraalReader::<Cursor<Vec<u8>>>::decode_bits(&[33, 32, 32, 32]),
850 2097152
851 );
852 }
853
854 #[test]
855 fn test_encode_bits() {
856 let mut reader = vec![];
857 GraalWriter::<Cursor<Vec<u8>>>::encode_bits(0, &mut reader, 4);
858 assert_eq!(reader, vec![32, 32, 32, 32]);
859
860 let mut reader = vec![];
861 GraalWriter::<Cursor<Vec<u8>>>::encode_bits(1, &mut reader, 4);
862 assert_eq!(reader, vec![32, 32, 32, 33]);
863
864 let mut reader = vec![];
865 GraalWriter::<Cursor<Vec<u8>>>::encode_bits(128, &mut reader, 4);
866 assert_eq!(reader, vec![32, 32, 33, 32]);
867
868 let mut reader = vec![];
869 GraalWriter::<Cursor<Vec<u8>>>::encode_bits(16384, &mut reader, 4);
870 assert_eq!(reader, vec![32, 33, 32, 32]);
871
872 let mut reader = vec![];
873 GraalWriter::<Cursor<Vec<u8>>>::encode_bits(2097152, &mut reader, 4);
874 assert_eq!(reader, vec![33, 32, 32, 32]);
875 }
876
877 // ===== Read Methods =====
878
879 #[test]
880 fn test_read_string() {
881 let mut reader = GraalReader::new(Cursor::new(vec![
882 104, 101, 108, 108, 111, 0, 119, 111, 114, 108, 100, 0,
883 ]));
884 assert_eq!(reader.read_string().unwrap().0, "hello");
885 assert_eq!(reader.read_string().unwrap().0, "world");
886
887 // read a string that doesn't have a null terminator
888 let mut reader = GraalReader::new(Cursor::new(vec![
889 104, 101, 108, 108, 111, 119, 111, 114, 108, 100,
890 ]));
891 assert!(reader.read_string().is_err());
892
893 // read a string that is empty
894 let mut reader = GraalReader::new(Cursor::new(vec![0]));
895 assert_eq!(reader.read_string().unwrap().0, "");
896 }
897
898 #[test]
899 fn test_read_gstring() {
900 let mut reader = GraalReader::new(Cursor::new(vec![
901 32 + 5,
902 104,
903 101,
904 108,
905 108,
906 111,
907 32 + 5,
908 119,
909 111,
910 114,
911 108,
912 100,
913 ]));
914 assert_eq!(reader.read_gstring().unwrap(), "hello");
915 assert_eq!(reader.read_gstring().unwrap(), "world");
916
917 // read a string that is too long
918 let mut reader = GraalReader::new(Cursor::new(vec![255]));
919 assert!(reader.read_gstring().is_err());
920 }
921
922 #[test]
923 fn test_read_u8() {
924 let mut reader = GraalReader::new(Cursor::new(vec![1, 2, 3, 4]));
925 assert_eq!(reader.read_u8().unwrap(), 1);
926 assert_eq!(reader.read_u8().unwrap(), 2);
927 assert_eq!(reader.read_u8().unwrap(), 3);
928 assert_eq!(reader.read_u8().unwrap(), 4);
929 }
930
931 #[test]
932 fn test_read_u16() {
933 let mut reader = GraalReader::new(Cursor::new(vec![0, 1, 0, 2]));
934 assert_eq!(reader.read_u16().unwrap(), 1);
935 assert_eq!(reader.read_u16().unwrap(), 2);
936 }
937
938 #[test]
939 fn test_read_u32() {
940 let mut reader = GraalReader::new(Cursor::new(vec![0, 0, 0, 1, 0, 0, 0, 2]));
941 assert_eq!(reader.read_u32().unwrap(), 1);
942 assert_eq!(reader.read_u32().unwrap(), 2);
943 }
944
945 #[test]
946 fn test_read_gu8() {
947 let mut reader = GraalReader::new(Cursor::new(vec![32 + 1]));
948 assert_eq!(reader.read_gu8().unwrap(), 1);
949 }
950
951 #[test]
952 fn test_read_gu16() {
953 let mut reader = GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1]));
954 assert_eq!(reader.read_gu16().unwrap(), 129);
955 }
956
957 #[test]
958 fn test_read_gu24() {
959 let mut reader = GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1, 32 + 1]));
960 assert_eq!(reader.read_gu24().unwrap(), 16513);
961 }
962
963 #[test]
964 fn test_read_gu32() {
965 let mut reader = GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1, 32 + 1, 32 + 1]));
966 assert_eq!(reader.read_gu32().unwrap(), 2113665);
967 }
968
969 #[test]
970 fn test_read_gu40() {
971 let mut reader =
972 GraalReader::new(Cursor::new(vec![32 + 1, 32 + 1, 32 + 1, 32 + 1, 32 + 1]));
973 assert_eq!(reader.read_gu40().unwrap(), 270549121);
974 }
975
976 // ===== Write Methods =====
977
978 #[test]
979 fn test_write_gstring() {
980 // create a structure to wrap our writer
981 let cursor = Cursor::new(vec![]);
982 let mut writer = GraalWriter::new(cursor);
983 writer.write_gstring("hello").unwrap();
984 writer.write_gstring("world").unwrap();
985 assert_eq!(
986 writer.inner.into_inner(),
987 vec![
988 32 + 5,
989 104,
990 101,
991 108,
992 108,
993 111,
994 32 + 5,
995 119,
996 111,
997 114,
998 108,
999 100
1000 ]
1001 );
1002
1003 // write the max length, which should be fine
1004 let cursor = Cursor::new(vec![]);
1005 let mut writer = GraalWriter::new(cursor);
1006 let long_string = "a".repeat(GUINT8_MAX as usize);
1007 writer.write_gstring(&long_string).unwrap();
1008 // assert_eq!(writer.inner.into_inner(), vec![32 + GUINT8_MAX as u8] + long_string.as_bytes());
1009
1010 // write a string that is too long
1011 let cursor = Cursor::new(vec![]);
1012 let mut writer = GraalWriter::new(cursor);
1013 let long_string = "a".repeat(GUINT8_MAX as usize + 1);
1014 assert!(writer.write_gstring(&long_string).is_err());
1015 }
1016
1017 #[test]
1018 fn test_write_string() {
1019 // create new cursor
1020 let cursor = Cursor::new(vec![]);
1021 let mut writer = GraalWriter::new(cursor);
1022 writer.write_string("hello").unwrap();
1023 writer.write_string("world").unwrap();
1024 assert_eq!(
1025 writer.inner.into_inner(),
1026 vec![104, 101, 108, 108, 111, 0, 119, 111, 114, 108, 100, 0]
1027 );
1028 }
1029
1030 #[test]
1031 fn test_write() {
1032 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1033 writer.write(&[1, 2, 3, 4]).unwrap();
1034 assert_eq!(writer.inner.into_inner(), vec![1, 2, 3, 4]);
1035 }
1036
1037 #[test]
1038 fn test_write_u8() {
1039 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1040 writer.write_u8(1).unwrap();
1041 writer.write_u8(2).unwrap();
1042 assert_eq!(writer.inner.into_inner(), vec![1, 2]);
1043 }
1044
1045 #[test]
1046 fn test_write_u16() {
1047 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1048 writer.write_u16(1).unwrap();
1049 writer.write_u16(2).unwrap();
1050 assert_eq!(writer.inner.into_inner(), vec![0, 1, 0, 2]);
1051 }
1052
1053 #[test]
1054 fn test_write_u32() {
1055 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1056 writer.write_u32(1).unwrap();
1057 writer.write_u32(2).unwrap();
1058 assert_eq!(writer.inner.into_inner(), vec![0, 0, 0, 1, 0, 0, 0, 2]);
1059 }
1060
1061 #[test]
1062 fn test_write_gu8() {
1063 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1064 writer.write_gu8(1).unwrap();
1065 assert_eq!(writer.inner.into_inner(), vec![32 + 1]);
1066
1067 // test for error case
1068 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1069 assert!(writer.write_gu8(GUINT8_MAX + 1).is_err());
1070 }
1071
1072 #[test]
1073 fn test_write_gu16() {
1074 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1075 writer.write_gu16(1).unwrap();
1076 assert_eq!(writer.inner.into_inner(), vec![32, 32 + 1]);
1077
1078 // test for error case
1079 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1080 assert!(writer.write_gu16(GUINT16_MAX + 1).is_err());
1081 }
1082
1083 #[test]
1084 fn test_write_gu24() {
1085 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1086 writer.write_gu24(1).unwrap();
1087 assert_eq!(writer.inner.into_inner(), vec![32, 32, 32 + 1]);
1088
1089 // test for error case
1090 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1091 assert!(writer.write_gu24(GUINT24_MAX + 1).is_err());
1092 }
1093
1094 #[test]
1095 fn test_write_gu32() {
1096 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1097 writer.write_gu32(1).unwrap();
1098 assert_eq!(writer.inner.into_inner(), vec![32, 32, 32, 32 + 1]);
1099
1100 // test for error case
1101 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1102 assert!(writer.write_gu32(GUINT32_MAX + 1).is_err());
1103 }
1104
1105 #[test]
1106 fn test_write_gu40() {
1107 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1108 writer.write_gu40(1).unwrap();
1109 assert_eq!(writer.inner.into_inner(), vec![32, 32, 32, 32, 32 + 1]);
1110
1111 // test for error case
1112 let mut writer = GraalWriter::new(Cursor::new(vec![]));
1113 assert!(writer.write_gu40(GUINT40_MAX + 1).is_err());
1114 }
1115}