Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ hex = "^0.2"

[dev-dependencies]
serde_derive = "1.0"

[features]
unsigned_conversion = []
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
Encoding and decoding support for BSON in Rust

## Useful links
- [API Documentation](https://docs.rs/bson/)
- [Serde](https://serde.rs/)

* [API Documentation](https://docs.rs/bson/)
* [Serde](https://serde.rs/)

## Installation

This crate works with Cargo and can be found on
[crates.io](https://crates.io/crates/bson) with a `Cargo.toml` like:

Expand All @@ -20,6 +22,7 @@ bson = "0.11"
```

## Usage

Link the library in _main.rs_:

```rust
Expand All @@ -32,7 +35,7 @@ Prepare your struct for Serde serialization:
```rust
#[derive(Serialize, Deserialize, Debug)]
pub struct Person {
#[serde(rename = "_id")] // Use MongoDB's special primary key field name when serializing
#[serde(rename = "_id")] // Use MongoDB's special primary key field name when serializing
pub id: String,
pub name: String,
pub age: i32
Expand Down Expand Up @@ -95,3 +98,5 @@ fn test_compat_u2f() {
```

In this example, we added an attribute `#[serde(with = "bson::compat::u2f")]` on field `x`, which will tell `serde` to use the `bson::compat::u2f::serialize` and `bson::compat::u2f::deserialize` methods to process this field.

More recently, the ability to cast unsigned integers to signed integers has been added behind the `unsigned_conversion` feature. It makes of the unstable nightly `try_from` API to avoid undefined behavior, and will throw an error if the number being cast is larger than the maximum value of a 32-bit integer.
36 changes: 34 additions & 2 deletions serde-tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::collections::{BTreeMap, HashSet};
use serde::{Deserialize, Serialize, Deserializer};
use serde::de::Unexpected;

use bson::{Bson, Encoder, Decoder, DecoderError};
use bson::{Bson, Encoder, Decoder, DecoderError, to_bson};

macro_rules! bson {
([]) => {{ bson::Bson::Array(Vec::new()) }};
Expand Down Expand Up @@ -132,7 +132,7 @@ fn application_decode_error() {
struct Range10(usize);
impl<'de> Deserialize<'de> for Range10 {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Range10, D::Error> {
let x: usize = try!(Deserialize::deserialize(d));
let x: usize = Deserialize::deserialize(d)?;
if x > 10 {
Err(serde::de::Error::invalid_value(Unexpected::Unsigned(x as u64),
&"more than 10"))
Expand Down Expand Up @@ -577,3 +577,35 @@ fn empty_arrays2() {
});
assert_eq!(v, t!(Deserialize::deserialize(d)));
}

#[test]
fn unsigned() {
#[derive(Serialize, Deserialize)]
struct Foo {
pub a: u16,
pub b: u32,
pub c: u64,
}

let res = to_bson(&Foo {
a: 1u16,
b: 2u32,
c: 3u64,
});

if cfg!(feature = "unsigned_conversion") {
assert!(res.is_ok())
} else {
assert!(res.is_err())
}
}

#[test]
fn unsigned_overflow() {
#[derive(Serialize, Deserialize)]
struct Foo {
a: u64
}

assert!(to_bson(&Foo { a: u64::max_value() }).is_err())
}
6 changes: 3 additions & 3 deletions src/bson.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,15 @@ impl Display for Bson {
&Bson::FloatingPoint(f) => write!(fmt, "{}", f),
&Bson::String(ref s) => write!(fmt, "\"{}\"", s),
&Bson::Array(ref vec) => {
try!(write!(fmt, "["));
write!(fmt, "[")?;

let mut first = true;
for bson in vec.iter() {
if !first {
try!(write!(fmt, ", "));
write!(fmt, ", ")?;
}

try!(write!(fmt, "{}", bson));
write!(fmt, "{}", bson)?;
first = false;
}

Expand Down
60 changes: 30 additions & 30 deletions src/decoder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,18 @@ use oid;
use serde::de::Deserialize;

fn read_string<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> DecoderResult<String> {
let len = try!(reader.read_i32::<LittleEndian>());
let len = reader.read_i32::<LittleEndian>()?;

let s = if utf8_lossy {
let mut buf = Vec::with_capacity(len as usize - 1);
try!(reader.take(len as u64 - 1).read_to_end(&mut buf));
reader.take(len as u64 - 1).read_to_end(&mut buf)?;
String::from_utf8_lossy(&buf).to_string()
} else {
let mut s = String::with_capacity(len as usize - 1);
try!(reader.take(len as u64 - 1).read_to_string(&mut s));
reader.take(len as u64 - 1).read_to_string(&mut s)?;
s
};
try!(reader.read_u8()); // The last 0x00
reader.read_u8()?; // The last 0x00

Ok(s)
}
Expand All @@ -60,14 +60,14 @@ fn read_cstring<R: Read + ?Sized>(reader: &mut R) -> DecoderResult<String> {
let mut v = Vec::new();

loop {
let c = try!(reader.read_u8());
let c = reader.read_u8()?;
if c == 0 {
break;
}
v.push(c);
}

Ok(try!(String::from_utf8(v)))
Ok(String::from_utf8(v)?)
}

#[inline]
Expand All @@ -85,17 +85,17 @@ pub fn decode_document<R: Read + ?Sized>(reader: &mut R) -> DecoderResult<Docume
let mut doc = Document::new();

// disregard the length: using Read::take causes infinite type recursion
try!(read_i32(reader));
read_i32(reader)?;

loop {
let tag = try!(reader.read_u8());
let tag = reader.read_u8()?;

if tag == 0 {
break;
}

let key = try!(read_cstring(reader));
let val = try!(decode_bson(reader, tag, false));
let key = read_cstring(reader)?;
let val = decode_bson(reader, tag, false)?;

doc.insert(key, val);
}
Expand All @@ -108,17 +108,17 @@ pub fn decode_document_utf8_lossy<R: Read + ?Sized>(reader: &mut R) -> DecoderRe
let mut doc = Document::new();

// disregard the length: using Read::take causes infinite type recursion
try!(read_i32(reader));
read_i32(reader)?;

loop {
let tag = try!(reader.read_u8());
let tag = reader.read_u8()?;

if tag == 0 {
break;
}

let key = try!(read_cstring(reader));
let val = try!(decode_bson(reader, tag, true));
let key = read_cstring(reader)?;
let val = decode_bson(reader, tag, true)?;

doc.insert(key, val);
}
Expand All @@ -130,16 +130,16 @@ fn decode_array<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> DecoderRe
let mut arr = Array::new();

// disregard the length: using Read::take causes infinite type recursion
try!(read_i32(reader));
read_i32(reader)?;

loop {
let tag = try!(reader.read_u8());
let tag = reader.read_u8()?;
if tag == 0 {
break;
}

// check that the key is as expected
let key = try!(read_cstring(reader));
let key = read_cstring(reader)?;
match key.parse::<usize>() {
Err(..) => return Err(DecoderError::InvalidArrayKey(arr.len(), key)),
Ok(idx) => {
Expand All @@ -149,7 +149,7 @@ fn decode_array<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> DecoderRe
}
}

let val = try!(decode_bson(reader, tag, utf8_lossy));
let val = decode_bson(reader, tag, utf8_lossy)?;
arr.push(val)
}

Expand All @@ -159,46 +159,46 @@ fn decode_array<R: Read + ?Sized>(reader: &mut R, utf8_lossy: bool) -> DecoderRe
fn decode_bson<R: Read + ?Sized>(reader: &mut R, tag: u8, utf8_lossy: bool) -> DecoderResult<Bson> {
use spec::ElementType::*;
match spec::ElementType::from(tag) {
Some(FloatingPoint) => Ok(Bson::FloatingPoint(try!(reader.read_f64::<LittleEndian>()))),
Some(FloatingPoint) => Ok(Bson::FloatingPoint(reader.read_f64::<LittleEndian>()?)),
Some(Utf8String) => read_string(reader, utf8_lossy).map(Bson::String),
Some(EmbeddedDocument) => decode_document(reader).map(Bson::Document),
Some(Array) => decode_array(reader, utf8_lossy).map(Bson::Array),
Some(Binary) => {
let len = try!(read_i32(reader));
let subtype = BinarySubtype::from(try!(reader.read_u8()));
let len = read_i32(reader)?;
let subtype = BinarySubtype::from(reader.read_u8()?);
let mut data = Vec::with_capacity(len as usize);
try!(reader.take(len as u64).read_to_end(&mut data));
reader.take(len as u64).read_to_end(&mut data)?;
Ok(Bson::Binary(subtype, data))
}
Some(ObjectId) => {
let mut objid = [0; 12];
for x in &mut objid {
*x = try!(reader.read_u8());
*x = reader.read_u8()?;
}
Ok(Bson::ObjectId(oid::ObjectId::with_bytes(objid)))
}
Some(Boolean) => Ok(Bson::Boolean(try!(reader.read_u8()) != 0)),
Some(Boolean) => Ok(Bson::Boolean(reader.read_u8()? != 0)),
Some(NullValue) => Ok(Bson::Null),
Some(RegularExpression) => {
let pat = try!(read_cstring(reader));
let opt = try!(read_cstring(reader));
let pat = read_cstring(reader)?;
let opt = read_cstring(reader)?;
Ok(Bson::RegExp(pat, opt))
}
Some(JavaScriptCode) => read_string(reader, utf8_lossy).map(Bson::JavaScriptCode),
Some(JavaScriptCodeWithScope) => {
// disregard the length:
// using Read::take causes infinite type recursion
try!(read_i32(reader));
read_i32(reader)?;

let code = try!(read_string(reader, utf8_lossy));
let scope = try!(decode_document(reader));
let code = read_string(reader, utf8_lossy)?;
let scope = decode_document(reader)?;
Ok(Bson::JavaScriptCodeWithScope(code, scope))
}
Some(Integer32Bit) => read_i32(reader).map(Bson::I32),
Some(Integer64Bit) => read_i64(reader).map(Bson::I64),
Some(TimeStamp) => read_i64(reader).map(Bson::TimeStamp),
Some(UtcDatetime) => {
let time = try!(read_i64(reader));
let time = read_i64(reader)?;
Ok(Bson::UtcDatetime(Utc.timestamp(time / 1000, (time % 1000) as u32 * 1000000)))
}
Some(Symbol) => read_string(reader, utf8_lossy).map(Bson::Symbol),
Expand Down
36 changes: 27 additions & 9 deletions src/decoder/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,24 @@ impl<'de> Deserialize<'de> for Bson {
}
}

#[cfg(feature = "unsigned_conversion")]
fn visit_unsigned_int<
T: Copy + ::std::convert::TryInto<i32> + Into<u64>,
E: Error
>(value: T) -> Result<Bson, E> {
value.try_into()
.map(Bson::I32)
.map_err(|_| de::Error::invalid_value(
Unexpected::Unsigned(value.into()),
&format!("an integer less than or equal to {}", i32::max_value()).as_str()
))
}

#[cfg(not(feature = "unsigned_conversion"))]
fn visit_unsigned_int<T: Into<u64>, E: Error>(value: T) -> Result<Bson, E> {
Err(Error::invalid_type(Unexpected::Unsigned(value.into()), &"a signed integer"))
}

impl<'de> Visitor<'de> for BsonVisitor {
type Value = Bson;

Expand All @@ -79,7 +97,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
fn visit_u8<E>(self, value: u8) -> Result<Bson, E>
where E: Error
{
Err(Error::invalid_type(Unexpected::Unsigned(value as u64), &"a signed integer"))
visit_unsigned_int(value)
}

#[inline]
Expand All @@ -93,7 +111,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
fn visit_u16<E>(self, value: u16) -> Result<Bson, E>
where E: Error
{
Err(Error::invalid_type(Unexpected::Unsigned(value as u64), &"a signed integer"))
visit_unsigned_int(value)
}

#[inline]
Expand All @@ -107,7 +125,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
fn visit_u32<E>(self, value: u32) -> Result<Bson, E>
where E: Error
{
Err(Error::invalid_type(Unexpected::Unsigned(value as u64), &"a signed integer"))
visit_unsigned_int(value)
}

#[inline]
Expand All @@ -121,7 +139,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
fn visit_u64<E>(self, value: u64) -> Result<Bson, E>
where E: Error
{
Err(Error::invalid_type(Unexpected::Unsigned(value), &"a signed integer"))
visit_unsigned_int(value)
}

#[inline]
Expand Down Expand Up @@ -175,7 +193,7 @@ impl<'de> Visitor<'de> for BsonVisitor {
fn visit_map<V>(self, visitor: V) -> Result<Bson, V::Error>
where V: MapAccess<'de>
{
let values = try!(OrderedDocumentVisitor::new().visit_map(visitor));
let values = OrderedDocumentVisitor::new().visit_map(visitor)?;
Ok(Bson::from_extended_document(values.into()))
}
}
Expand Down Expand Up @@ -405,14 +423,14 @@ impl<'de> VariantAccess<'de> for VariantDecoder {
fn newtype_variant_seed<T>(mut self, seed: T) -> DecoderResult<T::Value>
where T: DeserializeSeed<'de>
{
let dec = Decoder::new(try!(self.val.take().ok_or(DecoderError::EndOfStream)));
let dec = Decoder::new(self.val.take().ok_or(DecoderError::EndOfStream)?);
seed.deserialize(dec)
}

fn tuple_variant<V>(mut self, _len: usize, visitor: V) -> DecoderResult<V::Value>
where V: Visitor<'de>
{
if let Bson::Array(fields) = try!(self.val.take().ok_or(DecoderError::EndOfStream)) {
if let Bson::Array(fields) = self.val.take().ok_or(DecoderError::EndOfStream)? {

let de = SeqDecoder {
len: fields.len(),
Expand All @@ -430,7 +448,7 @@ impl<'de> VariantAccess<'de> for VariantDecoder {
-> DecoderResult<V::Value>
where V: Visitor<'de>
{
if let Bson::Document(fields) = try!(self.val.take().ok_or(DecoderError::EndOfStream)) {
if let Bson::Document(fields) = self.val.take().ok_or(DecoderError::EndOfStream)? {
let de = MapDecoder {
len: fields.len(),
iter: fields.into_iter(),
Expand Down Expand Up @@ -549,7 +567,7 @@ impl<'de> MapAccess<'de> for MapDecoder {
fn next_value_seed<V>(&mut self, seed: V) -> DecoderResult<V::Value>
where V: DeserializeSeed<'de>
{
let value = try!(self.value.take().ok_or(DecoderError::EndOfStream));
let value = self.value.take().ok_or(DecoderError::EndOfStream)?;
let de = Decoder::new(value);
seed.deserialize(de)
}
Expand Down
Loading