compiles with custom bytes convertable arguments

This commit is contained in:
NikVolf 2016-04-13 12:09:47 +03:00
parent 3f5382d52c
commit 158f75b65d
3 changed files with 112 additions and 44 deletions

View File

@ -57,18 +57,15 @@ pub fn expand_ipc_implementation(
let builder = aster::AstBuilder::new().span(span); let builder = aster::AstBuilder::new().span(span);
let (impl_item, dispatches) = match implement_interface(cx, &builder, &item, push) { let (impl_item, dispatches, replacements) = match implement_interface(cx, &builder, &item, push) {
Ok((item, dispatches)) => (item, dispatches), Ok((item, dispatches, replacements)) => (item, dispatches, replacements),
Err(Error) => { return; } Err(Error) => { return; }
}; };
push_client(cx, &builder, &item, &dispatches, push); push_client(cx, &builder, &item, &dispatches, push, &replacements);
push_handshake_struct(cx, push); push_handshake_struct(cx, push);
push(Annotatable::Item(impl_item)); push(Annotatable::Item(impl_item));
let all_tys = dispatches.iter().flat_map(|ref dispatch| &dispatch.input_arg_tys).cloned().collect::<Vec<P<Ty>>>();
typegen::match_unknown_tys(cx, &builder, &all_tys, push);
} }
fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) { fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) {
@ -109,17 +106,16 @@ fn push_invoke_signature_aster(
let mut arg_names = Vec::new(); let mut arg_names = Vec::new();
let mut arg_tys = Vec::new(); let mut arg_tys = Vec::new();
let arg_name = format!("{}", field_name(builder, &inputs[skip-1]).name);
let mut arg_ty = inputs[skip-1].ty.clone(); let arg_name = format!("{}", field_name(builder, &inputs[skip-1]).name);
arg_ty = typegen::argument_replacement(builder, replacements, &arg_ty).unwrap_or(arg_ty); let arg_ty = inputs[skip-1].ty.clone();
let mut tree = builder.item() let mut tree = builder.item()
.attr().word("derive(Serialize, Deserialize)") .attr().word("derive(Serialize, Deserialize)")
.attr().word("allow(non_camel_case_types)") .attr().word("allow(non_camel_case_types)")
.struct_(name_str.as_str()) .struct_(name_str.as_str())
.field(arg_name.as_str()).ty() .field(arg_name.as_str()).ty()
.build(arg_ty.clone()); .build(typegen::argument_replacement(builder, replacements, &arg_ty).unwrap_or(arg_ty.clone()));
arg_names.push(arg_name); arg_names.push(arg_name);
arg_tys.push(arg_ty); arg_tys.push(arg_ty);
@ -129,7 +125,8 @@ fn push_invoke_signature_aster(
let mut arg_ty = arg.ty.clone(); let mut arg_ty = arg.ty.clone();
arg_ty = typegen::argument_replacement(builder, replacements, &arg_ty).unwrap_or(arg_ty); arg_ty = typegen::argument_replacement(builder, replacements, &arg_ty).unwrap_or(arg_ty);
tree = tree.field(arg_name.as_str()).ty().build(arg_ty.clone()); tree = tree.field(arg_name.as_str()).ty()
.build(typegen::argument_replacement(builder, replacements, &arg_ty).unwrap_or(arg_ty.clone()));
arg_names.push(arg_name); arg_names.push(arg_name);
arg_tys.push(arg_ty); arg_tys.push(arg_ty);
} }
@ -187,14 +184,20 @@ fn implement_dispatch_arm_invoke_stmt(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
dispatch: &Dispatch, dispatch: &Dispatch,
replacements: &HashMap<String, P<Ty>>,
) -> ast::Stmt ) -> ast::Stmt
{ {
let function_name = builder.id(dispatch.function_name.as_str()); let function_name = builder.id(dispatch.function_name.as_str());
let output_type_id = builder.id(dispatch.return_type_name.clone().unwrap().as_str()); let output_type_id = builder.id(dispatch.return_type_name.clone().unwrap().as_str());
let input_args_exprs = dispatch.input_arg_names.iter().map(|ref arg_name| { let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
let arg_ident = builder.id(arg_name); let arg_ident = builder.id(arg_name);
quote_expr!(cx, input. $arg_ident) if typegen::argument_replacement(builder, replacements, &dispatch.input_arg_tys[arg_index]).is_some() {
quote_expr!(cx, input. $arg_ident .into())
}
else {
quote_expr!(cx, input. $arg_ident)
}
}).collect::<Vec<P<ast::Expr>>>(); }).collect::<Vec<P<ast::Expr>>>();
let ext_cx = &*cx; let ext_cx = &*cx;
@ -251,6 +254,7 @@ fn implement_dispatch_arm_invoke(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
dispatch: &Dispatch, dispatch: &Dispatch,
buffer: bool, buffer: bool,
replacements: &HashMap<String, P<Ty>>,
) -> P<ast::Expr> ) -> P<ast::Expr>
{ {
let deserialize_expr = if buffer { let deserialize_expr = if buffer {
@ -261,7 +265,7 @@ fn implement_dispatch_arm_invoke(
let input_type_id = builder.id(dispatch.input_type_name.clone().unwrap().as_str()); let input_type_id = builder.id(dispatch.input_type_name.clone().unwrap().as_str());
let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch); let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch, replacements);
quote_expr!(cx, { quote_expr!(cx, {
let input: $input_type_id = $deserialize_expr; let input: $input_type_id = $deserialize_expr;
$invoke_serialize_stmt $invoke_serialize_stmt
@ -275,10 +279,11 @@ fn implement_dispatch_arm(
index: u32, index: u32,
dispatch: &Dispatch, dispatch: &Dispatch,
buffer: bool, buffer: bool,
replacements: &HashMap<String, P<Ty>>,
) -> ast::Arm ) -> ast::Arm
{ {
let index_ident = builder.id(format!("{}", index + (RESERVED_MESSAGE_IDS as u32)).as_str()); let index_ident = builder.id(format!("{}", index + (RESERVED_MESSAGE_IDS as u32)).as_str());
let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer); let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer, replacements);
quote_arm!(cx, $index_ident => { $invoke_expr } ) quote_arm!(cx, $index_ident => { $invoke_expr } )
} }
@ -287,11 +292,12 @@ fn implement_dispatch_arms(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
dispatches: &[Dispatch], dispatches: &[Dispatch],
buffer: bool, buffer: bool,
replacements: &HashMap<String, P<Ty>>,
) -> Vec<ast::Arm> ) -> Vec<ast::Arm>
{ {
let mut index = -1; let mut index = -1;
dispatches.iter() dispatches.iter()
.map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer) }).collect() .map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer, replacements) }).collect()
} }
/// generates client type for specified server type /// generates client type for specified server type
@ -313,10 +319,11 @@ fn push_client(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
item: &Item, item: &Item,
dispatches: &[Dispatch], dispatches: &[Dispatch],
push: &mut FnMut(Annotatable)) push: &mut FnMut(Annotatable),
{ replacements: &HashMap<String, P<Ty>>,
) {
push_client_struct(cx, builder, item, push); push_client_struct(cx, builder, item, push);
push_client_implementation(cx, builder, dispatches, item, push); push_client_implementation(cx, builder, dispatches, item, push, replacements);
push_with_socket_client_implementation(cx, builder, item, push); push_with_socket_client_implementation(cx, builder, item, push);
} }
@ -344,16 +351,18 @@ fn implement_client_method_body(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
index: u16, index: u16,
dispatch: &Dispatch, dispatch: &Dispatch,
) replacements: &HashMap<String, P<Ty>>,
-> P<ast::Expr> ) -> P<ast::Expr>
{ {
let request = if dispatch.input_arg_names.len() > 0 { let request = if dispatch.input_arg_names.len() > 0 {
let arg_name = dispatch.input_arg_names[0].as_str(); let arg_name = dispatch.input_arg_names[0].as_str();
let static_ty = &dispatch.input_arg_tys[0];
let arg_ty = builder let arg_ty = builder
.ty().ref_() .ty().ref_()
.lifetime("'a") .lifetime("'a")
.ty().build(dispatch.input_arg_tys[0].clone()); .ty()
.build(typegen::argument_replacement(builder, replacements, static_ty).unwrap_or(static_ty.clone()));
let mut tree = builder.item() let mut tree = builder.item()
.attr().word("derive(Serialize)") .attr().word("derive(Serialize)")
@ -361,15 +370,19 @@ fn implement_client_method_body(
.generics() .generics()
.lifetime_name("'a") .lifetime_name("'a")
.build() .build()
.field(arg_name).ty().build(arg_ty); .field(arg_name).ty()
.build(arg_ty);
for arg_idx in 1..dispatch.input_arg_names.len() { for arg_idx in 1..dispatch.input_arg_names.len() {
let arg_name = dispatch.input_arg_names[arg_idx].as_str(); let arg_name = dispatch.input_arg_names[arg_idx].as_str();
let static_ty = &dispatch.input_arg_tys[arg_idx];
let arg_ty = builder let arg_ty = builder
.ty().ref_() .ty().ref_()
.lifetime("'a") .lifetime("'a")
.ty().build(dispatch.input_arg_tys[arg_idx].clone()); .ty()
.build(typegen::argument_replacement(builder, replacements, static_ty).unwrap_or(static_ty.clone()));
tree = tree.field(arg_name).ty().build(arg_ty); tree = tree.field(arg_name).ty().build(arg_ty);
} }
let mut request_serialization_statements = Vec::new(); let mut request_serialization_statements = Vec::new();
@ -394,11 +407,28 @@ fn implement_client_method_body(
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
for arg in dispatch.input_arg_names.iter() { for (idx, arg) in dispatch.input_arg_names.iter().enumerate() {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
let arg_ty = &dispatch.input_arg_tys[idx];
let replacement = typegen::argument_replacement(builder, replacements, arg_ty);
if let Some(ref replacement_ty) = replacement {
let replacor_ident = ::syntax::print::pprust::ty_to_string(replacement_ty);
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(&replacor_ident), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("from"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()), ::syntax::parse::token::Plain)));
if replacement.is_some() {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
} }
@ -450,11 +480,13 @@ fn implement_client_method(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
index: u16, index: u16,
dispatch: &Dispatch) dispatch: &Dispatch,
replacements: &HashMap<String, P<Ty>>,
)
-> ast::ImplItem -> ast::ImplItem
{ {
let method_name = builder.id(dispatch.function_name.as_str()); let method_name = builder.id(dispatch.function_name.as_str());
let body = implement_client_method_body(cx, builder, index, dispatch); let body = implement_client_method_body(cx, builder, index, dispatch, replacements);
let ext_cx = &*cx; let ext_cx = &*cx;
// expanded version of this // expanded version of this
@ -527,13 +559,14 @@ fn push_client_implementation(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
dispatches: &[Dispatch], dispatches: &[Dispatch],
item: &Item, item: &Item,
push: &mut FnMut(Annotatable)) push: &mut FnMut(Annotatable),
{ replacements: &HashMap<String, P<Ty>>,
) {
let (item_ident, client_ident) = get_item_idents(builder, item); let (item_ident, client_ident) = get_item_idents(builder, item);
let mut index = -1i32; let mut index = -1i32;
let items = dispatches.iter() let items = dispatches.iter()
.map(|dispatch| { index = index + 1; P(implement_client_method(cx, builder, index as u16, dispatch)) }) .map(|dispatch| { index = index + 1; P(implement_client_method(cx, builder, index as u16, dispatch, replacements)) })
.collect::<Vec<P<ast::ImplItem>>>(); .collect::<Vec<P<ast::ImplItem>>>();
let implement = quote_item!(cx, let implement = quote_item!(cx,
@ -623,13 +656,28 @@ fn get_item_idents(builder: &aster::AstBuilder, item: &Item) -> (::syntax::ast::
(item_ident, client_ident) (item_ident, client_ident)
} }
fn collect_tys(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
items: &[&MethodSig],
) -> Vec<P<Ty>> {
let mut result = Vec::new();
for signature in items {
result.extend(signature.decl.inputs.iter().map(|input_arg| input_arg.ty.clone()));
if let FunctionRetTy::Ty(ref ty) = signature.decl.output {
result.push(ty.clone())
};
}
result
}
/// implements `IpcInterface<C>` for the given class `C` /// implements `IpcInterface<C>` for the given class `C`
fn implement_interface( fn implement_interface(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
item: &Item, item: &Item,
push: &mut FnMut(Annotatable), push: &mut FnMut(Annotatable),
) -> Result<(P<ast::Item>, Vec<Dispatch>), Error> { ) -> Result<(P<ast::Item>, Vec<Dispatch>, HashMap<String, P<Ty>>), Error> {
let (generics, impl_items) = match item.node { let (generics, impl_items) = match item.node {
ast::ItemKind::Impl(_, _, ref generics, _, _, ref impl_items) => (generics, impl_items), ast::ItemKind::Impl(_, _, ref generics, _, _, ref impl_items) => (generics, impl_items),
_ => { _ => {
@ -650,15 +698,26 @@ fn implement_interface(
let (ty, _) = get_item_idents(builder, item); let (ty, _) = get_item_idents(builder, item);
let mut dispatch_table = Vec::new(); let mut method_signatures = Vec::new();
for impl_item in impl_items { for impl_item in impl_items {
if let ImplItemKind::Method(ref signature, _) = impl_item.node { if let ImplItemKind::Method(ref signature, _) = impl_item.node {
dispatch_table.push(push_invoke_signature_aster(builder, &impl_item, signature, &HashMap::<String, P<Ty>>::new(), push)); method_signatures.push((impl_item, signature))
} }
} }
let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false); let all_tys = collect_tys(
let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true); cx,
builder,
&method_signatures.iter().map(|&(_, signature)| signature).collect::<Vec<&MethodSig>>());
let replacements = typegen::match_unknown_tys(cx, builder, &all_tys, push);
let dispatch_table = method_signatures.iter().map(|&(impl_item, signature)|
push_invoke_signature_aster(builder, impl_item, signature, &replacements, push))
.collect::<Vec<Dispatch>>();
let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false, &replacements);
let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true, &replacements);
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx); let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
@ -692,5 +751,5 @@ fn implement_interface(
} }
} }
} }
).unwrap(), dispatch_table)) ).unwrap(), dispatch_table, replacements))
} }

