Protocol Buffers (#9)

* Add protocol buffer messages for Proof and Lemma.

* Implement Protobuf serialization for Proof and Lemma.

* Implement Protobuf unserialization for Proof and Lemma.

* Add write_to_bytes and parse_from_bytes methods to Proof.

* Put the Protobuf-related code behind a feature flag.

* Enable more flags. See #10

* Fix clippy warnings. See #10
This commit is contained in:
Romain Ruetschi
2016-11-21 17:18:41 +01:00
committed by Frederic Jacobs
parent 28d7824b8c
commit b395f224f5
11 changed files with 959 additions and 75 deletions

137
src/proto/mod.rs Normal file
View File

@ -0,0 +1,137 @@
mod proof;
use proof::{ Proof, Lemma, Positioned };
pub use self::proof::{ ProofProto, LemmaProto };
use protobuf::Message;
use protobuf::error::ProtobufResult;
use protobuf::core::parse_from_bytes;
impl <D, T> Proof<D, T> {
/// Constructs a `Proof` struct from its Protobuf representation.
pub fn from_protobuf(digest: D, proto: ProofProto) -> Option<Self> {
proto.into_proof(digest)
}
/// Encode this `Proof` to its Protobuf representation.
pub fn into_protobuf(self) -> ProofProto {
ProofProto::from_proof(self)
}
/// Parse a `Proof` from its Protobuf binary representation.
pub fn parse_from_bytes(bytes: &[u8], digest: D) -> ProtobufResult<Option<Proof<D, T>>> {
parse_from_bytes::<ProofProto>(bytes).map(|proto| proto.into_proof(digest))
}
/// Serialize this `Proof` with Protobuf.
pub fn write_to_bytes(self) -> ProtobufResult<Vec<u8>> {
self.into_protobuf().write_to_bytes()
}
}
impl ProofProto {
pub fn from_proof<D, T>(proof: Proof<D, T>) -> Self {
let mut proto = Self::new();
match proof {
Proof { root_hash, lemma, .. } => {
proto.set_root_hash(root_hash);
proto.set_lemma(LemmaProto::from_lemma(lemma));
}
}
proto
}
pub fn into_proof<D, T>(mut self, digest: D) -> Option<Proof<D, T>> {
if !self.has_root_hash() || !self.has_lemma() {
return None;
}
self.take_lemma().into_lemma().map(|lemma| {
Proof::new(
digest,
self.take_root_hash(),
lemma
)
})
}
}
impl LemmaProto {
pub fn from_lemma(lemma: Lemma) -> Self {
let mut proto = Self::new();
match lemma {
Lemma { node_hash, sibling_hash, sub_lemma } => {
proto.set_node_hash(node_hash);
if let Some(sub_proto) = sub_lemma.map(|l| Self::from_lemma(*l)) {
proto.set_sub_lemma(sub_proto);
}
match sibling_hash {
Some(Positioned::Left(hash)) =>
proto.set_left_sibling_hash(hash),
Some(Positioned::Right(hash)) =>
proto.set_right_sibling_hash(hash),
None => {}
}
}
}
proto
}
pub fn into_lemma(mut self) -> Option<Lemma> {
if !self.has_node_hash() {
return None;
}
let node_hash = self.take_node_hash();
let sibling_hash =
if self.has_left_sibling_hash() {
Some(Positioned::Left(self.take_left_sibling_hash()))
}
else if self.has_right_sibling_hash() {
Some(Positioned::Left(self.take_right_sibling_hash()))
}
else {
None
};
if self.has_sub_lemma() {
// If a `sub_lemma` is present is the Protobuf,
// then we expect it to unserialize to a valid `Lemma`,
// otherwise we return `None`
self.take_sub_lemma().into_lemma().map(|sub_lemma| {
Lemma {
node_hash: node_hash,
sibling_hash: sibling_hash,
sub_lemma: Some(Box::new(sub_lemma))
}
})
}
else {
// We might very well not have a sub_lemma,
// in which case we just set it to `None`,
// but still return a potentially valid `Lemma`.
Some(Lemma {
node_hash: node_hash,
sibling_hash: sibling_hash,
sub_lemma: None
})
}
}
}