ciruela 0.6.12

A peer-to-peer synchronization software for servers in datacenters.
Documentation
use std::fmt;
use std::io;

use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{Visitor, Unexpected, Error};
use serde_cbor::ser::to_writer;

use hex::{FromHex};
use hexlify::Hex;
use blake2::digest::VariableOutput;
use digest_writer;
use blake2::{Blake2b, Digest};


#[derive(Hash, PartialEq, Eq, Clone, Copy)]
pub struct Hash([u8; 32]);

struct HashVisitor;


impl Hash {
    pub fn new(hash: &[u8]) -> Hash {
        assert_eq!(hash.len(), 32);
        let mut val = [0u8; 32];
        val.copy_from_slice(hash);
        return Hash(val);
    }
    pub fn builder() -> digest_writer::Writer<Blake2b> {
        VariableOutput::new(32).expect("length is okay")
    }
    pub fn for_object<S: Serialize>(obj: &S) -> Hash {
        let mut dig = Hash::builder();
        dig.object(obj);
        return dig.done();
    }
    pub fn for_bytes(bytes: &[u8]) -> Hash {
        let mut dig = Hash::builder();
        dig.input(bytes);
        return dig.done();
    }
}

pub trait Builder: io::Write {
    fn done(self) -> Hash;
    fn object<S: Serialize>(&mut self, obj: &S);
}

impl Builder for digest_writer::Writer<Blake2b> {
    fn object<S: Serialize>(&mut self, obj: &S) {
        to_writer(self, obj).expect("can always serialize/hash structure");
    }
    fn done(self) -> Hash {
        let mut result = [0u8; 32];
        self.variable_result(&mut result).expect("length is okay");
        Hash(result)
    }
}

impl fmt::Debug for Hash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Hash({})", &Hex(&self.0))
    }
}

impl fmt::Display for Hash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", &Hex(&self.0))
    }
}

impl<'a> Visitor<'a> for HashVisitor {
    type Value = Hash;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("bytes")
    }
    fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
        where E: Error
    {
        if value.len() == 32 {
            let mut array = [0u8; 32];
            array.copy_from_slice(value);
            Ok(Hash(array))
        } else {
            return Err(E::invalid_length(value.len(), &self));
        }
    }
    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
        where E: Error
    {
        if value.len() == 64 {
            let vec: Vec<u8> = FromHex::from_hex(value)
                .map_err(|_| E::invalid_value(
                    Unexpected::Str(value), &"hex coded string"))?;
            let mut val = [0u8; 32];
            val.copy_from_slice(&vec);
            Ok(Hash(val))
        } else {
            return Err(E::invalid_length(value.len(), &self));
        }
    }
}

impl<'a> Deserialize<'a> for Hash {
    fn deserialize<D>(deserializer: D) -> Result<Hash, D::Error>
        where D: Deserializer<'a>
    {
        deserializer.deserialize_any(HashVisitor)
    }
}

impl Serialize for Hash {
    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        if ser.is_human_readable() {
            ser.serialize_str(&self.to_string())
        } else {
            ser.serialize_bytes(&self.0)
        }
    }
}