use std::ops;
use super::value::{Value, ty_int};
use crate::vli;
use crate::BsonResult;
use crate::error::{BsonErr, parse_error_reason};
use crate::document::Document;
use crate::object_id::ObjectId;
#[derive(Debug, Clone)]
pub struct Array(Vec<Value>);
pub struct Iter<'a> {
arr: &'a Array,
index: u32,
}
impl<'a> std::iter::Iterator for Iter<'a> {
type Item = &'a Value;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.arr.len() {
return None;
}
let result: &'a Value = &self.arr[self.index as usize];
self.index += 1;
Some(result)
}
}
impl Array {
pub fn new() -> Array {
let data = vec![];
Array(data)
}
pub fn iter(&self) -> Iter {
Iter {
arr: self,
index: 0,
}
}
pub fn push(&mut self, elm: Value) {
self.0.push(elm)
}
#[inline]
pub fn len(&self) -> u32 {
self.0.len() as u32
}
}
impl Array {
pub fn to_bytes(&self) -> BsonResult<Vec<u8>> {
let mut result = vec![];
vli::encode(&mut result, self.0.len() as i64)?;
for item in &self.0 {
match item {
Value::Null => {
result.push(ty_int::NULL);
}
Value::Double(num) => {
result.push(ty_int::DOUBLE);
result.extend_from_slice(&num.to_be_bytes());
}
Value::Boolean(bl) => {
result.push(ty_int::BOOLEAN);
if *bl {
result.push(0x00);
} else {
result.push(0x01);
}
}
Value::Int(int_num) => {
result.push(ty_int::INT); vli::encode(&mut result, *int_num).expect("encode vli error");
}
Value::String(str) => {
result.push(ty_int::STRING);
result.extend_from_slice(str.as_bytes());
result.push(0);
}
Value::ObjectId(oid) => {
result.push(ty_int::OBJECT_ID);
oid.serialize(&mut result)?;
}
Value::Array(arr) => {
result.push(ty_int::ARRAY);
let buffer = arr.to_bytes()?;
vli::encode(&mut result, buffer.len() as i64)?;
result.extend(&buffer);
}
Value::Document(doc) => {
result.push(ty_int::DOCUMENT);
let buffer = doc.to_bytes()?;
vli::encode(&mut result, buffer.len() as i64)?;
result.extend(&buffer);
}
Value::Binary(bin) => {
result.push(ty_int::BINARY);
vli::encode(&mut result, bin.len() as i64)?;
result.extend(bin.as_ref());
}
Value::UTCDateTime(datetime) => {
result.push(ty_int::UTC_DATETIME); let ts = datetime.timestamp();
vli::encode(&mut result, ts as i64).expect("encode vli error");
}
}
}
result.push(0);
Ok(result)
}
pub unsafe fn from_bytes(bytes: &[u8]) -> BsonResult<Array> {
let mut arr = Array::new();
let mut ptr: usize = 0;
let (arr_len, offset) = vli::decode_u64(&bytes[ptr..])?;
ptr += offset;
let mut counter: u64 = 0;
while bytes[ptr] != 0 && counter < arr_len {
let byte = bytes[ptr];
ptr += 1;
match byte {
ty_int::NULL => {
arr.0.push(Value::Null);
}
ty_int::DOUBLE => {
let mut buffer: [u8; 8] = [0; 8];
buffer.copy_from_slice(&bytes[ptr..(ptr+8)]);
let num = f64::from_be_bytes(buffer);
arr.0.push(Value::Double(num));
ptr += 8;
}
ty_int::BOOLEAN => {
let bl_value = bytes[ptr];
ptr += 1;
arr.0.push(Value::Boolean(if bl_value != 0 {
true
} else {
false
}));
}
ty_int::INT => {
let (integer, offset) = vli::decode_u64(&bytes[ptr..])?;
ptr += offset;
arr.0.push(Value::Int(integer as i64));
}
ty_int::STRING => {
let (value, to_ptr) = Document::parse_key(bytes, ptr)?;
ptr = to_ptr;
arr.0.push(value.into());
}
ty_int::OBJECT_ID => {
let mut buffer: [u8; 12] = [0; 12];
buffer.copy_from_slice(&bytes[ptr..(ptr+12)]);
ptr += 12;
let oid = ObjectId::deserialize(&buffer)?;
arr.0.push(oid.into());
}
ty_int::ARRAY => {
let (len, offset) = vli::decode_u64(&bytes[ptr..])?;
ptr += offset;
let mut buffer = Vec::with_capacity(len as usize);
buffer.extend_from_slice(&bytes[ptr..(ptr+len as usize)]);
ptr += len as usize;
let sub_arr = Array::from_bytes(&buffer)?;
arr.0.push(sub_arr.into());
}
ty_int::DOCUMENT => {
let (len, offset) = vli::decode_u64(&bytes[ptr..])?;
ptr += offset;
let mut buffer = Vec::with_capacity(len as usize);
buffer.extend_from_slice(&bytes[ptr..(ptr+len as usize)]);
ptr += len as usize;
let sub_doc = Document::from_bytes(&buffer)?;
arr.0.push(sub_doc.into());
}
ty_int::BINARY => {
let (len, offset) = vli::decode_u64(&bytes[ptr..])?;
ptr += offset;
let mut buffer = Vec::with_capacity(len as usize);
buffer.extend_from_slice(&bytes[ptr..(ptr+len as usize)]);
ptr += len as usize;
arr.0.push(buffer.into());
}
_ => return Err(BsonErr::ParseError(parse_error_reason::UNEXPECTED_DOCUMENT_FLAG.into())),
}
counter += 1;
}
Ok(arr)
}
}
impl ops::Index<usize> for Array {
type Output = Value;
fn index(&self, index: usize) -> &Value {
&self.0[index]
}
}