diff options
Diffstat (limited to 'src/ion.rs')
-rw-r--r-- | src/ion.rs | 201 |
1 files changed, 182 insertions, 19 deletions
@@ -1,4 +1,4 @@ -use std::iter::Copied; +use std::{iter::Copied, cmp::Ordering}; pub enum IonType { Null = 0x00, @@ -26,6 +26,56 @@ impl IonValue { IonValue(vec![0x0F]) } + pub fn new_symbol(value: usize) -> IonValue { + let mut buf = Vec::new(); + if value == 0 { + buf.push(0x70); + } else { + let octets = ((usize::BITS - value.leading_zeros() + 7) >> 3) as usize; + let tl = 0x70 | octets as u8; + buf.push(tl); + let be = value.to_be_bytes(); + let start = be.len() - octets; + for b in &be[start..] { + buf.push(*b); + } + } + IonValue(buf) + } + + pub fn new_f64(value: f64) -> IonValue { + let b = value.to_be_bytes(); + IonValue(vec![0x48, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) + } + + pub fn new_i32(value: i32) -> IonValue { + IonValue::from(value as i64) + } + + pub fn new_bool(value: bool) -> IonValue { + if value { + IonValue(vec![0x11]) + } else { + IonValue(vec![0x10]) + } + } + + pub fn new_string<S>(value: S) -> IonValue + where S: AsRef<str> + { + let bytes = value.as_ref().as_bytes(); + let mut v = Vec::with_capacity(2 + bytes.len()); + if bytes.len() < 14 { + v.push(0x80 | (bytes.len() as u8)); + } else { + v.push(0x8E); + push_varuint(&mut v, bytes.len()); + } + v.extend(bytes); + IonValue(v) + } + + pub fn ion_type(&self) -> u8 { self.0[0] >> 4 } @@ -62,6 +112,10 @@ impl IonValue { self.reader().next_usize() } + pub fn to_symbol_id(&self) -> usize { + self.reader().next_symbol_id() + } + } impl From<Vec<u8>> for IonValue { @@ -74,6 +128,47 @@ impl From<Vec<u8>> for IonValue { } } +impl From<usize> for IonValue { + fn from(value: usize) -> Self { + let mut buf = Vec::new(); + if value == 0 { + buf.push(0x20); + } else { + let v = value; + let octets = ((usize::BITS - v.leading_zeros() + 7) >> 3) as usize; + let tl = 0x20 | octets as u8; + buf.push(tl); + let be = v.to_be_bytes(); + let start = be.len() - octets; + for b in &be[start..] { + buf.push(*b); + } + } + IonValue(buf) + } +} + +impl From<i64> for IonValue { + fn from(value: i64) -> Self { + let mut buf = Vec::new(); + let (mut tl, v) = match value.cmp(&0) { + Ordering::Equal => return IonValue(vec![0x20]), + Ordering::Greater => (0x20, value), + Ordering::Less => (0x30, -value), + }; + + let octets = ((usize::BITS - v.leading_zeros() + 7) >> 3) as usize; + tl |= octets as u8; + buf.push(tl); + let be = v.to_be_bytes(); + let start = be.len() - octets; + for b in &be[start..] { + buf.push(*b); + } + IonValue(buf) + } +} + pub struct IonReader<T> { iter: T, @@ -141,21 +236,49 @@ impl <T> IonReader<T> pub fn next_value(&mut self) -> IonValue { self.prepare_next(); let tl = self.next_byte(); - let (mut buf, len) = match tl & 0x0F { - 0 | 15 => (vec![tl], 0), - 14 => { - let l = self.next_varuint(); - let mut v = Vec::with_capacity(5 + l); - v.push(tl); - push_varuint(&mut v, l); - (v, l) + let (mut buf, len) = match tl & 0xF0 { + 0x10 => (vec![tl], 0), // bool + 0xD0 => { // struct + match tl & 0x0F { + 0 | 15 => (vec![tl], 0), + 1 | 14 => { + let l = self.next_varuint(); + let mut v = Vec::with_capacity(5 + l); + v.push(tl); + push_varuint(&mut v, l); + (v, l) + }, + len => { + let l = len.into(); + let mut v = Vec::with_capacity(5 + l); + v.push(tl); + (v, l) + } + } }, - len => { - let l = len.into(); - let mut v = Vec::with_capacity(5 + l); - v.push(tl); - (v, l) - } + 0x00 | 0x20 | 0x30 | 0x40 | + 0x50 | 0x60 | 0x70 | 0x80 | + 0x90 | 0xA0 | 0xB0 | 0xC0 | + 0xE0 => + { + match tl & 0x0F { + 0 | 15 => (vec![tl], 0), + 14 => { + let l = self.next_varuint(); + let mut v = Vec::with_capacity(5 + l); + v.push(tl); + push_varuint(&mut v, l); + (v, l) + }, + len => { + let l = len.into(); + let mut v = Vec::with_capacity(5 + l); + v.push(tl); + (v, l) + } + } + }, + _ => panic!("unsupported ion type"), }; for _ in 0..len { let b = self.next_byte(); @@ -185,16 +308,55 @@ impl <T> IonReader<T> value } + pub fn next_symbol_id(&mut self) -> usize { + self.prepare_next(); + let tl = self.next_byte(); + if tl & 0xF0 != 0x70 { + panic!("Not a symbol"); + } + + let len = self.extract_length(tl); + if len * 8 > usize::BITS as usize { + panic!("Symbol id too large for usize"); + } + + let mut value = 0; + for _ in 0..len { + let b = self.next_byte(); + value <<= 8; + value |= b as usize; + } + value + } + + fn next_byte(&mut self) -> u8 { self.offset += 1; self.iter.next().expect("Missing data") } fn extract_length(&mut self, tl: u8) -> usize { - match tl & 0x0F { - 0 | 15 => 0, - 14 => self.next_varuint(), - len => len.into(), + match tl & 0xF0 { + 0x10 => 0, // bool + 0xD0 => { // struct + match tl & 0x0F { + 0 | 15 => 0, + 1 | 14 => self.next_varuint(), + len => len.into(), + } + }, + 0x00 | 0x20 | 0x30 | 0x40 | + 0x50 | 0x60 | 0x70 | 0x80 | + 0x90 | 0xA0 | 0xB0 | 0xC0 | + 0xE0 => + { + match tl & 0x0F { + 0 | 15 => 0, + 14 => self.next_varuint(), + len => len.into(), + } + } + _ => panic!("Unsupported Ion type"), } } @@ -239,3 +401,4 @@ fn parse_varuint(buf: &[u8]) -> usize { } value } + |