diff --git a/Cargo.toml b/Cargo.toml index 3ab2f3b4..7a0272de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,6 @@ hex = "^0.2" [dev-dependencies] serde_derive = "1.0" + +[features] +unsigned_conversion = [] diff --git a/README.md b/README.md index b6651e69..257e59ad 100644 --- a/README.md +++ b/README.md @@ -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: @@ -20,6 +22,7 @@ bson = "0.11" ``` ## Usage + Link the library in _main.rs_: ```rust @@ -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 @@ -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. diff --git a/serde-tests/test.rs b/serde-tests/test.rs index aaf823f7..b20fac6b 100644 --- a/serde-tests/test.rs +++ b/serde-tests/test.rs @@ -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()) }}; @@ -132,7 +132,7 @@ fn application_decode_error() { struct Range10(usize); impl<'de> Deserialize<'de> for Range10 { fn deserialize>(d: D) -> Result { - 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")) @@ -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()) +} diff --git a/src/bson.rs b/src/bson.rs index 77b7de69..8b8739ae 100644 --- a/src/bson.rs +++ b/src/bson.rs @@ -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; } diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 16895bbd..e8ddce40 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -40,18 +40,18 @@ use oid; use serde::de::Deserialize; fn read_string(reader: &mut R, utf8_lossy: bool) -> DecoderResult { - let len = try!(reader.read_i32::()); + let len = reader.read_i32::()?; 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) } @@ -60,14 +60,14 @@ fn read_cstring(reader: &mut R) -> DecoderResult { 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] @@ -85,17 +85,17 @@ pub fn decode_document(reader: &mut R) -> DecoderResult(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); } @@ -130,16 +130,16 @@ fn decode_array(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::() { Err(..) => return Err(DecoderError::InvalidArrayKey(arr.len(), key)), Ok(idx) => { @@ -149,7 +149,7 @@ fn decode_array(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) } @@ -159,46 +159,46 @@ fn decode_array(reader: &mut R, utf8_lossy: bool) -> DecoderRe fn decode_bson(reader: &mut R, tag: u8, utf8_lossy: bool) -> DecoderResult { use spec::ElementType::*; match spec::ElementType::from(tag) { - Some(FloatingPoint) => Ok(Bson::FloatingPoint(try!(reader.read_f64::()))), + Some(FloatingPoint) => Ok(Bson::FloatingPoint(reader.read_f64::()?)), 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), diff --git a/src/decoder/serde.rs b/src/decoder/serde.rs index 89e2e6e7..2a9fcc2c 100644 --- a/src/decoder/serde.rs +++ b/src/decoder/serde.rs @@ -54,6 +54,24 @@ impl<'de> Deserialize<'de> for Bson { } } +#[cfg(feature = "unsigned_conversion")] +fn visit_unsigned_int< + T: Copy + ::std::convert::TryInto + Into, + E: Error +>(value: T) -> Result { + 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, E: Error>(value: T) -> Result { + Err(Error::invalid_type(Unexpected::Unsigned(value.into()), &"a signed integer")) +} + impl<'de> Visitor<'de> for BsonVisitor { type Value = Bson; @@ -79,7 +97,7 @@ impl<'de> Visitor<'de> for BsonVisitor { fn visit_u8(self, value: u8) -> Result where E: Error { - Err(Error::invalid_type(Unexpected::Unsigned(value as u64), &"a signed integer")) + visit_unsigned_int(value) } #[inline] @@ -93,7 +111,7 @@ impl<'de> Visitor<'de> for BsonVisitor { fn visit_u16(self, value: u16) -> Result where E: Error { - Err(Error::invalid_type(Unexpected::Unsigned(value as u64), &"a signed integer")) + visit_unsigned_int(value) } #[inline] @@ -107,7 +125,7 @@ impl<'de> Visitor<'de> for BsonVisitor { fn visit_u32(self, value: u32) -> Result where E: Error { - Err(Error::invalid_type(Unexpected::Unsigned(value as u64), &"a signed integer")) + visit_unsigned_int(value) } #[inline] @@ -121,7 +139,7 @@ impl<'de> Visitor<'de> for BsonVisitor { fn visit_u64(self, value: u64) -> Result where E: Error { - Err(Error::invalid_type(Unexpected::Unsigned(value), &"a signed integer")) + visit_unsigned_int(value) } #[inline] @@ -175,7 +193,7 @@ impl<'de> Visitor<'de> for BsonVisitor { fn visit_map(self, visitor: V) -> Result 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())) } } @@ -405,14 +423,14 @@ impl<'de> VariantAccess<'de> for VariantDecoder { fn newtype_variant_seed(mut self, seed: T) -> DecoderResult 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(mut self, _len: usize, visitor: V) -> DecoderResult 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(), @@ -430,7 +448,7 @@ impl<'de> VariantAccess<'de> for VariantDecoder { -> DecoderResult 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(), @@ -549,7 +567,7 @@ impl<'de> MapAccess<'de> for MapDecoder { fn next_value_seed(&mut self, seed: V) -> DecoderResult 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) } diff --git a/src/encoder/error.rs b/src/encoder/error.rs index 4b772845..7e233a80 100644 --- a/src/encoder/error.rs +++ b/src/encoder/error.rs @@ -10,6 +10,7 @@ pub enum EncoderError { InvalidMapKeyType(Bson), Unknown(String), UnsupportedUnsignedType, + OutOfRangeUnsignedType(u64), } impl From for EncoderError { @@ -27,6 +28,9 @@ impl fmt::Display for EncoderError { } &EncoderError::Unknown(ref inner) => inner.fmt(fmt), &EncoderError::UnsupportedUnsignedType => write!(fmt, "BSON does not support unsigned type"), + &EncoderError::OutOfRangeUnsignedType(val) => { + write!(fmt, "The provided value {} is larger than the max value for a 32-bit integer", val) + }, } } } @@ -38,8 +42,10 @@ impl error::Error for EncoderError { &EncoderError::InvalidMapKeyType(_) => "Invalid map key type", &EncoderError::Unknown(ref inner) => inner, &EncoderError::UnsupportedUnsignedType => "BSON does not support unsigned type", + &EncoderError::OutOfRangeUnsignedType(_) => "Unsigned integer large than valid range", } } + fn cause(&self) -> Option<&error::Error> { match self { &EncoderError::IoError(ref inner) => Some(inner), diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 2741fb69..d1436be6 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -38,15 +38,15 @@ use bson::Bson; use serde::Serialize; fn write_string(writer: &mut W, s: &str) -> EncoderResult<()> { - try!(writer.write_i32::(s.len() as i32 + 1)); - try!(writer.write_all(s.as_bytes())); - try!(writer.write_u8(0)); + writer.write_i32::(s.len() as i32 + 1)?; + writer.write_all(s.as_bytes())?; + writer.write_u8(0)?; Ok(()) } fn write_cstring(writer: &mut W, s: &str) -> EncoderResult<()> { - try!(writer.write_all(s.as_bytes())); - try!(writer.write_u8(0)); + writer.write_all(s.as_bytes())?; + writer.write_u8(0)?; Ok(()) } @@ -68,13 +68,15 @@ fn write_f64(writer: &mut W, val: f64) -> EncoderResult<()> { fn encode_array(writer: &mut W, arr: &[Bson]) -> EncoderResult<()> { let mut buf = Vec::new(); for (key, val) in arr.iter().enumerate() { - try!(encode_bson(&mut buf, &key.to_string(), val)); + encode_bson(&mut buf, &key.to_string(), val)?; } - try!(write_i32(writer, - (buf.len() + mem::size_of::() + mem::size_of::()) as i32)); - try!(writer.write_all(&buf)); - try!(writer.write_u8(0)); + write_i32( + writer, + (buf.len() + mem::size_of::() + mem::size_of::()) as i32 + )?; + writer.write_all(&buf)?; + writer.write_u8(0)?; Ok(()) } @@ -91,19 +93,21 @@ pub fn encode_document<'a, -> EncoderResult<()> { let mut buf = Vec::new(); for (key, val) in doc.into_iter() { - try!(encode_bson(&mut buf, key.as_ref(), val)); + encode_bson(&mut buf, key.as_ref(), val)?; } - try!(write_i32(writer, - (buf.len() + mem::size_of::() + mem::size_of::()) as i32)); - try!(writer.write_all(&buf)); - try!(writer.write_u8(0)); + write_i32( + writer, + (buf.len() + mem::size_of::() + mem::size_of::()) as i32 + )?; + writer.write_all(&buf)?; + writer.write_u8(0)?; Ok(()) } fn encode_bson(writer: &mut W, key: &str, val: &Bson) -> EncoderResult<()> { - try!(writer.write_u8(val.element_type() as u8)); - try!(write_cstring(writer, key)); + writer.write_u8(val.element_type() as u8)?; + write_cstring(writer, key)?; match val { &Bson::FloatingPoint(v) => write_f64(writer, v), @@ -112,25 +116,25 @@ fn encode_bson(writer: &mut W, key: &str, val: &Bson) -> Enco &Bson::Document(ref v) => encode_document(writer, v), &Bson::Boolean(v) => writer.write_u8(if v { 0x01 } else { 0x00 }).map_err(From::from), &Bson::RegExp(ref pat, ref opt) => { - try!(write_cstring(writer, pat)); + write_cstring(writer, pat)?; write_cstring(writer, opt) } &Bson::JavaScriptCode(ref code) => write_string(writer, &code), &Bson::ObjectId(ref id) => writer.write_all(&id.bytes()).map_err(From::from), &Bson::JavaScriptCodeWithScope(ref code, ref scope) => { let mut buf = Vec::new(); - try!(write_string(&mut buf, code)); - try!(encode_document(&mut buf, scope)); + write_string(&mut buf, code)?; + encode_document(&mut buf, scope)?; - try!(write_i32(writer, buf.len() as i32 + 4)); + write_i32(writer, buf.len() as i32 + 4)?; writer.write_all(&buf).map_err(From::from) } &Bson::I32(v) => write_i32(writer, v), &Bson::I64(v) => write_i64(writer, v), &Bson::TimeStamp(v) => write_i64(writer, v), &Bson::Binary(subtype, ref data) => { - try!(write_i32(writer, data.len() as i32)); - try!(writer.write_u8(From::from(subtype))); + write_i32(writer, data.len() as i32)?; + writer.write_u8(From::from(subtype))?; writer.write_all(data).map_err(From::from) } &Bson::UtcDatetime(ref v) => { diff --git a/src/encoder/serde.rs b/src/encoder/serde.rs index afddf181..7d10d506 100644 --- a/src/encoder/serde.rs +++ b/src/encoder/serde.rs @@ -23,10 +23,10 @@ impl Serialize for Document { fn serialize(&self, serializer: S) -> Result where S: Serializer { - let mut state = try!(serializer.serialize_map(Some(self.len()))); + let mut state = serializer.serialize_map(Some(self.len()))?; for (k, v) in self { - try!(state.serialize_key(k)); - try!(state.serialize_value(v)); + state.serialize_key(k)?; + state.serialize_value(v)?; } state.end() } @@ -62,6 +62,20 @@ impl Encoder { pub fn new() -> Encoder { Encoder } + + #[cfg(feature = "unsigned_conversion")] + fn visit_unsigned_int< + T: Copy + ::std::convert::TryInto + Into + >(self, value: T) -> EncoderResult { + value.try_into() + .map(|val| self.serialize_i32(val)) + .map_err(|_| EncoderError::OutOfRangeUnsignedType(value.into()))? + } + + #[cfg(not(feature = "unsigned_conversion"))] + fn visit_unsigned_int>(self, _: T) -> EncoderResult { + Err(EncoderError::UnsupportedUnsignedType) + } } impl Serializer for Encoder { @@ -87,8 +101,8 @@ impl Serializer for Encoder { } #[inline] - fn serialize_u8(self, _value: u8) -> EncoderResult { - Err(EncoderError::UnsupportedUnsignedType) + fn serialize_u8(self, value: u8) -> EncoderResult { + self.visit_unsigned_int(value) } #[inline] @@ -97,8 +111,8 @@ impl Serializer for Encoder { } #[inline] - fn serialize_u16(self, _value: u16) -> EncoderResult { - Err(EncoderError::UnsupportedUnsignedType) + fn serialize_u16(self, value: u16) -> EncoderResult { + self.visit_unsigned_int(value) } #[inline] @@ -107,8 +121,8 @@ impl Serializer for Encoder { } #[inline] - fn serialize_u32(self, _value: u32) -> EncoderResult { - Err(EncoderError::UnsupportedUnsignedType) + fn serialize_u32(self, value: u32) -> EncoderResult { + self.visit_unsigned_int(value) } #[inline] @@ -117,8 +131,8 @@ impl Serializer for Encoder { } #[inline] - fn serialize_u64(self, _value: u64) -> EncoderResult { - Err(EncoderError::UnsupportedUnsignedType) + fn serialize_u64(self, value: u64) -> EncoderResult { + self.visit_unsigned_int(value) } #[inline] diff --git a/src/lib.rs b/src/lib.rs index 38d2cd31..ec595bba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,8 @@ //! } //! ``` +#![cfg_attr(feature = "unsigned_conversion", feature(try_from))] + extern crate byteorder; extern crate chrono; extern crate crypto; diff --git a/src/oid.rs b/src/oid.rs index e3f68980..eb743b97 100644 --- a/src/oid.rs +++ b/src/oid.rs @@ -99,9 +99,9 @@ impl ObjectId { /// for more information. pub fn new() -> Result { let timestamp = ObjectId::gen_timestamp(); - let machine_id = try!(ObjectId::gen_machine_id()); + let machine_id = ObjectId::gen_machine_id()?; let process_id = ObjectId::gen_process_id(); - let counter = try!(ObjectId::gen_count()); + let counter = ObjectId::gen_count()?; let mut buf: [u8; 12] = [0; 12]; for i in 0..TIMESTAMP_SIZE { @@ -127,7 +127,7 @@ impl ObjectId { /// Creates an ObjectID using a 12-byte (24-char) hexadecimal string. pub fn with_string(s: &str) -> Result { - let bytes: Vec = try!(FromHex::from_hex(s.as_bytes())); + let bytes: Vec = FromHex::from_hex(s.as_bytes())?; if bytes.len() != 12 { Err(Error::ArgumentError("Provided string must be a 12-byte hexadecimal string." .to_owned())) @@ -248,7 +248,7 @@ impl ObjectId { fn gen_count() -> Result<[u8; 3]> { // Init oid counter if OID_COUNTER.load(Ordering::SeqCst) == 0 { - let mut rng = try!(OsRng::new()); + let mut rng = OsRng::new()?; let start = rng.gen_range(0, MAX_U24 + 1); OID_COUNTER.store(start, Ordering::SeqCst); } diff --git a/src/ordered.rs b/src/ordered.rs index 16cd9dae..f572f181 100644 --- a/src/ordered.rs +++ b/src/ordered.rs @@ -68,21 +68,21 @@ impl Default for OrderedDocument { impl Display for OrderedDocument { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - try!(write!(fmt, "{{")); + write!(fmt, "{{")?; let mut first = true; for (k, v) in self.iter() { if first { first = false; - try!(write!(fmt, " ")); + write!(fmt, " ")?; } else { - try!(write!(fmt, ", ")); + write!(fmt, ", ")?; } - try!(write!(fmt, "{}: {}", k, v)); + write!(fmt, "{}: {}", k, v)?; } - try!(write!(fmt, "{}}}", if !first { " " } else { "" })); + write!(fmt, "{}}}", if !first { " " } else { "" })?; Ok(()) } } @@ -419,7 +419,7 @@ impl<'de> Visitor<'de> for OrderedDocumentVisitor { None => LinkedHashMap::new(), }; - while let Some((key, value)) = try!(visitor.next_entry()) { + while let Some((key, value)) = visitor.next_entry()? { inner.insert(key, value); } diff --git a/tests/serde.rs b/tests/serde.rs index 844fe9dc..f5dc1640 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -97,7 +97,6 @@ fn test_ser_datetime() { assert_eq!(xfoo, foo); } - #[test] fn test_compat_u2f() { #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]