use std::convert::TryFrom;
use serde::{ser::SerializeSeq, Deserialize, Serialize};
use super::{
error::{ValueAccessError, ValueAccessErrorKind, ValueAccessResult},
Error,
Iter,
RawBinary,
RawBson,
RawDocument,
RawRegex,
Result,
};
use crate::{
oid::ObjectId,
raw::{RawBsonVisitor, RAW_ARRAY_NEWTYPE},
spec::{BinarySubtype, ElementType},
Bson,
DateTime,
Timestamp,
};
#[derive(PartialEq)]
#[repr(transparent)]
pub struct RawArray {
pub(crate) doc: RawDocument,
}
impl RawArray {
pub(crate) fn from_doc(doc: &RawDocument) -> &RawArray {
unsafe { &*(doc as *const RawDocument as *const RawArray) }
}
pub fn get(&self, index: usize) -> Result<Option<RawBson<'_>>> {
self.into_iter().nth(index).transpose()
}
fn get_with<'a, T>(
&'a self,
index: usize,
expected_type: ElementType,
f: impl FnOnce(RawBson<'a>) -> Option<T>,
) -> ValueAccessResult<T> {
let bson = self
.get(index)
.map_err(|e| ValueAccessError {
key: index.to_string(),
kind: ValueAccessErrorKind::InvalidBson(e),
})?
.ok_or(ValueAccessError {
key: index.to_string(),
kind: ValueAccessErrorKind::NotPresent,
})?;
match f(bson) {
Some(t) => Ok(t),
None => Err(ValueAccessError {
key: index.to_string(),
kind: ValueAccessErrorKind::UnexpectedType {
expected: expected_type,
actual: bson.element_type(),
},
}),
}
}
pub fn get_f64(&self, index: usize) -> ValueAccessResult<f64> {
self.get_with(index, ElementType::Double, RawBson::as_f64)
}
pub fn get_str(&self, index: usize) -> ValueAccessResult<&str> {
self.get_with(index, ElementType::String, RawBson::as_str)
}
pub fn get_document(&self, index: usize) -> ValueAccessResult<&RawDocument> {
self.get_with(index, ElementType::EmbeddedDocument, RawBson::as_document)
}
pub fn get_array(&self, index: usize) -> ValueAccessResult<&RawArray> {
self.get_with(index, ElementType::Array, RawBson::as_array)
}
pub fn get_binary(&self, index: usize) -> ValueAccessResult<RawBinary<'_>> {
self.get_with(index, ElementType::Binary, RawBson::as_binary)
}
pub fn get_object_id(&self, index: usize) -> ValueAccessResult<ObjectId> {
self.get_with(index, ElementType::ObjectId, RawBson::as_object_id)
}
pub fn get_bool(&self, index: usize) -> ValueAccessResult<bool> {
self.get_with(index, ElementType::Boolean, RawBson::as_bool)
}
pub fn get_datetime(&self, index: usize) -> ValueAccessResult<DateTime> {
self.get_with(index, ElementType::DateTime, RawBson::as_datetime)
}
pub fn get_regex(&self, index: usize) -> ValueAccessResult<RawRegex<'_>> {
self.get_with(index, ElementType::RegularExpression, RawBson::as_regex)
}
pub fn get_timestamp(&self, index: usize) -> ValueAccessResult<Timestamp> {
self.get_with(index, ElementType::Timestamp, RawBson::as_timestamp)
}
pub fn get_i32(&self, index: usize) -> ValueAccessResult<i32> {
self.get_with(index, ElementType::Int32, RawBson::as_i32)
}
pub fn get_i64(&self, index: usize) -> ValueAccessResult<i64> {
self.get_with(index, ElementType::Int64, RawBson::as_i64)
}
pub fn as_bytes(&self) -> &[u8] {
self.doc.as_bytes()
}
}
impl std::fmt::Debug for RawArray {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RawArray")
.field("data", &hex::encode(self.doc.as_bytes()))
.finish()
}
}
impl TryFrom<&RawArray> for Vec<Bson> {
type Error = Error;
fn try_from(arr: &RawArray) -> Result<Vec<Bson>> {
arr.into_iter()
.map(|result| {
let rawbson = result?;
Bson::try_from(rawbson)
})
.collect()
}
}
impl<'a> IntoIterator for &'a RawArray {
type IntoIter = RawArrayIter<'a>;
type Item = Result<RawBson<'a>>;
fn into_iter(self) -> RawArrayIter<'a> {
RawArrayIter {
inner: self.doc.into_iter(),
}
}
}
pub struct RawArrayIter<'a> {
inner: Iter<'a>,
}
impl<'a> Iterator for RawArrayIter<'a> {
type Item = Result<RawBson<'a>>;
fn next(&mut self) -> Option<Result<RawBson<'a>>> {
match self.inner.next() {
Some(Ok((_, v))) => Some(Ok(v)),
Some(Err(e)) => Some(Err(e)),
None => None,
}
}
}
impl<'de: 'a, 'a> Deserialize<'de> for &'a RawArray {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
match deserializer.deserialize_newtype_struct(RAW_ARRAY_NEWTYPE, RawBsonVisitor)? {
RawBson::Array(d) => Ok(d),
RawBson::Binary(b) if b.subtype == BinarySubtype::Generic => {
let doc = RawDocument::new(b.bytes).map_err(serde::de::Error::custom)?;
Ok(RawArray::from_doc(doc))
}
b => Err(serde::de::Error::custom(format!(
"expected raw array reference, instead got {:?}",
b
))),
}
}
}
impl<'a> Serialize for &'a RawArray {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
struct SeqSerializer<'a>(&'a RawArray);
impl<'a> Serialize for SeqSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
let mut seq = serializer.serialize_seq(None)?;
for v in self.0 {
let v = v.map_err(serde::ser::Error::custom)?;
seq.serialize_element(&v)?;
}
seq.end()
} else {
serializer.serialize_bytes(self.0.as_bytes())
}
}
}
serializer.serialize_newtype_struct(RAW_ARRAY_NEWTYPE, &SeqSerializer(self))
}
}