polodb_bson 0.2.0

BSON lib for PoloDB
Documentation
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);  // not standard, use vli
                    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);  // not standard, use vli
                    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]
    }

}