diff options
| author | bors <bors@rust-lang.org> | 2014-08-01 05:41:05 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-08-01 05:41:05 +0000 |
| commit | 9f0b91985fb99730f145b62f2d3b4c10f54e27f0 (patch) | |
| tree | 25ecb89241b9081954eb2ea6e79d058650c25cfa | |
| parent | b495933a7fdc5e7b28ddbb058d1e2dab330ace7b (diff) | |
| parent | dac9a1c5207cb33a0b40813896b74d00bbbd1d36 (diff) | |
| download | rust-9f0b91985fb99730f145b62f2d3b4c10f54e27f0.tar.gz rust-9f0b91985fb99730f145b62f2d3b4c10f54e27f0.zip | |
auto merge of #16130 : apoelstra/rust/decode-error, r=alexcrichton
A quick and dirty fix for #15036 until we get serious decoder reform. Right now it is impossible for a `Decodable` to signal a decode error, for example if it has only finitely many allowed values, is a string which must be encoded a certain way, needs a valid checksum, etc. For example in the `libuuid` implementation of `Decodable` an `Option` is unwrapped, meaning that a decode of a malformed UUID will cause the task to fail.
| -rw-r--r-- | src/librbml/lib.rs | 17 | ||||
| -rw-r--r-- | src/libserialize/json.rs | 5 | ||||
| -rw-r--r-- | src/libserialize/serialize.rs | 3 | ||||
| -rw-r--r-- | src/libuuid/lib.rs | 22 |
4 files changed, 40 insertions, 7 deletions
diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index f77d36d1e06..4927a8293a4 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -105,7 +105,8 @@ pub enum EbmlEncoderTag { pub enum Error { IntTooBig(uint), Expected(String), - IoError(std::io::IoError) + IoError(std::io::IoError), + ApplicationError(String) } // -------------------------------------- @@ -119,11 +120,11 @@ pub mod reader { use serialize; - use super::{ EsVec, EsMap, EsEnum, EsVecLen, EsVecElt, EsMapLen, EsMapKey, - EsEnumVid, EsU64, EsU32, EsU16, EsU8, EsInt, EsI64, EsI32, EsI16, EsI8, - EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, EsEnumBody, EsUint, - EsOpaque, EsLabel, EbmlEncoderTag, Doc, TaggedDoc, Error, IntTooBig, - Expected }; + use super::{ ApplicationError, EsVec, EsMap, EsEnum, EsVecLen, EsVecElt, + EsMapLen, EsMapKey, EsEnumVid, EsU64, EsU32, EsU16, EsU8, EsInt, EsI64, + EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, + EsEnumBody, EsUint, EsOpaque, EsLabel, EbmlEncoderTag, Doc, TaggedDoc, + Error, IntTooBig, Expected }; pub type DecodeResult<T> = Result<T, Error>; // rbml reading @@ -636,6 +637,10 @@ pub mod reader { debug!("read_map_elt_val(idx={})", idx); self.push_doc(EsMapVal, f) } + + fn error(&mut self, err: &str) -> Error { + ApplicationError(err.to_string()) + } } } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 0752c68f4d0..58d69e38cc6 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -257,6 +257,7 @@ pub enum DecoderError { ExpectedError(String, String), MissingFieldError(String), UnknownVariantError(String), + ApplicationError(String) } /// Returns a readable error string for a given error code. @@ -2071,6 +2072,10 @@ impl ::Decoder<DecoderError> for Decoder { debug!("read_map_elt_val(idx={})", idx); f(self) } + + fn error(&mut self, err: &str) -> DecoderError { + ApplicationError(err.to_string()) + } } /// A trait for converting values to JSON diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 03d9445b9b9..95c677bcbd7 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -163,6 +163,9 @@ pub trait Decoder<E> { fn read_map<T>(&mut self, f: |&mut Self, uint| -> Result<T, E>) -> Result<T, E>; fn read_map_elt_key<T>(&mut self, idx: uint, f: |&mut Self| -> Result<T, E>) -> Result<T, E>; fn read_map_elt_val<T>(&mut self, idx: uint, f: |&mut Self| -> Result<T, E>) -> Result<T, E>; + + // Failure + fn error(&mut self, err: &str) -> E; } pub trait Encodable<S:Encoder<E>, E> { diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index 2ffed792abd..d922dde6f85 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -501,7 +501,10 @@ impl<T: Encoder<E>, E> Encodable<T, E> for Uuid { impl<T: Decoder<E>, E> Decodable<T, E> for Uuid { /// Decode a UUID from a string fn decode(d: &mut T) -> Result<Uuid, E> { - Ok(from_str(try!(d.read_str()).as_slice()).unwrap()) + match from_str(try!(d.read_str()).as_slice()) { + Some(decode) => Ok(decode), + None => Err(d.error("Unable to decode UUID")) + } } } @@ -803,6 +806,23 @@ mod test { } #[test] + fn test_bad_decode() { + use serialize::json; + use serialize::{Encodable, Decodable}; + + let js_good = json::String("a1a2a3a4a5a6a7a8a1a2a3a4a5a6a7a8".to_string()); + let js_bad1 = json::String("a1a2a3a4a5a6a7a8a1a2a3a4a5a6a7ah".to_string()); + let js_bad2 = json::String("a1a2a3a4a5a6a7a8a1a2a3a4a5a6a7a".to_string()); + + let u_good: Result<Uuid, _> = Decodable::decode(&mut json::Decoder::new(js_good)); + let u_bad1: Result<Uuid, _> = Decodable::decode(&mut json::Decoder::new(js_bad1)); + let u_bad2: Result<Uuid, _> = Decodable::decode(&mut json::Decoder::new(js_bad2)); + assert!(u_good.is_ok()); + assert!(u_bad1.is_err()); + assert!(u_bad2.is_err()); + } + + #[test] fn test_iterbytes_impl_for_uuid() { use std::collections::HashSet; let mut set = HashSet::new(); |
