diff --git a/src/lib.rs b/src/lib.rs index ba4bbbe..709e075 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,7 @@ extern crate byteorder; use rustc_serialize::{Encodable, Decodable}; -pub use refbox::RefBox; +pub use refbox::{RefBox, StrBox, SliceBox}; pub use writer::{EncoderWriter, EncodingResult, EncodingError}; pub use reader::{DecoderReader, DecodingResult, DecodingError}; use writer::SizeChecker; diff --git a/src/refbox.rs b/src/refbox.rs index 42c4bd9..8f72c35 100644 --- a/src/refbox.rs +++ b/src/refbox.rs @@ -58,13 +58,23 @@ use rustc_serialize::{Decodable, Decoder}; /// Please don't stick RefBox inside deep data structures. It is much better /// suited in the outermost layer of whatever it is that you are encoding. pub struct RefBox<'a, T: 'a> { - inner: RefBoxInner<'a, T> + inner: RefBoxInner<'a, T, Box> +} + +/// Like a RefBox, but encoding from a `str` and decoedes to a `String`. +pub struct StrBox<'a> { + inner: RefBoxInner<'a, str, String> +} + +/// Like a RefBox, but encodes from a `[T]` and encodes to a `Vec`. +pub struct SliceBox<'a, T: 'a> { + inner: RefBoxInner<'a, [T], Vec> } #[derive(Debug, Hash)] -enum RefBoxInner<'a, T: 'a> { - Ref(&'a T), - Box(Box) +enum RefBoxInner<'a, A: 'a + ?Sized, B> { + Ref(&'a A), + Box(B) } impl <'a, T> RefBox<'a, T> { @@ -98,11 +108,13 @@ impl RefBox<'static, T> { } } } + impl <'a, T: Encodable> Encodable for RefBox<'a, T> { fn encode(&self, s: &mut S) -> Result<(), S::Error> { self.inner.encode(s) } } + impl Decodable for RefBox<'static, T> { fn decode(d: &mut D) -> Result, D::Error> { let inner = try!(Decodable::decode(d)); @@ -110,32 +122,113 @@ impl Decodable for RefBox<'static, T> { } } -impl <'a, T: Encodable> Encodable for RefBoxInner<'a, T> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_enum("RefBox", |s| { - s.emit_enum_variant("Box", 1, 1, |s| { - s.emit_enum_variant_arg(0, |s| { - match self { - &RefBoxInner::Ref(ref r) => r.encode(s), - &RefBoxInner::Box(ref b) => b.encode(s) - } - }) - }) - }) +impl <'a> StrBox<'a> { + /// Creates a new RefBox that looks at a borrowed value. + pub fn new(s: &'a str) -> StrBox<'a> { + StrBox { + inner: RefBoxInner::Ref(s) + } } } -impl Decodable for RefBoxInner<'static, T> { - fn decode(d: &mut D) -> Result, D::Error> { - d.read_enum("RefBox", |d| { - d.read_enum_variant(&["Ref", "Box"], |d, i| { - assert!(i == 1); - d.read_enum_variant_arg(0, |d| { - let decoded = try!(Decodable::decode(d)); - Ok(RefBoxInner::Box(Box::new(decoded))) - }) - }) - }) +impl StrBox<'static> { + /// Takes the value out of this refbox. + /// + /// Fails if this refbox was not created out of a deserialization. + /// + /// Unless you are doing some really weird things with static references, + /// this function will never fail. + pub fn take(self) -> String { + match self.inner { + RefBoxInner::Box(b) => b, + _ => unreachable!() + } + } + + /// Tries to take the value out of this refbox. + pub fn try_take(self) -> Result> { + match self.inner { + RefBoxInner::Box(b) => Ok(b), + o => Err(StrBox{ inner: o}) + } + } +} + +impl <'a> Encodable for StrBox<'a> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.inner.encode(s) + } +} + +impl Decodable for StrBox<'static> { + fn decode(d: &mut D) -> Result, D::Error> { + let inner: RefBoxInner<'static, str, String> = try!(Decodable::decode(d)); + Ok(StrBox{inner: inner}) + } +} + +// +// SliceBox +// + +impl <'a, T> SliceBox<'a, T> { + /// Creates a new RefBox that looks at a borrowed value. + pub fn new(v: &'a [T]) -> SliceBox<'a, T> { + SliceBox { + inner: RefBoxInner::Ref(v) + } + } +} + +impl SliceBox<'static, T> { + /// Takes the value out of this refbox. + /// + /// Fails if this refbox was not created out of a deserialization. + /// + /// Unless you are doing some really weird things with static references, + /// this function will never fail. + pub fn take(self) -> Vec { + match self.inner { + RefBoxInner::Box(b) => b, + _ => unreachable!() + } + } + + /// Tries to take the value out of this refbox. + pub fn try_take(self) -> Result, SliceBox<'static, T>> { + match self.inner { + RefBoxInner::Box(b) => Ok(b), + o => Err(SliceBox{ inner: o}) + } + } +} + +impl <'a, T: Encodable> Encodable for SliceBox<'a, T> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.inner.encode(s) + } +} + +impl Decodable for SliceBox<'static, T> { + fn decode(d: &mut D) -> Result, D::Error> { + let inner: RefBoxInner<'static, [T], Vec> = try!(Decodable::decode(d)); + Ok(SliceBox{inner: inner}) + } +} + +impl <'a, A: Encodable + ?Sized, B: Encodable> Encodable for RefBoxInner<'a, A, B> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + match self { + &RefBoxInner::Ref(ref r) => r.encode(s), + &RefBoxInner::Box(ref b) => b.encode(s) + } + } +} + +impl Decodable for RefBoxInner<'static, A, B> { + fn decode(d: &mut D) -> Result, D::Error> { + let decoded = try!(Decodable::decode(d)); + Ok(RefBoxInner::Box(decoded)) } } diff --git a/src/test.rs b/src/test.rs index e05ac8c..449eded 100644 --- a/src/test.rs +++ b/src/test.rs @@ -4,8 +4,17 @@ use std::ops::Deref; use rustc_serialize::{Encoder, Decoder, Encodable, Decodable}; -use super::{encode, decode, decode_from, encoded_size, DecodingError, - DecodingResult, RefBox}; +use super::{ + encode, + decode, + decode_from, + encoded_size, + DecodingError, + DecodingResult, + RefBox, + StrBox, + SliceBox, +}; use super::SizeLimit::{Infinite, Bounded}; @@ -288,6 +297,24 @@ fn test_refbox() { } } +#[test] +fn test_strbox() { + let strx: &'static str = "hello world"; + let encoded = encode(&StrBox::new(strx), Infinite).unwrap(); + let decoded: (StrBox<'static>, _) = decode(&encoded[..]).unwrap(); + let stringx: String = decoded.0.take(); + assert!(strx == &stringx[..]); +} + +#[test] +fn test_slicebox() { + let slice = [1u32, 2, 3 ,4, 5]; + let encoded = encode(&SliceBox::new(&slice), Infinite).unwrap(); + let decoded: (SliceBox<'static, u32>, _) = decode(&encoded[..]).unwrap(); + let vecx: Vec = decoded.0.take(); + assert!(slice == &vecx[..]); +} + #[test] fn test_multi_strings() { assert!(encode(&("foo", "bar", "baz"), Infinite).is_ok()); diff --git a/src/writer.rs b/src/writer.rs index 68f8b41..adc966f 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -21,7 +21,7 @@ pub enum EncodingError { /// /// This error is returned before any bytes are written to the /// output `Writer`. - SizeLimit + SizeLimit, } /// An Encoder that encodes values directly into a Writer.