View File

@ -52,7 +52,7 @@ fn is_new_entry(builder: &aster::AstBuilder, path: &Path) -> Option<String> {
ident == "i32" || ident == "i32" ||
ident == "i64" || ident == "i64" ||
ident == "String" || ident == "String" ||
ident == "Option" ident == "bool"
} }
}; };
@ -146,13 +146,12 @@ pub fn push_bin_box(
} }
}).unwrap())); }).unwrap()));
let serialize_impl = quote_item!(cx, let serialize_impl = quote_item!(cx,
impl ::serde::ser::Serialize for $ident { impl ::serde::ser::Serialize for $ident {
fn serialize<__S>(&self, _serializer: &mut __S) -> ::std::result::Result<(), __S::Error> fn serialize<__S>(&self, _serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
where __S: ::serde::ser::Serializer where __S: ::serde::ser::Serializer
{ {
let &$ident(val) = self; let &$ident(ref val) = self;
_serializer.serialize_bytes(val.as_slice()) _serializer.serialize_bytes(val.as_slice())
} }
}).unwrap(); }).unwrap();
@ -242,7 +241,7 @@ pub fn match_unknown_tys(
None => {} None => {}
} }
}, },
_ => { panic!("bad parameter in input args: {:?}", ty) } _ => { }
} }
} }

