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..939aed7 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,7 +122,101 @@ impl Decodable for RefBox<'static, T> { } } -impl <'a, T: Encodable> Encodable for RefBoxInner<'a, T> { +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 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> { s.emit_enum("RefBox", |s| { s.emit_enum_variant("Box", 1, 1, |s| { @@ -125,14 +231,14 @@ impl <'a, T: Encodable> Encodable for RefBoxInner<'a, T> { } } -impl Decodable for RefBoxInner<'static, T> { - fn decode(d: &mut D) -> Result, D::Error> { +impl Decodable for RefBoxInner<'static, A, B> { + 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))) + Ok(RefBoxInner::Box(decoded)) }) }) })