mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-18 02:41:03 +00:00
Initial support for #[deriving_deserializable] deserializing from maps
This commit is contained in:
+208
-147
@@ -2,7 +2,7 @@
|
|||||||
#![crate_type = "dylib"]
|
#![crate_type = "dylib"]
|
||||||
#![license = "MIT/ASL2"]
|
#![license = "MIT/ASL2"]
|
||||||
|
|
||||||
#![feature(plugin_registrar)]
|
#![feature(plugin_registrar, quote)]
|
||||||
|
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
@@ -303,174 +303,91 @@ pub fn expand_deriving_deserializable(cx: &mut ExtCtxt,
|
|||||||
fn deserializable_substructure(cx: &mut ExtCtxt, trait_span: Span,
|
fn deserializable_substructure(cx: &mut ExtCtxt, trait_span: Span,
|
||||||
substr: &Substructure) -> Gc<Expr> {
|
substr: &Substructure) -> Gc<Expr> {
|
||||||
let deserializer = substr.nonself_args[0];
|
let deserializer = substr.nonself_args[0];
|
||||||
|
let token = substr.nonself_args[1];
|
||||||
|
|
||||||
match *substr.fields {
|
match *substr.fields {
|
||||||
StaticStruct(_, ref summary) => {
|
StaticStruct(_, ref fields) => {
|
||||||
let mut stmts = vec!();
|
let struct_block = struct_block(
|
||||||
|
|
||||||
let call = cx.expr_method_call(
|
|
||||||
trait_span,
|
|
||||||
deserializer,
|
|
||||||
cx.ident_of("expect_struct_start"),
|
|
||||||
vec!(
|
|
||||||
substr.nonself_args[1],
|
|
||||||
cx.expr_str(trait_span, token::get_ident(substr.type_ident)),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
let call = cx.expr_try(trait_span, call);
|
|
||||||
stmts.push(cx.stmt_expr(call));
|
|
||||||
|
|
||||||
let expect_struct_field = cx.ident_of("expect_struct_field");
|
|
||||||
|
|
||||||
let call = deserializable_static_fields(
|
|
||||||
cx,
|
cx,
|
||||||
trait_span,
|
trait_span,
|
||||||
substr.type_ident,
|
substr.type_ident,
|
||||||
summary,
|
fields,
|
||||||
|cx, span, name| {
|
deserializer
|
||||||
cx.expr_try(span,
|
|
||||||
cx.expr_method_call(
|
|
||||||
span,
|
|
||||||
deserializer,
|
|
||||||
expect_struct_field,
|
|
||||||
vec!(
|
|
||||||
cx.expr_str(span, name),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = cx.ident_of("result");
|
let map_block = map_block(
|
||||||
|
cx,
|
||||||
stmts.push(
|
|
||||||
cx.stmt_let(
|
|
||||||
trait_span,
|
|
||||||
false,
|
|
||||||
result,
|
|
||||||
call
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
let call = cx.expr_method_call(
|
|
||||||
trait_span,
|
trait_span,
|
||||||
deserializer,
|
substr.type_ident,
|
||||||
cx.ident_of("expect_struct_end"),
|
fields,
|
||||||
vec!()
|
deserializer
|
||||||
);
|
);
|
||||||
let call = cx.expr_try(trait_span, call);
|
|
||||||
stmts.push(cx.stmt_expr(call));
|
|
||||||
|
|
||||||
cx.expr_block(
|
quote_expr!(
|
||||||
cx.block(
|
cx,
|
||||||
trait_span,
|
match $token {
|
||||||
stmts,
|
::serde::de::StructStart(_, _) => $struct_block,
|
||||||
Some(
|
::serde::de::MapStart(_) => $map_block,
|
||||||
cx.expr_ok(
|
_ => $deserializer.syntax_error(),
|
||||||
trait_span,
|
}
|
||||||
cx.expr_ident(trait_span, result)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StaticEnum(_, ref fields) => {
|
StaticEnum(_, ref fields) => {
|
||||||
let mut stmts = vec!();
|
let type_name = cx.expr_str(
|
||||||
|
trait_span,
|
||||||
|
token::get_ident(substr.type_ident)
|
||||||
|
);
|
||||||
|
|
||||||
let mut arms = vec!();
|
let variants = fields.iter()
|
||||||
let mut variants = vec!();
|
.map(|&(name, span, _)| {
|
||||||
|
cx.expr_str(span, token::get_ident(name))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let expect_enum_sep = cx.ident_of("expect_enum_sep");
|
let variants = cx.expr_vec(trait_span, variants);
|
||||||
for (i, &(name, v_span, ref parts)) in fields.iter().enumerate() {
|
|
||||||
variants.push(cx.expr_str(v_span, token::get_ident(name)));
|
|
||||||
|
|
||||||
let deserializabled = deserializable_static_fields(cx,
|
let arms: Vec<ast::Arm> = fields.iter()
|
||||||
v_span,
|
.enumerate()
|
||||||
name,
|
.map(|(i, &(name, span, ref parts))| {
|
||||||
parts,
|
let call = deserializable_static_fields(
|
||||||
|cx, span, _| {
|
cx,
|
||||||
cx.expr_try(span,
|
span,
|
||||||
cx.expr_method_call(
|
name,
|
||||||
span,
|
parts,
|
||||||
deserializer,
|
|cx, span, _| {
|
||||||
expect_enum_sep,
|
cx.expr_try(span,
|
||||||
vec!()
|
cx.expr_method_call(
|
||||||
)
|
span,
|
||||||
)
|
deserializer,
|
||||||
});
|
cx.ident_of("expect_enum_sep"),
|
||||||
|
vec!()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
arms.push(
|
|
||||||
cx.arm(
|
cx.arm(
|
||||||
v_span,
|
span,
|
||||||
vec!(
|
vec!(
|
||||||
cx.pat_lit(v_span, cx.expr_uint(v_span, i)),
|
cx.pat_lit(span, cx.expr_uint(span, i)),
|
||||||
),
|
),
|
||||||
deserializabled
|
call
|
||||||
)
|
)
|
||||||
);
|
})
|
||||||
}
|
.collect();
|
||||||
|
|
||||||
arms.push(cx.arm_unreachable(trait_span));
|
quote_expr!(cx, {
|
||||||
|
let i = try!($deserializer.expect_enum_start($token, $type_name, $variants));
|
||||||
|
|
||||||
|
let result = match i {
|
||||||
|
$arms
|
||||||
|
_ => { unreachable!() }
|
||||||
|
};
|
||||||
|
|
||||||
let call = cx.expr_method_call(
|
try!($deserializer.expect_enum_end());
|
||||||
trait_span,
|
|
||||||
deserializer,
|
|
||||||
cx.ident_of("expect_enum_start"),
|
|
||||||
vec!(
|
|
||||||
substr.nonself_args[1],
|
|
||||||
cx.expr_str(trait_span, token::get_ident(substr.type_ident)),
|
|
||||||
cx.expr_vec(trait_span, variants),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
let call = cx.expr_try(trait_span, call);
|
|
||||||
|
|
||||||
let variant = cx.ident_of("i");
|
Ok(result)
|
||||||
stmts.push(
|
})
|
||||||
cx.stmt_let(
|
|
||||||
trait_span,
|
|
||||||
false,
|
|
||||||
variant,
|
|
||||||
call
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = cx.ident_of("result");
|
|
||||||
let call = cx.expr_match(
|
|
||||||
trait_span,
|
|
||||||
cx.expr_ident(trait_span, variant),
|
|
||||||
arms
|
|
||||||
);
|
|
||||||
stmts.push(
|
|
||||||
cx.stmt_let(
|
|
||||||
trait_span,
|
|
||||||
false,
|
|
||||||
result,
|
|
||||||
call
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
let call = cx.expr_method_call(
|
|
||||||
trait_span,
|
|
||||||
deserializer,
|
|
||||||
cx.ident_of("expect_enum_end"),
|
|
||||||
vec!()
|
|
||||||
);
|
|
||||||
let call = cx.expr_try(trait_span, call);
|
|
||||||
stmts.push(cx.stmt_expr(call));
|
|
||||||
|
|
||||||
cx.expr_block(
|
|
||||||
cx.block(
|
|
||||||
trait_span,
|
|
||||||
stmts,
|
|
||||||
Some(
|
|
||||||
cx.expr_ok(
|
|
||||||
trait_span,
|
|
||||||
cx.expr_ident(trait_span, result)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
_ => cx.bug("expected StaticEnum or StaticStruct in deriving(Deserializable)")
|
_ => cx.bug("expected StaticEnum or StaticStruct in deriving(Deserializable)")
|
||||||
}
|
}
|
||||||
@@ -478,13 +395,13 @@ fn deserializable_substructure(cx: &mut ExtCtxt, trait_span: Span,
|
|||||||
|
|
||||||
/// Create a deserializer for a single enum variant/struct:
|
/// Create a deserializer for a single enum variant/struct:
|
||||||
/// - `outer_pat_ident` is the name of this enum variant/struct
|
/// - `outer_pat_ident` is the name of this enum variant/struct
|
||||||
/// - `getarg` should retrieve the `uint`-th field with name `@str`.
|
/// - `getarg` should retrieve the `uint`-th field with name `&str`.
|
||||||
fn deserializable_static_fields(
|
fn deserializable_static_fields(
|
||||||
cx: &mut ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
outer_pat_ident: Ident,
|
outer_pat_ident: Ident,
|
||||||
fields: &StaticFields,
|
fields: &StaticFields,
|
||||||
getarg: |&mut ExtCtxt, Span, token::InternedString| -> Gc<Expr>
|
getarg: |&ExtCtxt, Span, token::InternedString| -> Gc<Expr>
|
||||||
) -> Gc<Expr> {
|
) -> Gc<Expr> {
|
||||||
match *fields {
|
match *fields {
|
||||||
Unnamed(ref fields) => {
|
Unnamed(ref fields) => {
|
||||||
@@ -517,3 +434,147 @@ fn deserializable_static_fields(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn struct_block<'a>(
|
||||||
|
cx: &ExtCtxt<'a>,
|
||||||
|
span: Span,
|
||||||
|
type_ident: Ident,
|
||||||
|
fields: &StaticFields,
|
||||||
|
deserializer: Gc<ast::Expr>
|
||||||
|
) -> Gc<ast::Expr> {
|
||||||
|
let mut stmts = vec!();
|
||||||
|
|
||||||
|
let expect_struct_field = cx.ident_of("expect_struct_field");
|
||||||
|
|
||||||
|
let call = deserializable_static_fields(
|
||||||
|
cx,
|
||||||
|
span,
|
||||||
|
type_ident,
|
||||||
|
fields,
|
||||||
|
|cx, span, name| {
|
||||||
|
cx.expr_try(span,
|
||||||
|
cx.expr_method_call(
|
||||||
|
span,
|
||||||
|
deserializer,
|
||||||
|
expect_struct_field,
|
||||||
|
vec!(
|
||||||
|
cx.expr_str(span, name),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = cx.ident_of("result");
|
||||||
|
|
||||||
|
stmts.push(
|
||||||
|
cx.stmt_let(span, false, result, call)
|
||||||
|
);
|
||||||
|
|
||||||
|
let call = cx.expr_method_call(
|
||||||
|
span,
|
||||||
|
deserializer,
|
||||||
|
cx.ident_of("expect_struct_end"),
|
||||||
|
vec!()
|
||||||
|
);
|
||||||
|
let call = cx.expr_try(span, call);
|
||||||
|
stmts.push(cx.stmt_expr(call));
|
||||||
|
|
||||||
|
let expr = cx.expr_ok(span, cx.expr_ident(span, result));
|
||||||
|
|
||||||
|
cx.expr_block(
|
||||||
|
cx.block(
|
||||||
|
span,
|
||||||
|
stmts,
|
||||||
|
Some(expr)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_block<'a>(
|
||||||
|
cx: &ExtCtxt<'a>,
|
||||||
|
span: Span,
|
||||||
|
type_ident: Ident,
|
||||||
|
fields: &StaticFields,
|
||||||
|
deserializer: Gc<ast::Expr>
|
||||||
|
) -> Gc<ast::Expr> {
|
||||||
|
let fields = match *fields {
|
||||||
|
Unnamed(_) => fail!(),
|
||||||
|
Named(ref fields) => fields.as_slice(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Declare each field.
|
||||||
|
let let_fields: Vec<Gc<ast::Stmt>> = fields.iter()
|
||||||
|
.map(|&(name, span)| {
|
||||||
|
cx.stmt_let(span, true, name, cx.expr_none(span))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Declare key arms.
|
||||||
|
let key_arms: Vec<Vec<ast::TokenTree>> = fields.iter()
|
||||||
|
.map(|&(name, span)| {
|
||||||
|
let s = cx.expr_str(span, token::get_ident(name));
|
||||||
|
quote_tokens!(cx, $s => {
|
||||||
|
$name = Some(try!(::serde::de::Deserializable::deserialize($deserializer)));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let fields_tuple = cx.expr_tuple(
|
||||||
|
span,
|
||||||
|
fields.iter()
|
||||||
|
.map(|&(name, span)| {
|
||||||
|
cx.expr_ident(span, name)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
);
|
||||||
|
|
||||||
|
let fields_pats: Vec<Gc<ast::Pat>> = fields.iter()
|
||||||
|
.map(|&(name, span)| {
|
||||||
|
cx.pat_some(span, cx.pat_ident(span, name))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let fields_pat = cx.pat_tuple(span, fields_pats);
|
||||||
|
|
||||||
|
let result = cx.expr_struct_ident(
|
||||||
|
span,
|
||||||
|
type_ident,
|
||||||
|
fields.iter()
|
||||||
|
.map(|&(name, span)| {
|
||||||
|
cx.field_imm(span, name, cx.expr_ident(span, name))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
);
|
||||||
|
|
||||||
|
quote_expr!(cx, {
|
||||||
|
$let_fields
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let token = match try!($deserializer.expect_token()) {
|
||||||
|
::serde::de::End => { break; }
|
||||||
|
token => token,
|
||||||
|
};
|
||||||
|
|
||||||
|
let key = match token {
|
||||||
|
::serde::de::Str(s) => s,
|
||||||
|
::serde::de::String(ref s) => s.as_slice(),
|
||||||
|
_ => { return $deserializer.syntax_error(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
match key {
|
||||||
|
$key_arms
|
||||||
|
_ => { return $deserializer.syntax_error(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = match $fields_tuple {
|
||||||
|
$fields_pat => { $result }
|
||||||
|
_ => { return $deserializer.syntax_error(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
try!($deserializer.expect_struct_end());
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user