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}