,
input_arg_tys: Vec>,
return_type_ty: Option
>,
}
// This is the expanded version of this:
//
// let invoke_serialize_stmt = quote_stmt!(cx, {
// ::bincode::serde::serialize(& $output_type_id { payload: self. $function_name ($hand_param_a, $hand_param_b) }, ::bincode::SizeLimit::Infinite).unwrap()
// });
//
// But the above does not allow comma-separated expressions for arbitrary number
// of parameters ...$hand_param_a, $hand_param_b, ... $hand_param_n
fn implement_dispatch_arm_invoke_stmt(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
dispatch: &Dispatch,
) -> ast::Stmt
{
let function_name = builder.id(dispatch.function_name.as_str());
let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
let arg_ident = builder.id(arg_name);
let expr = quote_expr!(cx, input. $arg_ident);
if has_ptr(&dispatch.input_arg_tys[arg_index]) { quote_expr!(cx, & $expr) }
else { expr }
}).collect::>>();
let ext_cx = &*cx;
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
ext_cx.parse_sess(),
ext_cx.cfg(),
{
let _sp = ext_cx.call_site();
let mut tt = ::std::vec::Vec::new();
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::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc"))));
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("binary"))));
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("serialize"))));
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::BinOp(::syntax::parse::token::And)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
for arg_expr in input_args_exprs {
tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
}
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::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"))));
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::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
tt
})).unwrap()
}
fn implement_dispatch_arm_invoke(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
dispatch: &Dispatch,
buffer: bool,
) -> P
{
let deserialize_expr = if buffer {
quote_expr!(cx, ::ipc::binary::deserialize(buf).expect("ipc deserialization error, aborting"))
} else {
quote_expr!(cx, ::ipc::binary::deserialize_from(r).expect("ipc deserialization error, aborting"))
};
let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch);
dispatch.input_type_name.as_ref().map(|val| {
let input_type_id = builder.id(val.clone().as_str());
quote_expr!(cx, {
let input: $input_type_id = $deserialize_expr;
$invoke_serialize_stmt
})
}).unwrap_or(quote_expr!(cx, { $invoke_serialize_stmt }))
}
/// generates dispatch match for method id
fn implement_dispatch_arm(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
index: u32,
dispatch: &Dispatch,
buffer: bool,
) -> ast::Arm
{
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);
quote_arm!(cx, $index_ident => { $invoke_expr } )
}
fn implement_dispatch_arms(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
dispatches: &[Dispatch],
buffer: bool,
) -> Vec
{
let mut index = -1;
dispatches.iter()
.map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer) }).collect()
}
pub fn strip_ptr(ty: &P) -> P {
if let ast::TyKind::Rptr(_, ref ptr_mut) = ty.node {
ptr_mut.ty.clone()
}
else { ty.clone() }
}
pub fn has_ptr(ty: &P) -> bool {
if let ast::TyKind::Rptr(_, ref _ptr_mut) = ty.node {
true
}
else { false }
}
/// returns an expression with the body for single operation that is being sent to server
/// operation itself serializes input, writes to socket and waits for socket to respond
/// (the latter only if original method signature returns anyting)
///
/// assuming expanded class contains method
/// fn commit(&self, f: u32) -> u32
///
/// the expanded implementation will generate method for the client like that
/// #[derive(Serialize)]
/// struct Request<'a> {
/// f: &'a u32,
/// }
/// let payload = Request{f: &f,};
/// let mut socket_ref = self.socket.borrow_mut();
/// let mut socket = socket_ref.deref_mut();
/// let serialized_payload = ::bincode::serde::serialize(&payload, ::bincode::SizeLimit::Infinite).unwrap();
/// ::ipc::invoke(0, &Some(serialized_payload), &mut socket);
/// while !socket.ready().load(::std::sync::atomic::Ordering::Relaxed) { }
/// ::bincode::serde::deserialize_from::<_, u32>(&mut socket, ::bincode::SizeLimit::Infinite).unwrap()
fn implement_client_method_body(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
index: u16,
interface_map: &InterfaceMap,
) -> P
{
let dispatch = &interface_map.dispatches[index as usize];
let index_ident = builder.id(format!("{}", index + RESERVED_MESSAGE_IDS).as_str());
let request = if dispatch.input_arg_names.len() > 0 {
let arg_name = dispatch.input_arg_names[0].as_str();
let static_ty = strip_ptr(&dispatch.input_arg_tys[0]);
let arg_ty = builder
.ty().ref_()
.lifetime("'a")
.ty()
.build(static_ty.clone());
let mut tree = builder.item()
.attr().word("derive(Binary)")
.struct_("Request")
.generics()
.lifetime_name("'a")
.build()
.field(arg_name).ty()
.build(arg_ty);
for arg_idx in 1..dispatch.input_arg_names.len() {
let arg_name = dispatch.input_arg_names[arg_idx].as_str();
let static_ty = strip_ptr(&dispatch.input_arg_tys[arg_idx]);
let arg_ty = builder
.ty().ref_()
.lifetime("'a")
.ty()
.build(static_ty);
tree = tree.field(arg_name).ty().build(arg_ty);
}
let mut request_serialization_statements = Vec::new();
let struct_tree = tree.build();
let struct_stmt = quote_stmt!(cx, $struct_tree);
request_serialization_statements.push(struct_stmt);
// actually this is just expanded version of this:
// request_serialization_statements.push(quote_stmt!(cx, let payload = Request { p1: &p1, p2: &p2, ... pn: &pn, }));
// again, cannot dynamically create expression with arbitrary number of comma-separated members
request_serialization_statements.push({
let ext_cx = &*cx;
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
ext_cx.parse_sess(),
ext_cx.cfg(),
{
let _sp = ext_cx.call_site();
let mut tt = ::std::vec::Vec::new();
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("let"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Eq));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
for arg in dispatch.input_arg_names.iter() {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
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::Ident(ext_cx.ident_of(arg.as_str()))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
tt
}))
});
request_serialization_statements.push(
quote_stmt!(cx, let mut socket = self.socket.write().unwrap(); ));
request_serialization_statements.push(
quote_stmt!(cx, let serialized_payload = ::ipc::binary::serialize(&payload).unwrap()));
request_serialization_statements.push(
quote_stmt!(cx, ::ipc::invoke($index_ident, &Some(serialized_payload), &mut *socket)));
request_serialization_statements
}
else {
let mut request_serialization_statements = Vec::new();
request_serialization_statements.push(
quote_stmt!(cx, let mut socket = self.socket.write().unwrap(); ));
request_serialization_statements.push(
quote_stmt!(cx, ::ipc::invoke($index_ident, &None, &mut *socket)));
request_serialization_statements
};
if let Some(ref return_ty) = dispatch.return_type_ty {
let return_expr = quote_expr!(cx,
::ipc::binary::deserialize_from::<$return_ty, _>(&mut *socket).unwrap()
);
quote_expr!(cx, {
$request
$return_expr
})
}
else {
quote_expr!(cx, {
$request
})
}
}
/// Generates signature and body (see `implement_client_method_body`)
/// for the client (signature is identical to the original method)
fn implement_client_method(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
index: u16,
interface_map: &InterfaceMap,
)
-> ast::ImplItem
{
let dispatch = &interface_map.dispatches[index as usize];
let method_name = builder.id(dispatch.function_name.as_str());
let body = implement_client_method_body(cx, builder, index, interface_map);
let ext_cx = &*cx;
// expanded version of this
// pub fn $method_name(&self, p1: p1_ty, p2: p2_ty ... pn: pn_ty, ) [-> return_ty] { $body }
// looks like it's tricky to build function declaration with aster if body already generated
let signature = ::syntax::parse::parser::Parser::parse_impl_item(
&mut ::syntax::parse::new_parser_from_tts(
ext_cx.parse_sess(),
ext_cx.cfg(),
{
let _sp = ext_cx.call_site();
let mut tt = ::std::vec::Vec::new();
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("fn"))));
tt.extend(::quasi::ToTokens::to_tokens(&method_name, ext_cx).into_iter());
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::BinOp(::syntax::parse::token::And)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
for arg_idx in 0..dispatch.input_arg_names.len() {
let arg_name = dispatch.input_arg_names[arg_idx].as_str();
let arg_ty = dispatch.input_arg_tys[arg_idx].clone();
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg_name))));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon));
tt.extend(::quasi::ToTokens::to_tokens(&arg_ty, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
if let Some(ref return_ty) = dispatch.return_type_ty {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::RArrow));
tt.extend(::quasi::ToTokens::to_tokens(return_ty, ext_cx).into_iter());
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
tt.extend(::quasi::ToTokens::to_tokens(&body, ext_cx).into_iter());
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
tt
}));
signature.unwrap()
}
fn client_generics(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> Generics {
let ty_param = aster::ty_param::TyParamBuilder::new(
builder.id("S")).trait_bound(
builder.path().global().ids(&["ipc", "IpcSocket"]).build()
).build().build();
builder.from_generics(interface_map.generics.clone())
.with_ty_param(ty_param)
.build()
}
fn client_qualified_ident(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P {
let generics = client_generics(builder, interface_map);
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item))
.with_generics(generics).build()
.build()
}
fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P {
let generics = client_generics(builder, interface_map);
aster::ty::TyBuilder::new().phantom_data()
.tuple().with_tys(generics.ty_params.iter().map(|x| aster::ty::TyBuilder::new().id(x.ident)))
.build()
}
/// generates client type for specified server type
/// for say `Service` it generates `ServiceClient`
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap, push: &mut FnMut(Annotatable)) {
let generics = client_generics(builder, interface_map);
let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item);
let phantom = client_phantom_ident(builder, interface_map);
let client_struct_item = quote_item!(cx,
pub struct $client_short_ident $generics {
socket: ::std::sync::RwLock,
phantom: $phantom,
});
push(Annotatable::Item(client_struct_item.expect(&format!("could not generate client struct for {:?}", client_short_ident.name))));
}
/// pushes generated code for the client class (type declaration and method invocation implementations)
fn push_client(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
interface_map: &InterfaceMap,
push: &mut FnMut(Annotatable),
) {
push_client_struct(cx, builder, interface_map, push);
push_client_implementation(cx, builder, interface_map, push);
push_with_socket_client_implementation(cx, builder, interface_map, push);
}
fn push_with_socket_client_implementation(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
interface_map: &InterfaceMap,
push: &mut FnMut(Annotatable))
{
let generics = client_generics(builder, interface_map);
let client_ident = client_qualified_ident(cx, builder, interface_map);
let where_clause = &generics.where_clause;
let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item);
let implement = quote_item!(cx,
impl $generics ::ipc::WithSocket for $client_ident $where_clause {
fn init(socket: S) -> $client_ident {
$client_short_ident {
socket: ::std::sync::RwLock::new(socket),
phantom: ::std::marker::PhantomData,
}
}
}).unwrap();
push(Annotatable::Item(implement));
}
/// pushes full client side code for the original class exposed via ipc
fn push_client_implementation(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
interface_map: &InterfaceMap,
push: &mut FnMut(Annotatable),
) {
let item_ident = interface_map.ident_map.qualified_ident(builder);
let mut index = -1i32;
let items = interface_map.dispatches.iter()
.map(|_| { index = index + 1; P(implement_client_method(cx, builder, index as u16, interface_map)) })
.collect::>>();
let generics = client_generics(builder, interface_map);
let client_ident = client_qualified_ident(cx, builder, interface_map);
let where_clause = &generics.where_clause;
let handshake_item = quote_impl_item!(cx,
pub fn handshake(&self) -> Result<(), ::ipc::Error> {
let payload = BinHandshake {
protocol_version: $item_ident::protocol_version().to_string(),
api_version: $item_ident::api_version().to_string(),
reserved: vec![0u8; 64],
};
::ipc::invoke(
0,
&Some(::ipc::binary::serialize(&payload).unwrap()),
&mut *self.socket.write().unwrap());
let mut result = vec![0u8; 1];
if try!(self.socket.write().unwrap().read(&mut result).map_err(|_| ::ipc::Error::HandshakeFailed)) == 1 {
match result[0] {
1 => Ok(()),
_ => Err(::ipc::Error::RemoteServiceUnsupported),
}
}
else { Err(::ipc::Error::HandshakeFailed) }
}).unwrap();
let socket_item = quote_impl_item!(cx,
#[cfg(test)]
pub fn socket(&self) -> &::std::sync::RwLock {
&self.socket
}).unwrap();
let generic_items = vec![P(handshake_item), P(socket_item)];
if interface_map.impl_trait.is_some() {
let trait_ty = builder.id(
::syntax::print::pprust::path_to_string(
&interface_map.impl_trait.as_ref().unwrap().path));
let implement_trait =
quote_item!(cx,
impl $generics $trait_ty for $client_ident $where_clause {
$items
}
).unwrap();
push(Annotatable::Item(implement_trait));
let implement =
quote_item!(cx,
impl $generics $client_ident $where_clause {
$generic_items
}
).unwrap();
push(Annotatable::Item(implement));
}
else {
let pub_items = items.iter().map(|item| {
let pub_item = item.clone();
pub_item.map(|mut val| { val.vis = ast::Visibility::Public; val })
}).collect::>>();
let implement = quote_item!(cx,
impl $generics $client_ident $where_clause {
$pub_items
$generic_items
}).unwrap();
push(Annotatable::Item(implement));
}
}
/// implements dispatching of system handshake invocation (method_num 0)
fn implement_handshake_arm(
cx: &ExtCtxt,
) -> (ast::Arm, ast::Arm)
{
let handshake_deserialize = quote_stmt!(&cx,
let handshake_payload = ::ipc::binary::deserialize_from::(r).unwrap();
);
let handshake_deserialize_buf = quote_stmt!(&cx,
let handshake_payload = ::ipc::binary::deserialize::(buf).unwrap();
);
let handshake_serialize = quote_expr!(&cx,
::ipc::binary::serialize::(&Self::handshake(&::ipc::Handshake {
api_version: ::semver::Version::parse(&handshake_payload.api_version).unwrap(),
protocol_version: ::semver::Version::parse(&handshake_payload.protocol_version).unwrap(),
})).unwrap()
);
(
quote_arm!(&cx, 0 => {
$handshake_deserialize
$handshake_serialize
}),
quote_arm!(&cx, 0 => {
$handshake_deserialize_buf
$handshake_serialize
}),
)
}
fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result {
match lit.node {
ast::LitKind::Str(ref s, _) => Ok(format!("{}", s)),
_ => {
cx.span_err(
lit.span,
&format!("ipc client_ident annotation `{}` must be a string, not `{}`",
name,
::syntax::print::pprust::lit_to_string(lit)));
return Err(());
}
}
}
pub fn get_ipc_meta_items(attr: &ast::Attribute) -> Option<&[P]> {
match attr.node.value.node {
ast::MetaItemKind::List(ref name, ref items) if name == &"ipc" => {
Some(items)
}
_ => None
}
}
fn client_ident_renamed(cx: &ExtCtxt, item: &ast::Item) -> Option {
for meta_items in item.attrs().iter().filter_map(get_ipc_meta_items) {
for meta_item in meta_items {
let span = meta_item.span;
match meta_item.node {
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"client_ident" => {
if let Ok(s) = get_str_from_lit(cx, name, lit) {
return Some(s);
}
}
_ => {
cx.span_err(
meta_item.span,
&format!("unknown client_ident container attribute `{}`",
::syntax::print::pprust::meta_item_to_string(meta_item)));
}
}
}
}
None
}
struct InterfaceMap {
pub original_item: Item,
pub item: P,
pub dispatches: Vec,
pub generics: Generics,
pub impl_trait: Option,
pub ident_map: IdentMap,
}
struct IdentMap {
original_path: ast::Path,
}
impl IdentMap {
fn ident(&self, builder: &aster::AstBuilder) -> Ident {
builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path)))
}
fn client_ident(&self, cx: &ExtCtxt, builder: &aster::AstBuilder, item: &ast::Item) -> Ident {
if let Some(new_name) = client_ident_renamed(cx, item) {
builder.id(new_name)
}
else {
builder.id(format!("{}Client", self.original_path.segments[0].identifier))
}
}
fn qualified_ident(&self, builder: &aster::AstBuilder) -> Ident {
builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path).replace("<", "::<")))
}
}
fn ty_ident_map(original_ty: &P) -> IdentMap {
let original_path = match original_ty.node {
::syntax::ast::TyKind::Path(_, ref path) => path.clone(),
_ => { panic!("incompatible implementation"); }
};
let ident_map = IdentMap { original_path: original_path };
ident_map
}
/// implements `IpcInterface` for the given class `C`
fn implement_interface(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
item: &Item,
push: &mut FnMut(Annotatable),
) -> Result {
let (generics, impl_trait, original_ty, impl_items) = match item.node {
ast::ItemKind::Impl(_, _, ref generics, ref impl_trait, ref ty, ref impl_items) => (generics, impl_trait, ty, impl_items),
_ => {
cx.span_err(
item.span,
"`#[derive(Ipc)]` may only be applied to item implementations");
return Err(Error);
},
};
let impl_generics = builder.from_generics(generics.clone()).build();
let where_clause = &impl_generics.where_clause;
let mut method_signatures = Vec::new();
for impl_item in impl_items {
if let ImplItemKind::Method(ref signature, _) = impl_item.node {
method_signatures.push((impl_item, signature))
}
}
let dispatch_table = method_signatures.iter().map(|&(impl_item, signature)|
push_invoke_signature_aster(builder, impl_item, signature, push))
.collect::>();
let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false);
let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true);
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
let ty = ty_ident_map(&original_ty).ident(builder);
let ipc_item = quote_item!(cx,
impl $impl_generics ::ipc::IpcInterface<$ty> for $ty $where_clause {
fn dispatch(&self, r: &mut R) -> Vec
where R: ::std::io::Read
{
let mut method_num = vec![0u8;2];
match r.read(&mut method_num) {
Ok(size) if size == 0 => { panic!("method id not supplied" ); }
Err(e) => { panic!("ipc read error: {:?}, aborting", e); }
_ => { }
}
// method_num is a 16-bit little-endian unsigned number
match method_num[1] as u16 + (method_num[0] as u16)*256 {
// handshake
$handshake_arm
// user methods
$dispatch_arms
_ => vec![]
}
}
fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec
{
match method_num {
$handshake_arm_buf
$dispatch_arms_buffered
_ => vec![]
}
}
}
).unwrap();
Ok(InterfaceMap {
ident_map: ty_ident_map(&original_ty),
original_item: item.clone(),
item: ipc_item,
dispatches: dispatch_table,
generics: generics.clone(),
impl_trait: impl_trait.clone(),
})
}