summaryrefslogtreecommitdiff
path: root/src/ion.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ion.rs')
-rw-r--r--src/ion.rs201
1 files changed, 182 insertions, 19 deletions
diff --git a/src/ion.rs b/src/ion.rs
index 6773539..cbfae24 100644
--- a/src/ion.rs
+++ b/src/ion.rs
@@ -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
}
+