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 = "rlib"]
|
||||||
#![crate_type = "dylib"]
|
#![crate_type = "dylib"]
|
||||||
|
|
||||||
#![allow(unstable)]
|
#![feature(io, hash, core)]
|
||||||
|
|
||||||
#![doc(html_logo_url = "./icon.png")]
|
#![doc(html_logo_url = "./icon.png")]
|
||||||
|
|
||||||
|
|
@ -11,12 +11,14 @@ extern crate "rustc-serialize" as rustc_serialize;
|
||||||
use std::old_io::{Buffer, MemWriter};
|
use std::old_io::{Buffer, MemWriter};
|
||||||
use rustc_serialize::{Encodable, Decodable};
|
use rustc_serialize::{Encodable, Decodable};
|
||||||
|
|
||||||
|
pub use refbox::RefBox;
|
||||||
pub use writer::{EncoderWriter, EncodingResult, EncodingError};
|
pub use writer::{EncoderWriter, EncodingResult, EncodingError};
|
||||||
pub use reader::{DecoderReader, DecodingResult, DecodingError};
|
pub use reader::{DecoderReader, DecodingResult, DecodingError};
|
||||||
use writer::SizeChecker;
|
use writer::SizeChecker;
|
||||||
|
|
||||||
mod writer;
|
mod writer;
|
||||||
mod reader;
|
mod reader;
|
||||||
|
mod refbox;
|
||||||
#[cfg(test)] mod test;
|
#[cfg(test)] mod test;
|
||||||
|
|
||||||
///! `bincode` is a crate for encoding and decoding using a tiny binary
|
///! `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::fmt::Debug;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use rustc_serialize::{
|
use rustc_serialize::{
|
||||||
Encoder,
|
Encoder,
|
||||||
|
|
@ -16,17 +17,32 @@ use super::{
|
||||||
decode_from,
|
decode_from,
|
||||||
encoded_size,
|
encoded_size,
|
||||||
DecodingError,
|
DecodingError,
|
||||||
DecodingResult
|
DecodingResult,
|
||||||
|
RefBox,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SizeLimit::{Infinite, Bounded};
|
use super::SizeLimit::{Infinite, Bounded};
|
||||||
|
|
||||||
fn the_same<V>(element: V)
|
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 size = encoded_size(&element);
|
||||||
let encoded = encode(&element, Infinite).unwrap();
|
let encoded = encode(&element, Infinite).unwrap();
|
||||||
let decoded = decode(&encoded[]).unwrap();
|
let decoded = decode(&encoded[]).unwrap();
|
||||||
assert!(element == decoded);
|
assert!(element == decoded);
|
||||||
assert!(size == encoded.len() as u64);
|
assert!(size == encoded.len() as u64);
|
||||||
|
assert!(ref_box_correct(&element))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -246,3 +262,39 @@ fn test_encoded_size() {
|
||||||
fn encode_box() {
|
fn encode_box() {
|
||||||
the_same(Box::new(5));
|
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