Skip to content

Instantly share code, notes, and snippets.

@nikomatsakis
Created September 14, 2012 18:45
Show Gist options
  • Save nikomatsakis/3723867 to your computer and use it in GitHub Desktop.
Save nikomatsakis/3723867 to your computer and use it in GitHub Desktop.
extern mod std;
use io::WriterUtil;
use send_map::linear;
/// Represents a json value
enum Json {
Number(float),
String(~str),
Boolean(bool),
List(List),
Object(~Object),
Null,
}
type List = ~[mut Json];
type Object = linear::LinearMap<~str, Json>;
struct Deserializer {
priv mut stack: ~[&Json],
}
priv impl Deserializer {
fn peek() -> &self/Json {
vec::last(self.stack)
}
fn pop() -> &self/Json {
vec::pop(self.stack);
}
}
impl Deserializer {
fn read_nil() -> () {
debug!("read_nil");
match *self.pop() {
Null => (),
_ => fail ~"not a null"
}
}
fn read_u64() -> u64 { self.read_float() as u64 }
fn read_u32() -> u32 { self.read_float() as u32 }
fn read_u16() -> u16 { self.read_float() as u16 }
fn read_u8 () -> u8 { self.read_float() as u8 }
fn read_uint() -> uint { self.read_float() as uint }
fn read_i64() -> i64 { self.read_float() as i64 }
fn read_i32() -> i32 { self.read_float() as i32 }
fn read_i16() -> i16 { self.read_float() as i16 }
fn read_i8 () -> i8 { self.read_float() as i8 }
fn read_int() -> int { self.read_float() as int }
fn read_bool() -> bool {
debug!("read_bool");
match *self.pop() {
Boolean(b) => b,
_ => fail ~"not a boolean"
}
}
fn read_f64() -> f64 { self.read_float() as f64 }
fn read_f32() -> f32 { self.read_float() as f32 }
fn read_float() -> float {
debug!("read_float");
match *self.pop() {
Number(f) => f,
_ => fail ~"not a number"
}
}
fn read_str() -> ~str {
debug!("read_str");
match *self.pop() {
String(ref s) => copy *s,
_ => fail ~"not a string"
}
}
fn read_enum<T>(name: ~str, f: fn() -> T) -> T {
debug!("read_enum(%s)", name);
if name != ~"option" { fail ~"only supports the option enum" }
f()
}
fn read_enum_variant<T>(f: fn(uint) -> T) -> T {
debug!("read_enum_variant()");
let idx = match *self.peek() {
Null => 0,
_ => 1,
};
f(idx)
}
fn read_enum_variant_arg<T>(idx: uint, f: fn() -> T) -> T {
debug!("read_enum_variant_arg(idx=%u)", idx);
if idx != 0 { fail ~"unknown index" }
f()
}
fn read_vec<T>(f: fn(uint) -> T) -> T {
debug!("read_vec()");
let len = match *self.peek() {
List(ref list) => list.len(),
_ => fail ~"not a list",
};
let value = f(len);
value
}
fn read_vec_elt<T>(idx: uint, f: fn() -> T) -> T {
debug!("read_vec_elt(idx=%u)", idx);
match *self.peek() {
List(ref list) => {
vec::push(self.stack, &list[idx]);
f()
}
_ => fail ~"not a list",
}
}
fn read_box<T>(f: fn() -> T) -> T {
debug!("read_box()");
f()
}
fn read_uniq<T>(f: fn() -> T) -> T {
debug!("read_uniq()");
f()
}
fn read_rec<T>(f: fn() -> T) -> T {
debug!("read_rec()");
let value = f();
self.pop();
value
}
fn read_rec_field<T>(f_name: ~str, f_idx: uint, f: fn() -> T) -> T {
debug!("read_rec_field(%s, idx=%u)", f_name, f_idx);
match *self.peek() {
Object(ref obj) => {
do obj.with_find_ref(&f_name) |json| {
vec::push(self.stack, json);
f()
}
}
_ => fail ~"not an object"
}
}
fn read_tup<T>(sz: uint, f: fn() -> T) -> T {
debug!("read_tup(sz=%u)", sz);
let value = f();
self.pop();
value
}
fn read_tup_elt<T>(idx: uint, f: fn() -> T) -> T {
debug!("read_tup_elt(idx=%u)", idx);
match *self.peek() {
List(ref list) => {
vec::push(self.stack, &list[idx]);
f()
}
_ => fail ~"not a list"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment