| 1 | |
|
| 2 | |
|
| 3 | |
|
| 4 | |
|
| 5 | |
|
| 6 | |
|
| 7 | |
|
| 8 | | use crate::hash::ObjectRef; |
| 9 | | use crate::objects::ObjectError; |
| 10 | |
|
| 11 | | #[derive(Default)] |
| 12 | | pub struct Writer(pub Vec<u8>); |
| 13 | |
|
| 14 | | impl Writer { |
| 15 | 356374× | pub fn u8(&mut self, v: u8) { |
| 16 | 356374× | self.0.push(v); |
| 17 | 356374× | } |
| 18 | 396196× | pub fn u32(&mut self, v: u32) { |
| 19 | 396196× | self.0.extend_from_slice(&v.to_le_bytes()); |
| 20 | 396196× | } |
| 21 | 72252× | pub fn u64(&mut self, v: u64) { |
| 22 | 72252× | self.0.extend_from_slice(&v.to_le_bytes()); |
| 23 | 72252× | } |
| 24 | | |
| 25 | 190162× | pub fn count(&mut self, n: usize) { |
| 26 | 190162× | self.u32(u32::try_from(n).expect("an index count fits in 32 bits")); |
| 27 | 190162× | } |
| 28 | 715175× | pub fn fixed(&mut self, b: &[u8]) { |
| 29 | 715175× | self.0.extend_from_slice(b); |
| 30 | 715175× | } |
| 31 | 115989× | pub fn bytes(&mut self, b: &[u8]) { |
| 32 | 115989× | self.count(b.len()); |
| 33 | 115989× | self.0.extend_from_slice(b); |
| 34 | 115989× | } |
| 35 | 251555× | pub fn object(&mut self, r: &ObjectRef) { |
| 36 | 251555× | self.fixed(&r.0); |
| 37 | 251555× | } |
| 38 | 31662× | pub fn opt_object(&mut self, r: &Option<ObjectRef>) { |
| 39 | 31662× | match r { |
| 40 | 31345× | None => self.u8(0), |
| 41 | 317× | Some(r) => { |
| 42 | 317× | self.u8(1); |
| 43 | 317× | self.object(r); |
| 44 | 317× | } |
| 45 | | } |
| 46 | 31662× | } |
| 47 | | } |
| 48 | |
|
| 49 | | pub struct Reader<'a> { |
| 50 | | buf: &'a [u8], |
| 51 | | pos: usize, |
| 52 | | } |
| 53 | |
|
| 54 | 3× | fn short() -> ObjectError { |
| 55 | 3× | ObjectError::Schema("index: truncated".into()) |
| 56 | 3× | } |
| 57 | |
|
| 58 | | impl<'a> Reader<'a> { |
| 59 | 25988× | pub fn new(buf: &'a [u8]) -> Reader<'a> { |
| 60 | 25988× | Reader { buf, pos: 0 } |
| 61 | 25988× | } |
| 62 | 47552× | pub fn at_end(&self) -> bool { |
| 63 | 47552× | self.pos == self.buf.len() |
| 64 | 47552× | } |
| 65 | 1241538× | fn take(&mut self, n: usize) -> Result<&'a [u8], ObjectError> { |
| 66 | 1241538× | let end = self.pos.checked_add(n).ok_or_else(short)?; |
| 67 | 1241538× | let s = self.buf.get(self.pos..end).ok_or_else(short)?; |
| 68 | 1241535× | self.pos = end; |
| 69 | 1241535× | Ok(s) |
| 70 | 1241538× | } |
| 71 | 243374× | pub fn u8(&mut self) -> Result<u8, ObjectError> { |
| 72 | 243374× | Ok(self.take(1)?[0]) |
| 73 | 243374× | } |
| 74 | 312177× | pub fn u32(&mut self) -> Result<u32, ObjectError> { |
| 75 | 312177× | Ok(u32::from_le_bytes(self.fixed::<4>()?)) |
| 76 | 312177× | } |
| 77 | 55368× | pub fn u64(&mut self) -> Result<u64, ObjectError> { |
| 78 | 55368× | Ok(u64::from_le_bytes(self.fixed::<8>()?)) |
| 79 | 55368× | } |
| 80 | | |
| 81 | | |
| 82 | 64805× | pub fn count(&mut self) -> Result<usize, ObjectError> { |
| 83 | 64805× | let n = self.u32()? as usize; |
| 84 | 64805× | if n > self.buf.len() - self.pos { |
| 85 | 0× | return Err(short()); |
| 86 | 64805× | } |
| 87 | 64805× | Ok(n) |
| 88 | 64805× | } |
| 89 | 890661× | pub fn fixed<const N: usize>(&mut self) -> Result<[u8; N], ObjectError> { |
| 90 | 890661× | Ok(self.take(N)?.try_into().expect("N bytes")) |
| 91 | 890661× | } |
| 92 | 107503× | pub fn bytes(&mut self) -> Result<&'a [u8], ObjectError> { |
| 93 | 107503× | let n = self.u32()? as usize; |
| 94 | 107503× | self.take(n) |
| 95 | 107503× | } |
| 96 | 61919× | pub fn text(&mut self) -> Result<String, ObjectError> { |
| 97 | 61919× | String::from_utf8(self.bytes()?.to_vec()) |
| 98 | 61919× | .map_err(|_| ObjectError::Schema("index: text is not UTF-8".into())) |
| 99 | 61919× | } |
| 100 | 179254× | pub fn object(&mut self) -> Result<ObjectRef, ObjectError> { |
| 101 | 179254× | Ok(ObjectRef(self.fixed::<32>()?)) |
| 102 | 179254× | } |
| 103 | 26581× | pub fn opt_object(&mut self) -> Result<Option<ObjectRef>, ObjectError> { |
| 104 | 26581× | Ok(match self.u8()? { |
| 105 | 26329× | 0 => None, |
| 106 | 252× | _ => Some(self.object()?), |
| 107 | | }) |
| 108 | 26581× | } |
| 109 | | } |
| 110 | |
|
| 111 | | #[cfg(test)] |
| 112 | | mod tests { |
| 113 | | use super::*; |
| 114 | |
|
| 115 | | #[test] |
| 116 | 1× | fn numbers_and_bytes_round_trip_and_truncation_fails() { |
| 117 | 1× | let mut w = Writer::default(); |
| 118 | 1× | w.u8(7); |
| 119 | 1× | w.u32(70_000); |
| 120 | 1× | w.u64(1 << 40); |
| 121 | 1× | w.bytes(b"path/name"); |
| 122 | 1× | w.opt_object(&Some(ObjectRef([3; 32]))); |
| 123 | 1× | w.opt_object(&None); |
| 124 | 1× | let mut r = Reader::new(&w.0); |
| 125 | 1× | assert_eq!(r.u8().unwrap(), 7); |
| 126 | 1× | assert_eq!(r.u32().unwrap(), 70_000); |
| 127 | 1× | assert_eq!(r.u64().unwrap(), 1 << 40); |
| 128 | 1× | assert_eq!(r.text().unwrap(), "path/name"); |
| 129 | 1× | assert_eq!(r.opt_object().unwrap(), Some(ObjectRef([3; 32]))); |
| 130 | 1× | assert_eq!(r.opt_object().unwrap(), None); |
| 131 | 1× | assert!(r.at_end()); |
| 132 | 1× | let mut r = Reader::new(&w.0[..w.0.len() - 3]); |
| 133 | 1× | r.fixed::<13>().unwrap(); |
| 134 | 1× | assert!(r.text().is_ok()); |
| 135 | 1× | assert!(r.opt_object().is_err()); |
| 136 | 1× | } |
| 137 | | } |