codegen for service with generics
This commit is contained in:
parent
b7798d3869
commit
058ef59b13
@ -25,6 +25,9 @@ use syntax::ast::{
|
||||
PatKind,
|
||||
FunctionRetTy,
|
||||
Ty,
|
||||
TraitRef,
|
||||
Ident,
|
||||
Generics,
|
||||
};
|
||||
|
||||
use syntax::ast;
|
||||
@ -57,15 +60,15 @@ pub fn expand_ipc_implementation(
|
||||
|
||||
let builder = aster::AstBuilder::new().span(span);
|
||||
|
||||
let (impl_item, dispatches, replacements) = match implement_interface(cx, &builder, &item, push) {
|
||||
Ok((item, dispatches, replacements)) => (item, dispatches, replacements),
|
||||
let interface_map = match implement_interface(cx, &builder, &item, push) {
|
||||
Ok(interface_map) => interface_map,
|
||||
Err(Error) => { return; }
|
||||
};
|
||||
|
||||
push_client(cx, &builder, &item, &dispatches, push, &replacements);
|
||||
push_client(cx, &builder, &interface_map, push);
|
||||
push_handshake_struct(cx, push);
|
||||
|
||||
push(Annotatable::Item(impl_item));
|
||||
push(Annotatable::Item(interface_map.item));
|
||||
}
|
||||
|
||||
fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) {
|
||||
@ -95,7 +98,6 @@ fn push_invoke_signature_aster(
|
||||
replacements: &HashMap<String, P<Ty>>,
|
||||
push: &mut FnMut(Annotatable),
|
||||
) -> Dispatch {
|
||||
|
||||
let inputs = &signature.decl.inputs;
|
||||
let (input_type_name, input_arg_names, input_arg_tys) = if inputs.len() > 0 {
|
||||
let first_field_name = field_name(builder, &inputs[0]).name.as_str();
|
||||
@ -294,33 +296,6 @@ fn implement_dispatch_arms(
|
||||
.map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer, replacements) }).collect()
|
||||
}
|
||||
|
||||
/// generates client type for specified server type
|
||||
/// for say `Service` it generates `ServiceClient`
|
||||
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) {
|
||||
let (_, client_ident) = get_item_idents(builder, item);
|
||||
let client_struct_item = quote_item!(cx,
|
||||
pub struct $client_ident <S: ::ipc::IpcSocket> {
|
||||
socket: ::std::cell::RefCell<S>,
|
||||
phantom: ::std::marker::PhantomData<S>,
|
||||
});
|
||||
|
||||
push(Annotatable::Item(client_struct_item.expect(&format!("could not generate client struct for {:?}", client_ident.name))));
|
||||
}
|
||||
|
||||
/// pushes generated code for the client class (type declaration and method invocation implementations)
|
||||
fn push_client(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
item: &Item,
|
||||
dispatches: &[Dispatch],
|
||||
push: &mut FnMut(Annotatable),
|
||||
replacements: &HashMap<String, P<Ty>>,
|
||||
) {
|
||||
push_client_struct(cx, builder, item, push);
|
||||
push_client_implementation(cx, builder, dispatches, item, push, replacements);
|
||||
push_with_socket_client_implementation(cx, builder, item, push);
|
||||
}
|
||||
|
||||
/// 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)
|
||||
@ -344,10 +319,10 @@ fn implement_client_method_body(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
index: u16,
|
||||
dispatch: &Dispatch,
|
||||
replacements: &HashMap<String, P<Ty>>,
|
||||
interface_map: &InterfaceMap,
|
||||
) -> P<ast::Expr>
|
||||
{
|
||||
let dispatch = &interface_map.dispatches[index as usize];
|
||||
let request = if dispatch.input_arg_names.len() > 0 {
|
||||
|
||||
let arg_name = dispatch.input_arg_names[0].as_str();
|
||||
@ -356,7 +331,7 @@ fn implement_client_method_body(
|
||||
.ty().ref_()
|
||||
.lifetime("'a")
|
||||
.ty()
|
||||
.build(typegen::argument_replacement(builder, replacements, static_ty).unwrap_or(static_ty.clone()));
|
||||
.build(typegen::argument_replacement(builder, &interface_map.replacements, static_ty).unwrap_or(static_ty.clone()));
|
||||
|
||||
let mut tree = builder.item()
|
||||
.attr().word("derive(Serialize)")
|
||||
@ -374,7 +349,7 @@ fn implement_client_method_body(
|
||||
.ty().ref_()
|
||||
.lifetime("'a")
|
||||
.ty()
|
||||
.build(typegen::argument_replacement(builder, replacements, static_ty).unwrap_or(static_ty.clone()));
|
||||
.build(typegen::argument_replacement(builder, &interface_map.replacements, static_ty).unwrap_or(static_ty.clone()));
|
||||
tree = tree.field(arg_name).ty().build(arg_ty);
|
||||
|
||||
}
|
||||
@ -408,7 +383,7 @@ fn implement_client_method_body(
|
||||
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);
|
||||
let replacement = typegen::argument_replacement(builder, &interface_map.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)));
|
||||
@ -474,13 +449,13 @@ fn implement_client_method(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
index: u16,
|
||||
dispatch: &Dispatch,
|
||||
replacements: &HashMap<String, P<Ty>>,
|
||||
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, dispatch, replacements);
|
||||
let body = implement_client_method_body(cx, builder, index, interface_map);
|
||||
|
||||
let ext_cx = &*cx;
|
||||
// expanded version of this
|
||||
@ -527,18 +502,76 @@ fn implement_client_method(
|
||||
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(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
|
||||
let generics = client_generics(builder, interface_map);
|
||||
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(builder))
|
||||
.with_generics(generics).build()
|
||||
.build()
|
||||
}
|
||||
|
||||
fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
|
||||
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(builder);
|
||||
let where_clause = &generics.where_clause;
|
||||
let phantom = client_phantom_ident(builder, interface_map);
|
||||
|
||||
let client_struct_item = quote_item!(cx,
|
||||
pub struct $client_short_ident $generics {
|
||||
socket: ::std::cell::RefCell<S>,
|
||||
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,
|
||||
item: &Item,
|
||||
interface_map: &InterfaceMap,
|
||||
push: &mut FnMut(Annotatable))
|
||||
{
|
||||
let (_, client_ident) = get_item_idents(builder, item);
|
||||
let generics = client_generics(builder, interface_map);
|
||||
let client_ident = client_qualified_ident(builder, interface_map);
|
||||
let where_clause = &generics.where_clause;
|
||||
let client_short_ident = interface_map.ident_map.client_ident(builder);
|
||||
|
||||
let implement = quote_item!(cx,
|
||||
impl<S> ::ipc::WithSocket<S> for $client_ident<S> where S: ::ipc::IpcSocket {
|
||||
fn init(socket: S) -> $client_ident<S> {
|
||||
$client_ident {
|
||||
impl $generics ::ipc::WithSocket<S> for $client_ident $where_clause {
|
||||
fn init(socket: S) -> $client_ident {
|
||||
$client_short_ident {
|
||||
socket: ::std::cell::RefCell::new(socket),
|
||||
phantom: ::std::marker::PhantomData,
|
||||
}
|
||||
@ -551,20 +584,22 @@ fn push_with_socket_client_implementation(
|
||||
fn push_client_implementation(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
dispatches: &[Dispatch],
|
||||
item: &Item,
|
||||
interface_map: &InterfaceMap,
|
||||
push: &mut FnMut(Annotatable),
|
||||
replacements: &HashMap<String, P<Ty>>,
|
||||
) {
|
||||
let (item_ident, client_ident) = get_item_idents(builder, item);
|
||||
let (item_ident, client_ident) = (interface_map.ident_map.qualified_ident(builder), interface_map.ident_map.client_ident(builder));
|
||||
|
||||
let mut index = -1i32;
|
||||
let items = dispatches.iter()
|
||||
.map(|dispatch| { index = index + 1; P(implement_client_method(cx, builder, index as u16, dispatch, replacements)) })
|
||||
let items = interface_map.dispatches.iter()
|
||||
.map(|dispatch| { index = index + 1; P(implement_client_method(cx, builder, index as u16, interface_map)) })
|
||||
.collect::<Vec<P<ast::ImplItem>>>();
|
||||
|
||||
let generics = client_generics(builder, interface_map);
|
||||
let client_ident = client_qualified_ident(builder, interface_map);
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
let implement = quote_item!(cx,
|
||||
impl<S> $client_ident<S> where S: ::ipc::IpcSocket {
|
||||
impl $generics $client_ident $where_clause {
|
||||
pub fn handshake(&self) -> Result<(), ::ipc::Error> {
|
||||
let payload = BinHandshake {
|
||||
protocol_version: $item_ident::protocol_version().to_string(),
|
||||
@ -632,24 +667,6 @@ fn implement_handshake_arm(
|
||||
)
|
||||
}
|
||||
|
||||
fn get_item_idents(builder: &aster::AstBuilder, item: &Item) -> (::syntax::ast::Ident, ::syntax::ast::Ident) {
|
||||
let ty = match item.node {
|
||||
ast::ItemKind::Impl(_, _, _, _, ref ty, _) => ty.clone(),
|
||||
_ => { builder.ty().id("") }
|
||||
};
|
||||
|
||||
let (item_ident, client_ident) = match ty.node {
|
||||
::syntax::ast::TyKind::Path(_, ref path) => {
|
||||
(
|
||||
builder.id(format!("{}", path.segments[0].identifier)),
|
||||
builder.id(format!("{}Client", path.segments[0].identifier))
|
||||
)
|
||||
},
|
||||
_ => { panic!("incompatible implementation"); }
|
||||
};
|
||||
(item_ident, client_ident)
|
||||
}
|
||||
|
||||
fn collect_tys(items: &[&MethodSig]) -> Vec<P<Ty>> {
|
||||
let mut result = Vec::new();
|
||||
for signature in items {
|
||||
@ -661,15 +678,59 @@ fn collect_tys(items: &[&MethodSig]) -> Vec<P<Ty>> {
|
||||
result
|
||||
}
|
||||
|
||||
struct InterfaceMap {
|
||||
pub original_item: Item,
|
||||
pub item: P<ast::Item>,
|
||||
pub dispatches: Vec<Dispatch>,
|
||||
pub replacements: HashMap<String, P<Ty>>,
|
||||
pub generics: Generics,
|
||||
pub impl_trait: Option<TraitRef>,
|
||||
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, builder: &aster::AstBuilder) -> Ident {
|
||||
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<Ty>) -> 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
|
||||
}
|
||||
|
||||
fn item_ident_map(item: &Item) -> IdentMap {
|
||||
match item.node {
|
||||
ast::ItemKind::Impl(_, _, _, _, ref ty, _) => ty_ident_map(ty),
|
||||
_ => { panic!("Queried for non-implementation item!"); }
|
||||
}
|
||||
}
|
||||
|
||||
/// implements `IpcInterface<C>` for the given class `C`
|
||||
fn implement_interface(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
item: &Item,
|
||||
push: &mut FnMut(Annotatable),
|
||||
) -> Result<(P<ast::Item>, Vec<Dispatch>, HashMap<String, P<Ty>>), Error> {
|
||||
let (generics, impl_items) = match item.node {
|
||||
ast::ItemKind::Impl(_, _, ref generics, _, _, ref impl_items) => (generics, impl_items),
|
||||
) -> Result<InterfaceMap, Error> {
|
||||
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,
|
||||
@ -677,17 +738,9 @@ fn implement_interface(
|
||||
return Err(Error);
|
||||
}
|
||||
};
|
||||
|
||||
let impl_generics = builder.from_generics(generics.clone())
|
||||
.add_ty_param_bound(
|
||||
builder.path().global().ids(&["ethcore_ipc"]).build()
|
||||
)
|
||||
.build();
|
||||
|
||||
let impl_generics = builder.from_generics(generics.clone()).build();
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let (ty, _) = get_item_idents(builder, item);
|
||||
|
||||
let mut method_signatures = Vec::new();
|
||||
for impl_item in impl_items {
|
||||
if let ImplItemKind::Method(ref signature, _) = impl_item.node {
|
||||
@ -712,7 +765,8 @@ fn implement_interface(
|
||||
|
||||
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
|
||||
|
||||
Ok((quote_item!(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<R>(&self, r: &mut R) -> Vec<u8>
|
||||
where R: ::std::io::Read
|
||||
@ -743,5 +797,15 @@ fn implement_interface(
|
||||
}
|
||||
}
|
||||
}
|
||||
).unwrap(), dispatch_table, replacements))
|
||||
).unwrap();
|
||||
|
||||
Ok(InterfaceMap {
|
||||
ident_map: ty_ident_map(&original_ty),
|
||||
original_item: item.clone(),
|
||||
item: ipc_item,
|
||||
dispatches: dispatch_table,
|
||||
replacements: replacements,
|
||||
generics: generics.clone(),
|
||||
impl_trait: impl_trait.clone(),
|
||||
})
|
||||
}
|
||||
|
@ -36,6 +36,10 @@ fn is_new_entry(path: &Path) -> Option<String> {
|
||||
false
|
||||
} else {
|
||||
let ident = format!("{}", path.segments[0].identifier.name.as_str());
|
||||
ident == "u8" ||
|
||||
ident == "i8" ||
|
||||
ident == "u16" ||
|
||||
ident == "i16" ||
|
||||
ident == "u32" ||
|
||||
ident == "u64" ||
|
||||
ident == "usize" ||
|
||||
@ -199,12 +203,14 @@ pub fn match_unknown_tys(
|
||||
}
|
||||
},
|
||||
TyKind::Path(_, ref path) => {
|
||||
if path.segments.len() > 0 && path.segments[0].identifier.name.as_str() == "Option" ||
|
||||
path.segments[0].identifier.name.as_str() == "Result" {
|
||||
for extra_type in path.segments[0].parameters.types() {
|
||||
if !stop_list.contains(extra_type) {
|
||||
fringe.push(extra_type);
|
||||
}
|
||||
if path.segments.len() > 0 && {
|
||||
let first_segment = path.segments[0].identifier.name.as_str();
|
||||
first_segment == "Option" || first_segment == "Result" || first_segment == "Vec"
|
||||
}
|
||||
{
|
||||
let extra_type = &path.segments[0].parameters.types()[0];
|
||||
if !stop_list.contains(extra_type) {
|
||||
fringe.push(extra_type);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -24,6 +24,24 @@ use std::path::Path;
|
||||
pub fn main() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
|
||||
// ipc pass
|
||||
{
|
||||
let src = Path::new("nested.rs.in");
|
||||
let dst = Path::new(&out_dir).join("nested_ipc.rs");
|
||||
let mut registry = syntex::Registry::new();
|
||||
codegen::register(&mut registry);
|
||||
registry.expand("", &src, &dst).unwrap();
|
||||
}
|
||||
|
||||
// serde pass
|
||||
{
|
||||
let src = Path::new(&out_dir).join("nested_ipc.rs");
|
||||
let dst = Path::new(&out_dir).join("nested_cg.rs");
|
||||
let mut registry = syntex::Registry::new();
|
||||
serde_codegen::register(&mut registry);
|
||||
registry.expand("", &src, &dst).unwrap();
|
||||
}
|
||||
|
||||
// ipc pass
|
||||
{
|
||||
let src = Path::new("service.rs.in");
|
||||
@ -41,4 +59,5 @@ pub fn main() {
|
||||
serde_codegen::register(&mut registry);
|
||||
registry.expand("", &src, &dst).unwrap();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
mod tests {
|
||||
|
||||
use super::super::service::*;
|
||||
use super::super::nested::DBClient;
|
||||
use ipc::*;
|
||||
use devtools::*;
|
||||
use semver::Version;
|
||||
@ -121,4 +122,25 @@ mod tests {
|
||||
service_client.socket().borrow().write_buffer.clone());
|
||||
assert_eq!(true, result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_invoke_generic_service() {
|
||||
let mut socket = TestSocket::new();
|
||||
socket.read_buffer = vec![0, 0, 0, 0];
|
||||
let db_client = DBClient::<u64, _>::init(socket);
|
||||
|
||||
let result = db_client.write(vec![0u8; 100]);
|
||||
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
#[test]
|
||||
fn can_handshake_generic_service() {
|
||||
let mut socket = TestSocket::new();
|
||||
socket.read_buffer = vec![1];
|
||||
let db_client = DBClient::<u64, _>::init(socket);
|
||||
|
||||
let result = db_client.handshake();
|
||||
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
|
17
ipc/tests/nested.rs
Normal file
17
ipc/tests/nested.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/nested_cg.rs"));
|
44
ipc/tests/nested.rs.in
Normal file
44
ipc/tests/nested.rs.in
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::RwLock;
|
||||
use std::ops::*;
|
||||
use ipc::IpcConfig;
|
||||
|
||||
pub struct DB<L: Sized> {
|
||||
pub writes: RwLock<u64>,
|
||||
pub reads: RwLock<u64>,
|
||||
pub holdings: L,
|
||||
}
|
||||
|
||||
trait DBWriter {
|
||||
fn write(&self, data: Vec<u8>) -> Result<(), DBError>;
|
||||
}
|
||||
|
||||
impl<L: Sized> IpcConfig for DB<L> {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum DBError { Write, Read }
|
||||
|
||||
#[derive(Ipc)]
|
||||
impl<L: Sized> DBWriter for DB<L> {
|
||||
fn write(&self, data: Vec<u8>) -> Result<(), DBError> {
|
||||
let mut writes = self.writes.write().unwrap();
|
||||
*writes = *writes + data.len() as u64;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
extern crate bincode;
|
||||
extern crate ethcore_ipc as ipc;
|
||||
extern crate serde;
|
||||
@ -26,3 +28,4 @@ extern crate ethcore_util as util;
|
||||
pub mod service;
|
||||
mod examples;
|
||||
mod over_nano;
|
||||
mod nested;
|
||||
|
Loading…
Reference in New Issue
Block a user