use std::str;
use std::fmt;
use bson::{ Bson, to_bson };
use serde::{
ser::{ Serialize, Serializer, SerializeSeq },
de::{ Deserialize, Deserializer, Visitor, SeqAccess },
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Order {
Ascending = 1,
Descending = -1,
}
impl Default for Order {
fn default() -> Self {
Order::Ascending
}
}
impl From<Order> for Bson {
fn from(order: Order) -> Self {
Bson::I32(order as _)
}
}
impl Serialize for Order {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_i32(*self as _)
}
}
impl<'a> Deserialize<'a> for Order {
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
de.deserialize_i32(OrderVisitor)
}
}
struct OrderVisitor;
impl<'a> Visitor<'a> for OrderVisitor {
type Value = Order;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"an integer expressing ordering: {} or {}",
Order::Ascending as i32,
Order::Descending as i32,
)
}
fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<Self::Value, E> {
if v == Order::Ascending as i64 {
Ok(Order::Ascending)
} else if v == Order::Descending as i64 {
Ok(Order::Descending)
} else {
Err(E::custom(format!("invalid ordering: {}", v)))
}
}
fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Self::Value, E> {
if v == Order::Ascending as u64 {
Ok(Order::Ascending)
} else {
Err(E::custom(format!("invalid ordering: {}", v)))
}
}
#[allow(clippy::float_cmp, clippy::cast_lossless, clippy::cast_precision_loss)]
fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<Self::Value, E> {
if v == Order::Ascending as i32 as f64 {
Ok(Order::Ascending)
} else if v == Order::Descending as i32 as f64 {
Ok(Order::Descending)
} else {
Err(E::custom(format!("invalid ordering: {}", v)))
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum IndexType {
Ordered(Order),
Text,
Hashed,
Geo2D,
Geo2DSphere,
GeoHaystack,
}
impl From<IndexType> for Bson {
fn from(index_type: IndexType) -> Self {
match index_type {
IndexType::Ordered(order) => Bson::from(order),
IndexType::Text => Bson::from("text"),
IndexType::Hashed => Bson::from("hashed"),
IndexType::Geo2D => Bson::from("2d"),
IndexType::Geo2DSphere => Bson::from("2dsphere"),
IndexType::GeoHaystack => Bson::from("geoHaystack"),
}
}
}
impl Serialize for IndexType {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
Bson::from(*self).serialize(ser)
}
}
impl<'a> Deserialize<'a> for IndexType {
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
de.deserialize_any(IndexTypeVisitor)
}
}
struct IndexTypeVisitor;
impl<'a> Visitor<'a> for IndexTypeVisitor {
type Value = IndexType;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an ordering integer or an index type string")
}
fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<Self::Value, E> {
OrderVisitor.visit_i64(v).map(IndexType::Ordered)
}
fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Self::Value, E> {
OrderVisitor.visit_u64(v).map(IndexType::Ordered)
}
fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<Self::Value, E> {
OrderVisitor.visit_f64(v).map(IndexType::Ordered)
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(match v {
"text" => IndexType::Text,
"hashed" => IndexType::Hashed,
"2d" => IndexType::Geo2D,
"2dsphere" => IndexType::Geo2DSphere,
"geoHaystack" => IndexType::GeoHaystack,
_ => Err(E::custom(format!("unrecognized index type: {}", v)))?
})
}
}
bitflags! {
pub struct BsonType: u16 {
const NULL = 0b0000_0000_0000_0001;
const BOOL = 0b0000_0000_0000_0010;
const DOUBLE = 0b0000_0000_0000_0100;
const INT = 0b0000_0000_0000_1000;
const LONG = 0b0000_0000_0001_0000;
const DECIMAL = 0b0000_0000_0010_0000;
const NUMBER = 0b0000_0000_0011_1100;
const OBJECT_ID = 0b0000_0000_0100_0000;
const TIMESTAMP = 0b0000_0000_1000_0000;
const DATE = 0b0000_0001_0000_0000;
const STRING = 0b0000_0010_0000_0000;
const REGEX = 0b0000_0100_0000_0000;
const BINARY = 0b0000_1000_0000_0000;
const ARRAY = 0b0001_0000_0000_0000;
const DOCUMENT = 0b0010_0000_0000_0000;
const JAVASCRIPT = 0b0100_0000_0000_0000;
const JAVASCRIPT_WITH_SCOPE = 0b1000_0000_0000_0000;
}
}
impl Default for BsonType {
fn default() -> Self {
BsonType::NULL
}
}
impl From<BsonType> for Bson {
fn from(bson_type: BsonType) -> Self {
to_bson(&bson_type).unwrap_or_default()
}
}
static TYPE_NAMES: &[(BsonType, &str)] = &[
(BsonType::NULL, "null"),
(BsonType::BOOL, "bool"),
(BsonType::DOUBLE, "double"),
(BsonType::INT, "int"),
(BsonType::LONG, "int"),
(BsonType::DECIMAL, "decimal"),
(BsonType::OBJECT_ID, "objectId"),
(BsonType::TIMESTAMP, "timestamp"),
(BsonType::DATE, "date"),
(BsonType::STRING, "string"),
(BsonType::REGEX, "regex"),
(BsonType::BINARY, "binData"),
(BsonType::ARRAY, "array"),
(BsonType::DOCUMENT, "object"),
(BsonType::JAVASCRIPT, "javascript"),
(BsonType::JAVASCRIPT_WITH_SCOPE, "javascriptWithScope"),
];
impl Serialize for BsonType {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::Error;
match self.bits().count_ones() {
0 => Err(S::Error::custom("at least one type must be specified")),
1 => {
for &(flag, name) in TYPE_NAMES {
if self.contains(flag) {
return serializer.serialize_str(name);
}
}
Err(S::Error::custom("found an unexpected flag"))
}
n => {
let mut seq = serializer.serialize_seq(Some(n as usize))?;
for &(flag, name) in TYPE_NAMES {
if self.contains(flag) {
seq.serialize_element(name)?;
}
}
seq.end()
}
}
}
}
impl<'a> Deserialize<'a> for BsonType {
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_any(BsonTypeVisitor)
}
}
#[derive(Debug, Clone, Copy)]
struct BsonTypeVisitor;
impl BsonTypeVisitor {
fn bitflag_for_name<E: serde::de::Error>(name: &str) -> Result<BsonType, E> {
match TYPE_NAMES.iter().find(|&&(_, n)| n == name) {
Some(&(flag, _)) => Ok(flag),
None => Err(E::custom(format!("unknown BSON type alias: '{}'", name))),
}
}
}
impl<'a> Visitor<'a> for BsonTypeVisitor {
type Value = BsonType;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a BSON type alias string or an array of BSON type alias strings")
}
fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
Self::bitflag_for_name(value)
}
fn visit_seq<A: SeqAccess<'a>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut flags = BsonType::empty();
while let Some(name) = seq.next_element()? {
flags |= Self::bitflag_for_name(name)?;
}
Ok(flags)
}
}
bitflags! {
#[derive(Default)]
pub struct RegexOpts: u8 {
const IGNORE_CASE = 0b0000_0001;
const LINE_ANCHOR = 0b0000_0010;
const EXTENDED = 0b0000_0100;
const DOT_NEWLINE = 0b0000_1000;
}
}
impl From<RegexOpts> for Bson {
fn from(options: RegexOpts) -> Self {
to_bson(&options).unwrap_or_default()
}
}
static OPTION_LETTERS: &[(RegexOpts, u8)] = &[
(RegexOpts::IGNORE_CASE, b'i'),
(RegexOpts::LINE_ANCHOR, b'm'),
(RegexOpts::EXTENDED, b'x'),
(RegexOpts::DOT_NEWLINE, b's'),
];
impl Serialize for RegexOpts {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use std::mem::size_of;
use serde::ser::Error;
let mut letters = [0; size_of::<Self>() * 8];
let mut n = 0;
for &(option, letter) in OPTION_LETTERS {
if self.contains(option) {
letters[n] = letter;
n += 1;
}
}
let s = str::from_utf8(&letters[..n]).map_err(S::Error::custom)?;
serializer.serialize_str(s)
}
}
impl<'a> Deserialize<'a> for RegexOpts {
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_str(RegexOptsVisitor)
}
}
#[derive(Debug, Clone, Copy)]
struct RegexOptsVisitor;
impl<'a> Visitor<'a> for RegexOptsVisitor {
type Value = RegexOpts;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string containing one of [imxs]")
}
fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
let mut options = RegexOpts::empty();
for byte in value.bytes() {
match OPTION_LETTERS.iter().find(|&&(_, b)| b == byte) {
Some(&(option, _)) => options |= option,
None => return Err(E::custom(format!("unexpected regex option: '{}'", byte as char))),
}
}
Ok(options)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum DateTimeType {
Timestamp,
Date,
}
impl From<DateTimeType> for Bson {
fn from(ty: DateTimeType) -> Self {
to_bson(&ty).unwrap_or_default()
}
}