Add RefBox.
RefBox is a structure for encoding references, and decoding them into a box. This makes it easy to nest structures that otherwise would not be able to be nested and encoded.
This commit is contained in:
parent
b15b85797e
commit
f5111f9476
|
|
@ -2,7 +2,7 @@
|
|||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
|
||||
#![allow(unstable)]
|
||||
#![feature(io, hash, core)]
|
||||
|
||||
#![doc(html_logo_url = "./icon.png")]
|
||||
|
||||
|
|
@ -11,12 +11,14 @@ extern crate "rustc-serialize" as rustc_serialize;
|
|||
use std::old_io::{Buffer, MemWriter};
|
||||
use rustc_serialize::{Encodable, Decodable};
|
||||
|
||||
pub use refbox::RefBox;
|
||||
pub use writer::{EncoderWriter, EncodingResult, EncodingError};
|
||||
pub use reader::{DecoderReader, DecodingResult, DecodingError};
|
||||
use writer::SizeChecker;
|
||||
|
||||
mod writer;
|
||||
mod reader;
|
||||
mod refbox;
|
||||
#[cfg(test)] mod test;
|
||||
|
||||
///! `bincode` is a crate for encoding and decoding using a tiny binary
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
use std::boxed::Box;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_serialize::{Encodable, Encoder};
|
||||
use rustc_serialize::{Decodable, Decoder};
|
||||
|
||||
pub struct RefBox<'a, T: 'a> {
|
||||
inner: RefBoxInner<'a, T>
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
enum RefBoxInner<'a, T: 'a> {
|
||||
Ref(&'a T),
|
||||
Box(Box<T>)
|
||||
}
|
||||
|
||||
impl <'a, T> RefBox<'a, T> {
|
||||
pub fn new(v: &'a T) -> RefBox<'a, T> {
|
||||
RefBox {
|
||||
inner: RefBoxInner::Ref(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <T> RefBox<'static, T> {
|
||||
pub fn take(self) -> Box<T> {
|
||||
match self.inner {
|
||||
RefBoxInner::Box(b) => b,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
pub fn try_take(self) -> Result<Box<T>, RefBox<'static, T>> {
|
||||
match self.inner {
|
||||
RefBoxInner::Box(b) => Ok(b),
|
||||
o => Err(RefBox{ inner: o})
|
||||
}
|
||||
}
|
||||
}
|
||||
impl <'a, T: Encodable> Encodable for RefBox<'a, T> {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
self.inner.encode(s)
|
||||
}
|
||||
}
|
||||
impl <T: Decodable> Decodable for RefBox<'static, T> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<RefBox<'static, T>, D::Error> {
|
||||
let inner = try!(Decodable::decode(d));
|
||||
Ok(RefBox{inner: inner})
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, T: Encodable> Encodable for RefBoxInner<'a, T> {
|
||||
fn encode<S: Encoder>(&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 <T: Decodable> Decodable for RefBoxInner<'static, T> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<RefBoxInner<'static, T>, 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 <'a, T> Deref for RefBox<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
match &self.inner {
|
||||
&RefBoxInner::Ref(ref t) => t,
|
||||
&RefBoxInner::Box(ref b) => b.deref()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
56
src/test.rs
56
src/test.rs
|
|
@ -2,6 +2,7 @@ extern crate "rustc-serialize" as serialize;
|
|||
|
||||
use std::fmt::Debug;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_serialize::{
|
||||
Encoder,
|
||||
|
|
@ -16,17 +17,32 @@ use super::{
|
|||
decode_from,
|
||||
encoded_size,
|
||||
DecodingError,
|
||||
DecodingResult
|
||||
DecodingResult,
|
||||
RefBox,
|
||||
};
|
||||
|
||||
use super::SizeLimit::{Infinite, Bounded};
|
||||
|
||||
fn the_same<V>(element: V)
|
||||
where V: Encodable + Decodable + PartialEq + Debug {
|
||||
where V: Encodable + Decodable + PartialEq + Debug + 'static {
|
||||
|
||||
// Make sure that the bahavior is correct when wrapping with a RefBox.
|
||||
fn ref_box_correct<V>(v: &V) -> bool
|
||||
where V: Encodable + Decodable + PartialEq + Debug + 'static {
|
||||
let rf = RefBox::new(v);
|
||||
|
||||
let encoded = encode(&rf, Infinite).unwrap();
|
||||
let decoded: RefBox<'static, V> = decode(&encoded[]).unwrap();
|
||||
|
||||
decoded.take().deref() == v
|
||||
}
|
||||
|
||||
let size = encoded_size(&element);
|
||||
let encoded = encode(&element, Infinite).unwrap();
|
||||
let decoded = decode(&encoded[]).unwrap();
|
||||
assert!(element == decoded);
|
||||
assert!(size == encoded.len() as u64);
|
||||
assert!(ref_box_correct(&element))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -246,3 +262,39 @@ fn test_encoded_size() {
|
|||
fn encode_box() {
|
||||
the_same(Box::new(5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_refbox() {
|
||||
let large_object = vec![1u32,2,3,4,5,6];
|
||||
let mut large_map = HashMap::new();
|
||||
large_map.insert(1, 2);
|
||||
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
enum Message<'a> {
|
||||
M1(RefBox<'a, Vec<u32>>),
|
||||
M2(RefBox<'a, HashMap<u32, u32>>)
|
||||
}
|
||||
|
||||
// Test 1
|
||||
{
|
||||
let encoded = encode(&Message::M1(RefBox::new(&large_object)), Infinite).unwrap();
|
||||
let decoded: Message<'static> = decode(&encoded[]).unwrap();
|
||||
|
||||
match decoded {
|
||||
Message::M1(b) => assert!(b.take().deref() == &large_object),
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
|
||||
// Test 2
|
||||
{
|
||||
let encoded = encode(&Message::M2(RefBox::new(&large_map)), Infinite).unwrap();
|
||||
let decoded: Message<'static> = decode(&encoded[]).unwrap();
|
||||
|
||||
match decoded {
|
||||
Message::M2(b) => assert!(b.take().deref() == &large_map),
|
||||
_ => assert!(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue