-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Serialize/Deserialize #71
Conversation
exonum/src/blockchain/spec.rs
Outdated
@@ -1,5 +1,9 @@ | |||
#[macro_export] | |||
macro_rules! storage_value { | |||
(@count ) => {0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, implement this as separate macros:
macro_rules! counter {
() => { 0 };
($head:ident $($tail:ident)*) => { 1 + counter!($($tail)*) }
}
and than just call counter!($($field_name ))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@defuz if I implement it in separate macros, then I should export this macros too, and waste global namespace, is it ok?
exonum/src/blockchain/spec.rs
Outdated
use ::serde::ser::SerializeStruct; | ||
let mut strukt = serializer.serialize_struct(stringify!($name), counter!($($field_name)*))?; | ||
$(strukt.serialize_field(stringify!($field_name), &$crate::serialize::json::wrap(&self.$field_name()))?;)* | ||
strukt.end() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strukt
is a funny name. I understand that you cannot use struct
name, but maybe a simple val
would be better? Nothing better comes to my mind right now.
|
||
Ok(()) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a new line at the end of the file.
blockchain_explorer/src/api.rs
Outdated
@@ -133,12 +134,16 @@ struct HexVisitor<T> | |||
_p: PhantomData<T>, | |||
} | |||
|
|||
impl<T> Visitor for HexVisitor<T> | |||
impl<'a, T> Visitor<'a> for HexVisitor<T> | |||
where T: AsRef<[u8]> + HexValue + Clone | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a nitpick: you used 'v lifetime for Visitor in other places. It would be consistent to use it everywhere.
impl<'a> Field<'a> for &'a Signature { | ||
fn field_size() -> usize { | ||
32 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to use std::mem::size_of::<Signature>()
instead of the hard-coded value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but I will done this with all fields after refactor Fields
exonum/src/messages/protocol.rs
Outdated
} | ||
|
||
// Message with current state. | ||
// сообщение о текущем состоянии |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please leave the English version of the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ty, fxd
exonum/src/serialize/json.rs
Outdated
} | ||
|
||
impl WriteBufferWrapper for ::messages::MessageWriter { | ||
fn write<'a, T: Field<'a> >(&'a mut self, from: usize, to: usize, val:T){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a specific reason for importing messages::Field
and not messages::MessageWriter
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fxd
exonum/src/serialize/json.rs
Outdated
pub fn from_str<T: ExonumJsonDeserialize>(value: &str) -> Result<T, Box<Error>> { | ||
let value: Value = ::serde_json::from_str(value)?; | ||
from_value(&value) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -533,4 +523,4 @@ mod tests { | |||
assert_eq!(&bit_vec.repr(), "0111111101"); | |||
} | |||
|
|||
} | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line.
macro_rules! counter { | ||
() => (0usize); | ||
($head:ident $($tail:ident)*) => (1usize + counter!($($tail)*)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
} | ||
|
||
#[macro_use] | ||
mod utils; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -11,11 +11,13 @@ use std::fs::File; | |||
pub struct ConfigFile {} | |||
|
|||
impl ConfigFile { | |||
pub fn load<T: Deserialize>(path: &Path) -> Result<T, Box<Error>> { | |||
pub fn load<T>(path: &Path) -> Result<T, Box<Error>> | |||
where T: for<'r> Deserialize<'r> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also update toml
crate and simplify this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does toml
has new api for working with files?
} | ||
|
||
/* | ||
macro_rules! impl_deserialize_float { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this code is commented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because we currently didn't support float fields
blockchain_explorer/Cargo.toml
Outdated
serde = "0.8" | ||
serde_derive = "0.8" | ||
serde_json = "0.8" | ||
serde = "1.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Racer
does not like version strings without patch. It is better to use "1.0.0" instead of "1.0".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, ty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still I don't like strukt
variable name. If you have no idea for a more specific name, even struct_
will be better, as for me.
Rebased again, review pls @defuz @alekseysidorov @DarkEld3r @gisochre |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we supposed to use only Exonum-J...
traits and available helpers in exonum::serialize::json::{to_value, from_value, to_string, from_str}
? https://travis-ci.com/exonum/cryptocurrency/builds/46367602.
A minor issue is this:
error[E0277]: the trait bound `&str: exonum::serialize::json::ExonumJsonSerialize` is not satisfied
--> src/lib.rs:71:1
|
71 | message! {
| ^ the trait `exonum::serialize::json::ExonumJsonSerialize` is not implemented for `&str`
|
= note: required because of the requirements on the impl of `serde::Serialize` for `exonum::serialize::json::ExonumJsonSerializeWrapper<'_, &str>`
= note: this error originates in a macro outside of the current crate
error[E0277]: the trait bound `&str: exonum::serialize::json::ExonumJsonDeserializeField` is not satisfied
--> src/lib.rs:71:1
|
71 | message! {
| ^ the trait `exonum::serialize::json::ExonumJsonDeserializeField` is not implemented for `&str`
|
= note: required by `exonum::serialize::json::ExonumJsonDeserializeField::deserialize`
= note: this error originates in a macro outside of the current crate
The major issue for me is this: serde::Serialize, Deserialize isn't implemented for storage!
and message!
.
This would be inconvenient, when composing structs with #[derive(Ser/De)]
. But we can live without it, probably, or do the following manually:
impl<'de> Deserialize<'de> for Wallet {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
let value = <Value>::deserialize(deserializer)?;
from_value(&value).map_err(|_| D::Error::custom(""))
}
}
impl Serialize for Wallet {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
wrap(self).serialize(serializer)
}
}
@defuz. What approach do we pursue? Why not add default Serialize/Deserialize generation in macros? maybe there's a good reason not to add it now or ever.
exonum/src/messages/spec.rs
Outdated
use $crate::messages::{RawMessage, MessageWriter}; | ||
let mut writer = MessageWriter::new($extension, $id, $body); | ||
// if we could deserialize values, try append signature | ||
<Self as ExonumJsonDeserializeField>::deserialize(value, &mut writer, from, to)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and checking service_id
and message_id
against the expected $extension
and $id
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
exonum/src/messages/spec.rs
Outdated
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: $crate::serialize::json::reexport::Serializer { | ||
use $crate::serialize::json::reexport::SerializeStruct; | ||
let mut structure = serializer.serialize_struct(stringify!($name), counter!($($field_name)*) + 1)?; | ||
$(structure.serialize_field(stringify!($field_name), &$crate::serialize::json::wrap(&self.$field_name()))?;)* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no service_id, message_id and network_id here. I guess, they should be added, maybe, binary message length too, not sure about this last one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fxd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[derive(Debug, Clone, PartialEq)]
pub struct BlockProof {
pub block: blockchain::Block,
pub precommits: Vec<Precommit>,
}
exonum/src/messages/spec.rs
Outdated
let body = obj.get("body").ok_or("Can't get body from json.")?; | ||
|
||
let signature = from_value(obj.get("signature").ok_or("Can't get signature from json")?.clone())?; | ||
let message_type = from_value(obj.get("message_id").ok_or("Can't get message_type from json")?.clone())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok , so now neither exonum::serialize::json::reexport::from_value
nor exonum::serialize::json::from_value
can be used on our macrogenerated types, because it results in stack overflow:
running 15 tests
test tests::test_tx_create_wallet ... ok
test tests::generate_simple_scenario_transactions ... ok
test tests::test_tx_issue_serde ... FAILED
test tests::test_tx_transfer_serde ... FAILED
test tests::test_wallet_history_true_status ... ok
test tests::test_wallet_history_txcreate_false_status ... ok
test tests::test_tx_create_wallet_serde ... FAILED
test tests::test_wallet_prefix ... ok
test tx_metarecord::test_tx_meta_record ... ok
test tests::test_wallet_history_txtransfer_false_status_insufficient_balance ... ok
test tests::test_wallet_history_txtransfer_false_status_absent_receiver_wallet ... ok
test wallet::test_amount_transfer ... ok
test wallet::test_wallet ... ok
thread 'tx_metarecord::test_tx_meta_record_serde' has overflowed its stack
fatal runtime error: stack overflow
error: process didn't exit successfully: `/Users/sysmanj/Exonum/cryptocurrency/target/debug/deps/cryptocurrency-99db04e147220907` (signal: 6, SIGABRT: process abort signal)
To learn more, run the command again with --verbose.
I'll try to workaround this, shouldn't be a problem, because i don't need explicit calls of from_value
, because you implemented service_id
and message_id
checks by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exonum/src/messages/spec.rs
Outdated
{ | ||
use $crate::serialize::json::reexport::Error; | ||
let value = <$crate::serialize::json::reexport::Value>::deserialize(deserializer)?; | ||
$crate::serialize::json::reexport::from_value(value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look above. I assume it should be ExomunJsonDeserialize::deserialize_owned
here instead of from_value
, otherwise you're calling Deserialize
till death.
Move comments inside macro declaration
exonum/src/serialize/json.rs
Outdated
pub struct ExonumJsonSerializeWrapper<'a, T: ExonumJsonSerialize + 'a>( &'a T); | ||
|
||
|
||
#[derive(Serialize, Deserialize)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This results in
"round": 4,
"time": {
"nanos": 804000000,
"secs": 1486720350
},
"validator": 0
},
"message_id": 4,
"network_id": 0,
this should be
"secs": "1486720350"
for consistency.
@vldm Let's rename the methods ExonumJsonDeserializeField::deserialize_field
ExonumJsonDeserialize::deserialize Rationale:
|
@vldm If this does not cause conflicts, run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@defuz exonum/cryptocurrency#18
exonum/exonum-configuration#24.
May need some considerable time to parse it line by line for review.
@vldm took care of all my objections.
I may review later, after merge) At least it works, somehow.
🎉 🎉 🎉 @gisochre Anyway this is much better than it was before. Refactoring and line-by-line reviews can be done later. Especially since we are now waiting for #103. |
Implement Serialize/Deserialize Former-commit-id: 1ab7034c61572e9b7fd2ae4dde67c6b0277ba43e
* Update clippy version (0.0.169) * Fix Clippy warnings
update exonum-client version
In this request merged next commits:
For now there three new traits:
ExonumJsonSerialize
implemented for all types that should be serializable in json.ExonumJsonDeserialize
for types that can be created from jsonValue
ExonumJsonDeserializeField
for types that can deserialize and writeValue
asField
WriteBufferWrapper
- Trait for all types that can write field in their bodyExonumJsonSerializeWrapper
andfn wrap()
implemented forExonumJsonSerialize
. This types allows useserde
serializer for our purposes.TODO: This is temporary
Serialization
/Deserialization
implementation for our packed structures.It should be rewritten after storage_value refactor.