View File

@ -32,13 +32,23 @@ pub struct CustomData {
impl FromRawBytes for CustomData { impl FromRawBytes for CustomData {
fn from_bytes(bytes: &[u8]) -> Result<CustomData, FromBytesError> { fn from_bytes(bytes: &[u8]) -> Result<CustomData, FromBytesError> {
Ok(CustomData { a: bytes[0] * 256 + bytes[1], b: bytes[2] * 256 + bytes[3]}) Ok(CustomData {
a: bytes[0] as usize * 256 + bytes[1] as usize,
b: bytes[2] as usize * 256 + bytes[3] as usize
})
} }
} }
impl BytesConvertable for CustomData { impl BytesConvertable for CustomData {
fn bytes(&self) -> &[u8] { fn bytes(&self) -> &[u8] {
unsafe { &::std::mem::transmute::<[u8;8]>(self) } let ip: *const CustomData = self;
let ptr: *const u8 = ip as *const _;
unsafe {
::std::slice::from_raw_parts(
ptr,
::std::mem::size_of::<i64>()
)
}
} }
} }
@ -56,8 +66,8 @@ impl Service {
(a_0 - b) as i32 (a_0 - b) as i32
} }
pub fn push_custom(&self, data: CustomData) -> bool { pub fn push_custom(&self, data: CustomData) -> bool {
let clock = self.commits.write().unwrap(); let mut clock = self.commits.write().unwrap();
let rlock = self.commits.write().unwrap(); let mut rlock = self.commits.write().unwrap();
*clock = data.a; *clock = data.a;
*rlock = data.b; *rlock = data.b;